Search the FAQ Archives

3 - A - B - C - D - E - F - G - H - I - J - K - L - M
N - O - P - Q - R - S - T - U - V - W - X - Y - Z - Internet FAQ Archives

VCOMM Frequently Asked Questions (FAQ)

[ Usenet FAQs | Web FAQs | Documents | RFC Index | Business Photos and Profiles ]
Archive-name: windows/programming/vcomm
Posting-Frequency: bimonthly
Last-modified: 1996/09/13
Version: 1.8

See reader questions & answers on this topic! - Help others by sharing your knowledge
		    VCOMM Frequently Asked Questions (FAQ)

1:  Version History

Version	 When	Major Changes
-------	------	-------------
1.8	960913	First official posting to comp.answers newsgroup.
		Solved serial.vxd compiliation.
		New HyperTerminal section.
1.7	960828	Added disclaimer.
1.6	960826	Added some more references.
		Added VCOMM RxCallback register save bug.
		Added something on support for DOS applications.
1.5	960711	Updated for fixes in Vireo VtoolsD 2.03.
		Added Modems | More Info... AT set requirements.
		Added Modems | More Info... VtoolsD PortOpen bug.
1.4	960425	Added VtoolsD contention problem.
		Added blockable functions and HyperTerminal no buffers.
		Added contributors' names.
		More on dwLastError.
		Modifications for April 1996 MSDN.
1.3	960328	Added non-standard ports, PPP, and monitoring data traffic.
		Added HyperTerminal log, illegal baud rate indexes, and zmodem.
		Changed CommTimeouts.
		Updated for Vireo VtoolsD version 2.02.
1.2	960220	Added virtual modem, HyperTerminal, and VtoolsD makefiles.
1.1	960213	Added Table of Contents.
1.0	960208	Initial release.

2:  General

This document attempts to capture many of the issues that come up on the VCOMM
mailing list, and problems that we have found during development.  Any
suggested changes should be directed to that mailing list.  (See below for
information on subscribing to the mailing list.)

All topics herein should refer to the newest major version of the appropriate
documentation, source, or software.  Exceptions are noted.

Many, perhaps all, of the errors mentioned in this document have been reported
to the appropriate company, and may be fixed in subsequent releases.  Once
they have been confirmed to be fixed, they will be removed from this document
(or otherwise noted), unless there are backwards compatibility issues.

The newest version of this document can be obtained by sending a message body
of "get vcomm vcomm.faq" to, which is the server for
the VCOMM mailing list.

The VCOMM mailing list also maintains an archive of postings.  Searching the
archives for other topics is encouraged.

3:  Authors

This document is made up of input from a number of people, most of whom are on
the VCOMM mailing list.  Many sections are marked with the name of the
contributors.  Sections which are not credited were probably written by the
editor, based on information from the mailing list.  The major authors are
listed below alphabetically:

	Michael Grabelkovsky, Smart Link Limited (

	Taed Nelson, National Semiconductor Corporation (

The editor of this document is Taed Nelson (

4:  Copyright and Disclaimer

This document is Copyright 1996 by Taed Nelson and National Semiconductor
Corporation.  All rights are reserved.

This document may be distributed in electronic form only, provided that no fee
is charged and the document is distributed completely and exactly.  Any
additions or corrections must be noted as such, and must be submitted to the
editor listed above for potential future inclusion in this document.

Any other distribution or publication of this document must receive written
permission from the editor, who in turn will discuss the matter with the major

The information provided herein is for informational purposes only, and no
warranty is either expressed or implied.

5:  Table of Contents

	1:  Version History
	2:  General
	3:  Authors
	4:  Copyright and Disclaimer
	5:  Table of Contents
	6:  Tools and Information Sources
		6.1:  Microsoft
		6.2:  Online
		6.3:  Printed
		6.4:  Software Tools
		6.5:  Other
	7:  General Issues
		7.1:  Serial.vxd Source Won't Compile
			7.1.1:  Yes, it will
			7.1.2:  You need MASM Version 6.11c
			7.1.3:  Minor typographical error
		7.2:  Port.inf file
			7.2.1:  InfEdit.exe
		7.3:  Non-Standard Ports
		7.4:  No Logical Resources
		7.5:  Logical Memory Resources
		7.6:  Init Order
		7.7:  Virtual Modems and Printers
		7.8:  Point-to-Point Protocol (PPP)
		7.9:  How to Monitor or Intercept COMM Data Traffic
		7.10:  HyperTerminal Function Trace
		7.11:  Blockable Functions
			7.11.1:  Blockable Port functions
			7.11.2:  Non-Blockable Port functions
		7.12:  Support for DOS Applications
	8:  Problems With Applications
		8.1:  HyperTerminal Closes the Port Unexpectedly
		8.2:  HyperTerminal Zmodem Protocol Fails
		8.3:  HyperTerminal Allocates No Buffers
		8.4:  HyperTerminal can't work at high DTE speed
		8.5:  Control Panel | Modems | More Info...
	9:  Problems with VCOMM
		9.1:  PortOpen Causes VCOMM to Crash
		9.2:  Illegal Baud Rate Indexes
		9.3:  RxCallback does not preserve EBX.
	10:  Documentation Issues
		10.1:  CommNotifyProc
		10.2:  CommTimeouts
		10.3:  PortEscapeFunction
		10.4:  PortGetCommConfig and PortSetCommConfig
		10.5:  PortGetEventMask
		10.6:  PortGetWin32Error
		10.7:  PortSetModemStatusShadow
		10.8:  VCOMM_Map_Win32DCB_To_Ring0 and VCOMM_Map_Ring0DCB_To_Win32
		10.9:  _PortData Structure
			10.9.1:  Notification fields
			10.9.2:  dwLastReceivedTime
			10.9.3:  dwLastError
		10.10:  Other Structures
			10.10.1:  General
			10.10.2:  _COMM_CONFIG
		10.11:  Terminology
			10.11.1:  RLSD
	11:  VtoolsD Vcomm Class
		11.1:  General
		11.2:  Documentation Errors
		11.3:  PortOpen Errors
		11.4:  Contention Management Errors
		11.5:  Other Errors
		11.6:  Makefiles and #defines
			11.6.1:  Turning off optimization (Taed's way)
			11.6.2:  Turning off optimization (Michael's way)
			11.6.3:  Version resource
			11.6.4:  Dependencies
			11.6.5:  Assert versus ASSERT
			11.6.6:  DEBUG versus _DEBUG
			11.6.7:  Avoiding the dprintf() call

6:  Tools and Information Sources

6.1:  Microsoft

Microsoft Developer Network Device Driver Kit (MSDN DDK), July 1996.

"Communications Device Drivers" (\DDK\Docs\Desguide\Comm.doc), also known as
the Vcomm documentation.  In addition to the change of file name, this
document changed significantly on the April 1996 DDK.  (A copy of this file,
but not necessarily the newest, can also be obtain by sending a message body
of "get vcomm comm.doc.uu" to

Serial.vxd Source Code (\DDK\Comm\Samples\Serial\*.*).  This is (or seems to
be) the source code for the Serial.vxd port driver.

Microsoft Developer Network Software Development Kit (MSDN SDK), January 1996.

6.2:  Online

VCOMM Mailing List (  This covers VCOMM port driver
development and related issues.  The mailing list maintains an FAQ (this
document that you are reading) and archives of previous messages.  Mail the
body "subscribe vcomm" to to subscribe, or contact for other requests.  (Note that the mailing list will
be moving in late September 1996 (or may have already by the time you read
this), but don't let that stop you from subscribing, since all addresses will
be forwarded to the new site.)

DDK-L Mailing List (  This covers general VxD
development.  There is a $15 annual fee, but it is well worth it for the
quality of the postings and subscribers.  The mailing list maintains an archiv
of previous messages.  Contact to subscribe, or for other requests.

DDK Mailing List (  This covers general VxD development.
Mail the body "subscribe vcomm" to to
subscribe, or contact for other requests. UseNet Newsgroup.  This covers general VxD
development.  There is also an FAQ for that newsgroup.

6.3:  Printed

_Systems Programming for Windows 95_, by Walter Oney.  This has an entire
chapter on communications drivers, and presents a port driver written in C.

6.4:  Software Tools

VtoolsD by Vireo Software, Version 2.03.  This contains a Vcomm port driver
class, and allows one to write VxDs in C or C++.  They have a WWW page at

VXDMON by Mark Russinovich and Bryce Cogswell.  This program uses the
Pentium's cycle counter to provide performance and control-flow information
and any and all exported Virtual Machine Monitor (VMM) and Virtual Device
Driver (VxD) services under Windows 95.  Available at

6.5:  Other

"Hayes AT Command Reference for OPTIMA and ACCURA Products", Hayes
Microcomputer Products, Inc.  This covers the AT command set in great detail.
This document can be found at

7:  General Issues

7.1:  Serial.vxd Source Won't Compile

[Contributed by Taed Nelson (]

The "-coff -DBLD_COFF" must be removed from AFLAGS to get it to compile
successfully.  It can be gotten to compile in other ways, but then it won't
link or run correctly.

The new linker must also be used, but it will give a few warnings.  The size
is also considerable smaller than the actual Serial.vxd (11K versus 18K).  The
resulting VxD seems to run correctly, though.

7.1.1:  Yes, it will

[Contributed by Bill Stuart (]

I can build the serial sample without editing the makefile.  I build on Win95
in a DOS box and set my environment by running:

	d:\mstools\setenv d:\mstools d:\msvc20\bin
	d:\ddk\ddkenv 32 comm

I also place the linker I want to use in d:\ddk\bin.

7.1.2:  You need MASM Version 6.11c

The problem seems to be that it won't work with MASM version 6.11.  The update
to 6.11c is allegedly on the Microsoft web site somewhere.

7.1.3:  Minor typographical error

[Contributed by Michael Grabelkovsky (]

A coding error that seems to compile correctly anyway is in serutil.asm.  In
the function KickTx, the reference to [esi.pData.QOutMod] should just be

7.2:  Port.inf file

The Vcomm document mentions a commented sample port INF file in the \DDK\Comm
directory, but no such file exists.

There is a reasonable example file called \Windows95\Inf\msports.inf.  Other
examples can be found in the VCOMM mailing list archives.

7.2.1:  InfEdit.exe

[Contributed by Taed Nelson (]

Beware when editing a port INF file with the SDK tool InfEdit.exe.  It will
remove double-quote marks that are needed to do things such as:

7.3:  Non-Standard Ports

[Contributed by Taed Nelson (]

Port drivers with non-standard logical resources will be assigned to port COM5
or above.  These are typically referred to as "non-standard ports."
Nonetheless, they are supported just fine by any decent Win16 or Win32

On non-standard ports, the port.inf file should not specify a "Contention"
resource.  By default, VCOMM will perform contention management between Win16
and Win32 applications.  (I have found that you can actually use *VCD when
using Windows 3.11 style contention management (although I doubt it actually
does contention management), but that it will not work when using with Windows
95 style.)

7.4:  No Logical Resources

[Contributed by Taed Nelson (]

It is reasonable for a VCOMM port driver to have no logical configuration
resources at all.  This can occur since the port driver may communicate with
another driver, such as a network driver, to virtualize that as a COM port.
The port driver would then have no resources of its own.

But this leads to a problem.  The documentation states (in the VCOMM Device
Initialization section), "[VCOMM] assigns a PortName to the device in its
hardware key, if its devnode contains system resources."  Thus, without
resources, we don't get a port name, such as COM5.  And without a port name,
we have discovered, we are not recognized by Dial-Up Networking or UNIMODEM.
These are all required functionalities for any port driver.

The only solution at this point is to edit the Registry and add PortName and
FriendlyName entries by hand.  It is possible to hard-code the PortName and
FriendlyName (but not Description) in the port.inf file so that no
hand-editing is required.  The place to do the editing is

7.5:  Logical Memory Resources

[Contributed by David McCullough (]

VCOMM does not enumerate the PortNames if your device has any logical memory
resources.  IO and IRQ resources are OK.

I will try to double check this again, to be sure, but my ports were
enumerated fine until I added a memory address to the LogConfig, and then it

I don't know about multiple IO addresses yet.

7.6:  Init Order

[Contributed by Taed Nelson (]

What is the proper device init order for a VCOMM port driver?  The
documentation says to use UNDEFINED_INIT_ORDER, but SERIAL.VXD uses
VCD_INIT_ORDER.  And in VMM.H, there is a PORT_INIT_ORDER defined, which is
just slightly less than VCD.  Which is right?

This is an issue for any static port driver under Windows 95, and maybe every
port driver for Windows for Workgroups.

7.7:  Virtual Modems and Printers

[Contributed by Taed Nelson (]

In some cases (particularly if there are no logical resources), the port
driver will not actually attach to any physical device.  Nonetheless, since
UNIMODEM (and other system modules) is such a handy beast, some people may
wish to emulate a "virtual modem".  Thus, UNIMODEM will think that there is
actually a modem attached to the port, when there is really only the port

The easy way to approach this is to pick a modem and emulate it.  This
requires some modes and states within the port driver, but it isn't too
difficult (just time-consuming).  A good place to start is with the "Hayes AT
Command Reference".  To be supported as the W95 "Standard Modem", there are
very few AT commands that must be recognized.  See \WINDOWS\INF\MDMGEN.INF for
what needs to be supported.

The "better" method is to write your own modem INF file.  There are examples
in \WINDOWS\INF\MDM*.INF.  There is a lot of documentation for this in the
MSDN DDK.  It is also possible for your virtual modem to be auto-detected by

A similar approach can be taken for printers.

7.8:  Point-to-Point Protocol (PPP)

[Contributed by Taed Nelson (]

Microsoft Dial-Up Networking uses asynchonous PPP.  Most, if not all, ISDN
systems use synchronous PPP.  Therefore, to communicate over ISDN, your port
driver or the hardware must convert between async and sync PPP.  This isn't
actually too hard, and is described in RFC 1662.

7.9:  How to Monitor or Intercept COMM Data Traffic

There is a Microsoft Knowledge Base article on this topic:

	How to Monitor or Intercept COMM Data Traffic in Windows 95   
	ID: Q141230    CREATED: 13-DEC-1995   MODIFIED: 14-DEC-1995

[It is not on the January 1996 Library CD, so check the VCOMM archive

7.10:  HyperTerminal Function Trace

[Contributed by Taed Nelson (]

This trace is from a port driver that uses Vireo's VtoolsD, but the
translations to normal port driver functions should be obvious.  All numbers
are in hexadecimal.

This was done by opening HyperTerminal with a script that uses COM5, hitting
the Cancel button, typing a single return character, hitting the disconnect
button, and then quitting HyperTerminal.  The Writes that are seen are thus
the return character, and then the normal UniModem "ATZ<CR>".

Note that after the return character is written, there is no "Callback:
CN_RECEIVE".  This is because the Read threshhold is 50, but only 1 character
was received.  (A character was received since the virtual modem echos
characters in command mode.)  But what is not seen in this trace is that,
since dwLastReceivedTime was kept updated, VCOMM did a "Callback: CN_RECEIVE"
when a certain timer expired.  HyperTerminal then does a Read a short time
later.  See other sections in this FAQ for mor information.

Obviously, pointers and some other values should not match anyone else's
traces, but the sequence of function calls should be nearly identical.

DriverControl (function=00000000)
DC_Initialize (handle=c17cac74, iobase=00000000, irq=00000000, name=COM5)
Initialize (m_name=C16B4A30, baseIO=00000000, irq=00000000)
Open (hVM=C3D20154, pError=C15F5E20)
EnableNotification (pCallback=C1737E2E, refData=C65A0018)
EscapeFunction (lFunc=00000013, InData=C65A00A0, pOutData=00000000)
SetModemStatusShadow (pMSRShadow=C65A0050)
SetReadCallback (RxTrigger=FFFFFFFF, pCallback=00000000, refData=00000000)
ClearError (pComstat=00000000, pError=C15F5DE8)
Read (buf=C65A068C, cbRequest=00000001, pRxCount=C15F5E00, RxCount=00000000)
Purge (qType=00000001)
ClearError (pComstat=00000000, pError=C15F5E0C)
SetReadCallback (RxTrigger=00000001, pCallback=C173804C, refData=C65A0658)
GetCommState (pDCB=C15F5DF4)
SetCommState (pDCB=C15F5DF4, ActionMask=FFFFFFFF)
EscapeFunction (lFunc=00000005, InData=00000000, pOutData=00000000)
EscapeFunction (lFunc=00000003, InData=00000000, pOutData=00000000)
EscapeFunction (lFunc=00000010, InData=00000000, pOutData=00000000)
EscapeFunction (lFunc=00000014, InData=00000000, pOutData=00000000)
Setup (RxQueue=00000000, cbRxQueue=00001000, TxQueue=00000000, cbTxQueue=00000000)
Setup (RxQueue=00000000, cbRxQueue=00001000, TxQueue=00000000, cbTxQueue=00001000)
GetCommState (pDCB=C15F5E58)
SetCommState (pDCB=C15F5E58, ActionMask=FFFFFFFF)
EscapeFunction (lFunc=00000005, InData=00000000, pOutData=00000000)
EscapeFunction (lFunc=00000003, InData=00000000, pOutData=00000000)
SetReadCallback (RxTrigger=FFFFFFFF, pCallback=C1737E2E, refData=C65A0018)
SetWriteCallback (TxTrigger=FFFFFFFF, pCallback=C1737E2E, refData=C65A0018)
SetEventMask (mask=00000080, pEvents=00000000)
Setup (RxQueue=00000000, cbRxQueue=00008000, TxQueue=00000000, cbTxQueue=00008000)
GetCommState (pDCB=C15F5E58)
GetCommState (pDCB=C15F5E58)
GetCommState (pDCB=C15F5E58)
SetCommState (pDCB=C15F5E58, ActionMask=FFFFFFFF)
EscapeFunction (lFunc=00000005, InData=00000000, pOutData=00000000)
EscapeFunction (lFunc=00000003, InData=00000000, pOutData=00000000)
SetEventMask (mask=000000A0, pEvents=C65A0048)
GetQueueStatus (pComstat=C15F9E20)
SetReadCallback (RxTrigger=00000050, pCallback=C1737E2E, refData=C65A0018)
GetQueueStatus (pComstat=C1618E20)
SetWriteCallback (TxTrigger=00000001, pCallback=C1737E2E, refData=C65A0018)
Write (buf=00668D94, cbRequest=00000001, pTxCount=C1684CB4)
SetReadCallback (RxTrigger=FFFFFFFF, pCallback=C1737E2E, refData=C65A0018)
Read (buf=C1603AD8, cbRequest=00000050, pRxCount=C1684CF0, RxCount=00000001)
SetWriteCallback (TxTrigger=FFFFFFFF, pCallback=C1737E2E, refData=C65A0018)
GetQueueStatus (pComstat=C1618E74)
GetQueueStatus (pComstat=C15F9E20)
SetReadCallback (RxTrigger=00000050, pCallback=C1737E2E, refData=C65A0018)
SetEventMask (mask=000000A0, pEvents=C65A0048)
GetEventMask (mask=000000A0, pEvents=00BBFF58)
SetReadCallback (RxTrigger=FFFFFFFF, pCallback=00000000, refData=00000000)
ClearError (pComstat=00000000, pError=C15F5E44)
Read (buf=C65A068C, cbRequest=00000001, pRxCount=C15F5E5C, RxCount=00000000)
Purge (qType=00000001)
ClearError (pComstat=00000000, pError=C15F5E68)
SetReadCallback (RxTrigger=00000001, pCallback=C173804C, refData=C65A0658)
SetWriteCallback (TxTrigger=FFFFFFFF, pCallback=00000000, refData=00000000)
SetEventMask (mask=00000000, pEvents=00000000)
Purge (qType=00000000)
ClearError (pComstat=00000000, pError=C15F5E84)
EscapeFunction (lFunc=00000006, InData=00000000, pOutData=00000000)
Purge (qType=00000000)
Purge (qType=00000001)
SetEventMask (mask=00000004, pEvents=00000000)
Write (buf=C170829C, cbRequest=00000004, pTxCount=C65A0508)
Callback: CN_EVENT=00000004
Callback: CN_EVENT=00000004
Callback: CN_EVENT=00000004
Callback: CN_EVENT=00000004
Callback: CN_EVENT=00000004
Callback: CN_EVENT=00000004
Callback: CN_EVENT=00000004
Callback: CN_EVENT=00000004

7.11:  Blockable Functions

[Contributed by Joe Cossette (]

Basically, due to the type of driver we needed (a virtual COMM port over a
network), we needed to block at times when VCOMM called back on Port
functions.  We eventually discovered (painfully...) that for many Port
functions this just wasn't possible.  It would initially appear that some
would function OK (you could block), but after a certain number of calls into
it the system would typically hang (stop processing messages).

So we eventually separated the functions into 2 groups (based on looking over
VCOMM docs).  The first group was composed of Port functions that could not be
blocked and the second was composed of Port functions that might be a
candidate for blocking.

What follows is the list of Port functions separated into the 2 categories we
eventually came up with (that appeared to work for us).  We make no guarantees
on these, not that we've actually blocked on each of the functions listed
(we've blocked on some).  Simply, this is the information we've gleaned from
reading the docs and some of our experiences.  Maybe others can concur/dispute
these findings and hopefully our cumulative knowledge of VCOMM will increase
by understanding this.

The blockable functions are roughtly the same thing as asynchronous functions,
but I think the VCOMM docs didn't always indicate they were asynchronous.
Sometimes they said they were "safe" (I think???).

Blocking means to block (i.e. put the thread to sleep, typically to be awoken
at some later time).  During the blocked period the system runs other threads
(if there're any to run).

The blocking mechanism can be whatever the system might have available to
accomplish this sort of thing (i.e. semaphore, mutex, sleep functions,

7.11.1:  Blockable Port functions


7.11.2:  Non-Blockable Port functions


7.12:  Support for DOS Applications

[Contributed by John Loram (]

The Problem:

A DOS application running under Windows 95 or Windows for Workgroups 3.11
cannot access VCOMM port driver supported devices such as a host-based modems.
This is because the DOS app interacts with a serial communications channel by
way of the Windows COMBUFF module. COMBUFF is UART-based virtual device driver
(VxD) that engages in direct UART manipulation.

The Solution:

COMBUFF must be completely rewritten to serve as a translation layer between a
DOS app's UART based I/O activity and the VCOMM's API. Doing so provides DOS
apps access to the full range of VCOMM port drivers and the standard or
non-standard devices these port drivers serve.

Specifically, COMBUFF must be expanded to include full, 8250, 16450, and 16550
UART register-level emulation complete with appropriate interrupt-generation
In addition, the initialization and contention-handling mechanisms of VCD must
be revised significantly.  Separate versions of COMBUFF and VCD must be
created for Windows 95 and WFW 3.11, since there are major differences in the
code base for these environments.

TurboCom ViP (Pacific CommWare) is a finished product that accomplishes these
objectives.  For further information, contact John Loram at, call him at 541-482-2744 (Ashland, Oregon), or check their
web site at

8:  Problems With Applications

8.1:  HyperTerminal Closes the Port Unexpectedly

[Contributed by Taed Nelson (]

A few people have run into the problem where, under Windows 95, HyperTerminal
will seem to load the port driver correctly, but then suddenly close it for no
apparent reason.

The cause of this is that HyperTerminal or UNIMODEM (it is not clear which is
the actual culprit) requires at least two of the four new W95 functions.  See
below for more details.  The functions it needs to use are PortGetCommConfig
and PortSetCommConfig.

[See also "HyperTerminal Function Trace".]

8.2:  HyperTerminal Zmodem Protocol Fails

A few people have seen the Zmodem protocol fail with errors such as "bad
packet format" on the receiving side.  Other protocols seem to work just fine.
While this has been seen mostly with our own VCOMM ports, one person said that
they saw it on a high-speed modem with compression on.

The current theory is that this has something to do with high-speed data
transmission, but Hilgraeve has not responded.

The 28800 Modem FAQ ( suggests
that it may be caused by overrun errors.

There is also some data that implies that the problem is actually caused by
running the DDK Windows 95 debug kernel.

8.3:  HyperTerminal Allocates No Buffers

[Contributed by Mike Melo and Michael Grabelkovsky (]

HyperTerm has problems when configured to use "Direct to COMx".  The port
driver only receives a single PortSetup call, and TxQueue and cbTxQueue are
both zero.

It's undocumented, but SERIAL.VXD includes special support for this case.  You
can look at the SERFUNC.ASM module, function PortWrite.  The code is

8.4:  HyperTerminal can't work at high DTE speed

[Contributed by Michael Grabelkovsky (]

HyperTerminal loses some data when it receives a long text file from another
HyperTerminal at a high speed.

My download driver sometime wrote up to 1024 bytes to receive queue in one
time.  According the trace HyperTerminal successfully read the data. Each time
it asks 80 bytes.  After about 800 bytes it starts to ask shorter and from
this place data is lost.  Serial driver hasn't this problem because it writes
not more 16 bytes at one time.

I fixed it by changed my driver writes to receive queue small portion of data
every 20ms according defined DTE speed.

8.5:  Control Panel | Modems | More Info...

[Contributed by Michael Grabelkovsky (]

Two things must be done properly before the "More Info..." option of Control
Panal's Modems actually calls the ATIx commands to get "More Info":

1. The port driver EscapeFunction() must support the GETCOMBASEIRQ option.
"More Info" fell down when the driver answered with IE_EXITINVALID.  The
function may return 0, though.

2. The virtual modem (port driver) must support following AT commands and
answer OK on the string: "ATE0Q0V1".  The last commands are not set up in the
Modem's INF file, but it's used by "More Info".  After that Modem will be
asked ATI1, ATI2 ... ATI7 and in the end the FAX capabilities with

9:  Problems with VCOMM

9.1:  PortOpen Causes VCOMM to Crash

[Contributed by Michael Grabelkovsky (]

If the PortOpen() function return FALSE (unsuccessful), but *pError remains
unchanged, VCOMM crashes at VCOMM(04)+974.

9.2:  Illegal Baud Rate Indexes

[Contributed by Taed Nelson (]

In a few different circumstances, SetCommState will be asked to use a CBR_
baud rate index of 0xFF00.  According to all of the documentation I have seen,
that is clearly an illegal baud rate.

The "proper" thing to do is to return an error of IE_BAUDRATE.

My theory is that this is old behavior that has a special meaning, such as
"set to lowest supported baud rate" or something like that.

One easy way to duplicate this behavior under Windows 95 is to run Modems in
the Control Panel.  Click on the Diagnostics tab.  Select your virtual COM
port.  Click on More Info.  One of the calls to SetCommState will have this
illegal case.

9.3:  RxCallback does not preserve EBX.

[Contributed by Walter Oney and Taed Nelson (]

At a minimum, the default VCOMM RxCallback does not preserve the EBX register,
so you must "push EBX" prior to calling the callback, and "pop EBX"
afterwards.  (Turning of compiler optimization will also solve it.)

It is unknown if it affects other callbacks or other registers.

For more detail, see Walter Oney's _Systems Programming in Windows 95_.

10:  Documentation Issues

[Unless otherwise noted, all text in this chapter was contributed by Taed
Nelson ( and Michael Grabelkovsky (]

These comments refer to VCOMM.DOC on the January 1996 MSDN DDK.  Some of them
have been fixed in COMM.DOC on the April 1996 MSDN DDK.  Those fixes are not
yet referenced in this document.

10.1:  CommNotifyProc

The event type CN_RECEIVED should be CN_RECEIVE.

The use of EV_CTSS, EV_DSRS, EV_RingTe, and EV_RLSDS needs to be made clearer.
Is the use of "in Windows 3.1" to distinguish it from "in Windows 95", from
"in the hardware", or from "in the modem status shadow register"?  Do
applications request these events in PortSetEventMask, or are they always
passed up when the change state event occurs?

It is not clear what the events EV_CTSS2, EV_DSRS2, and EV_RING2 are for.
They are also not defined in the vcomm.h file, and are not used in Serial.vxd.

10.2:  CommTimeouts

Communications timeouts make use of the COMMTIMEOUTS structure in _PortData.
The timeouts and callbacks, when using COMMTIMEOUTS, are handled by VCOMM.

Unfortunately, this seems to only work for Win32 applications, such as
HyperTerminal.  (Oddly enough, Dial-Up Networking does not make use of
CommTimeouts, but I'm not sure if it is due to it not being Win32 or something

Serial.vxd implements its own form of 100 ms timeouts for received characters.
This is implemented via escape functions that enable and disable the "timer
logic".  This seems necessary for port drivers to implement if they want to
efficiently handle non-Win32 applications.

Apparently, when a Win32 application is running, VCOMM will disable the timer
logic via the escape function.  I don't know if it automatically enables it
for non-Win32, or if it is up to the application.

[See also "dwLastReceivedTime".]

10.3:  PortEscapeFunction

VCOMM.H defines and Serial.vxd supports more extended functions than are
described in the DDK.  But the list of function of EscapeCommFunction (see
SDK) is shorter then corresponding DDK's list.

In the newer "Comm.doc" document, the escape functions are very well
documented.  There is a minor error in that Serial.vxd does NOT implement

10.4:  PortGetCommConfig and PortSetCommConfig

There is no documentation on these functions.

Serial.vxd doesn't handle the error conditions in these functions correctly.
For example, PortGetCommConfig returns TRUE in all cases, even if dwSize is
less than the size of the Win32 DCB structure (see serfunc.asm module).

10.5:  PortGetEventMask

The description for dwEvents is wrong (a cut-and-paste error).  It should be
something like "The location where the previous port event flags should be
returned."  It could be copied from _VCOMM_GetCommEventMask.

There is some question on whether the previous events should be returned in
dwEvents as-is, or if they should be masked with dwMask.  Serial.vxd does not
mask them, and the _VCOMM_GetCommEventMask description implies that they
should not be masked.  On the other hand, that does not seem to match the
spirit of this function.  This should be spelled out in the documentation.  It
is mentioned in the Knowledge Base article Q81143, "DOCERR:
Get/SetCommEventMask Functions Documented Incorrectly", but that covers the

The VtoolsD documentation specifically states that they should be masked.
"The port object must set flags at the DWORD location pointed to by pEvents to
indicate which of the events specified by the mask have occurred".

10.6:  PortGetWin32Error

There is no documentation on this function.

Serial.vxd does nothing with this function; it is just a stub.

10.7:  PortSetModemStatusShadow

The Vcomm documentation and the comments in the Serial.vxd source code
describe a parameter called dwEventMask.  This parameter does not exist.  The
actual code in Serial.vxd does not declare this parameter.

10.8:  VCOMM_Map_Win32DCB_To_Ring0 and VCOMM_Map_Ring0DCB_To_Win32

There is no documentation on these VxD calls.

10.9:  _PortData Structure

There needs to be a better description (like that found in the TAPI
documentation for its structures, which uses a chart format) of which fields
are read and written by VCOMM, and which should be read and written by the
port driver.  And also a complete description of what each field is used for
by VCOMM and the port driver.

10.9.1:  Notification fields

The fields for support notification such as lpClientEventNotify,
lpClientReadNotify, lpClientWriteNotify etc. are defined in the _PortData
structure. But serial driver doesn't use it and defines similar additional
fields inside _PortInformation structure.  Why?

Is it possible to use the fields within the port driver?  Serial.vxd keeps its
own copy of the data, but does not update _PortData.  Does VCOMM copy this
information into _PortData when it passes the SetCallback functions down to
the port driver?

In all cases, the rules of using those fields must be documented.

10.9.2:  dwLastReceivedTime

This field is not described.

It seems that every time a character is received (including echo characters
and response codes from "virtual modems"), this field should be updated with
the result of Get_Last_Updated_System_Time.  (See also

This seems to allow VCOMM to perform timeouts using the entries in the
COMMTIMEOUTS structure.  This is also undocumented.

[See also "CommTimeouts".]

10.9.3:  dwLastError

There are many more fields in VCOMM.H than are described in COMM.DOC.
Serial.vxd makes use of some of these "extra" error values, such as
IE_HARDWARE.  Additionally, COMM.DOC defines two that are not in VCOMM.H:

The descriptions of IE_DEFAULT differ significantly between COMM.DOC and
VCOMM.H.  The first states "some general error occurred", while the second
defines an "error in default params".  It seems that SERIAL.VXD uses it more
as a catch-all error condition, rather than referring specifically to the
passed parameters of a function.

Should this field be updated with the value 0 when a function returns
successfully?  The wording of the Vcomm documentation is unclear as to whether
it should contain the last actual error, or just the last return value.
Serial.vxd writes a 0 much of the time, but often does not.

10.10:  Other Structures

10.10.1:  General

Some of the structures have "version" entries, but what version should be
filled in or checked for?  Some of this can be inferred from the Serial.vxd
source, but how will developers know if it is updated?  This information
should be in the Vcomm.h file.

10.10.2:  _COMM_CONFIG

This structure is not documented.

Some its fields can't be understood from the Serial.vxd source. For example,
it seems that the field cc_wVersion is defined with an error in it.

10.11:  Terminology

10.11.1:  RLSD

RLSD is used, but not defined.  It stands for Receive Line Signal Detect, and
is usually referred to as Carrier Detect, or DCD (Delta Carrier Detect).

11:  VtoolsD Vcomm Class

[Unless otherwise noted, all text in this chapter was contributed by Taed
Nelson ( and Michael Grabelkovsky (]

11.1:  General

The Vcomm example is not very useful, except to give an idea of where to
start.  It would be very nice to have a functional example.

11.2:  Documentation Errors

The errors listed here refer to the online help files, but many (if not all)
also exist in the printed documentation.

Many of the documentation errors in the Microsoft documentation are shared by
VtoolsD, since much of it is copied verbatim or only slightly modified.

[Fixed in version 2.02.] The main Vcomm page is missing a short description for

[Fixed in version 2.02.] Missing ClearError (although it can be searched for).

[Fixed in version 2.02.] SetModemStatus should be SetModemStatusShadow.

[Fixed in version 2.02.] Missing data members m_chain and m_PortFlags.

[Fixed in version 2.02.] The online help can be searched to find the entries
for _VCOMM_Map_Win32DCB_to_Ring0 and _VCOMM_Map_Ring0DCB_To_Win32, but they
are not in the alphabetical or functional sections.

11.3:  PortOpen Errors

[Fixed in version 2.02.] When it first returns NULL if it cannot find the port
(the message "Failed to acquire port"), it must update the pError variable
with IE_DEFAULT or some other type of error.  pError should not be set in the
other error case since pPort->Open had been called, and that would have a
chance to set it to a better value.

[Fixed in version 2.02.] It does not check to see if the port is already open.
Look at the SERIAL.ASM example of how to do this.  It should return IE_OPEN in
pError if this is detected.

The documentation for Open says that the port driver "may" choose to save hVM
in m_ownerVM, but there is no reason for the Open to do this since the class's
PortOpen already does it. It should probably be removed from the
documentation, since the port driver doesn't need to use it for anything else,
so why should it be responsible for updating it.

[Fixed in version 2.03.] [Contributed by Xianbin Wang (]  A
number of us saw problems with illegal port "stealing", such as Control Panel
| Modems | More Info...  would take an open port from HyperTerminal.  This is
probably due to PortOpen returning the port handle (instead of NULL) when a
port is actually open.  Although, it does return an error value.  Apparently,
More Info looks for a NULL handle instead of the error value.

11.4:  Contention Management Errors

[Contributed by Taed Nelson (]

VtoolsD version 2.02 uses a different contention management method for Windows
95.  This new method is only documented in the new version of the VCOMM
documentation, which is available from the VCOMM archives.

The first problem was due to not reading the documentation closely enough.  In
my INF file, I specified the contention handler as *VCD for my port driver,
which is on a non-standard port, COM5.  I don't think that documentation makes
it clear if it is OK to use *VCD for non-standard ports, but it did not seem
to break under VTD 2.01.

Anyway, it is bad when using the new 2.02 way -- it will always say that it
failed to open the port in PortOpen.  I just removed the Contention entry for
my port in the Registry, and that seemed to fix it.  Without this entry, VCOMM
itself will do simple contention management.

[The remainder is believed to be fixed in version 2.03.]

The second problem is a minor but significant problem with Vireo's
implementation.  VCOMM will not release a port unless the port driver provides
a notification function.  (This seems like a stupid VCOMM requirement, but
that's another issue.)

The easy way around this is to override the function CtnNotifyHandler (I think
that's the name).  For me, I just return TRUE in this function.  I'm not sure
why this helps, since the base VcommPort provides one, but I have verified
this by stepping through the VCOMM assembly source.  For some reason, if it is
not overridden, the creation of the thunk will return NULL, and VCOMM does not
like it.  (Personally, I think that is a VCOMM misfeature, but it is
documented that way...)

The symptom of this bug is that you can open your port, and attempt to close
it (which fails, and you will hit a DEBUGWARN if you have that turned on), but
you will not be able to open it a second time without rebooting the machine.

11.5:  Other Errors

The GetError member function should be renamed to GetWin32Error.  Although
just what a "Win32 Error" is remains a mystery.

[Fixed in version 2.02.] The parameters of VCOMM_Map_Ring3DCB_To_Ring0 are
just wrong.  Right now, it has VCOMM_Map_Ring3DCB_To_Ring0 (unsigned long *,
_dcb **).  It really should be VCOMM_Map_Ring3DCB_To_Ring0 (win32_dcb *, _dcb
*).  Thus, you need a structure in your copy of vcomm.h for a win32_dcb.  This
can be copied from \DDK\Include\

[Fixed in version 2.02.] The type of the referenceData in the parameters for
EnableNotification, SetReadCallback, and SetWriteCallback should be all the
same.  Right now, it has the first as a PVOID, and the latter two as DWORD.
The PCOMMNOTIFYPROC callbacks in Vthunks.h use PVOID, but DWORD seems to make
more sense.  Regardless, it should be consistent.

[Fixed in version 2.02.] In \vtd95\include\vcomm.h, the structure _COMM_CONFIG
is incorrect.  It contains a _win32_dcb, NOT a _DCB (which is for ring 0) --
the two sub-structures are different!  The sizeof (_COMM_CONFIG) should be
0x34, not 0x45 as it is now.

[Fixed in version 2.02.] The VcommPort class does not initialize the data
member m_dcb.  It should probably at least initialize the length, and maybe
zero out the rest.  Or document that it is not initialized.

The VcommPort class should have a data member called m_commProp (of type
_COMMPROP).  Every port driver must have this structure (due to the function
GetProperties).  It should also be initialized in the same way as m_dcb above.

11.6:  Makefiles and #defines

This is somewhat out of the scope of VCOMM, but it is useful information

11.6.1:  Turning off optimization (Taed's way)

[Fixed in version 2.02 with the addition of the COPTFLAGS define.]

[Contributed by Taed Nelson (]

To make debugging easier, I turn off all optimizations, and attempt (but fail)
to get more debugging information, by editing \VTD95\Include\MS9.MAK to the

	CFLAGS          = -W2 -Zp -Gs -c -bzalign -Zl -D_X86_ -DIS_32 \
	ASMFLAGS        = -DMASM6 -c -W2 -Cx -DCOFF -coff

	! if $(DEBUG) != 0
	CFLAGS          = $(CFLAGS) -Od -Oi -DDEBUG -Zi
	! else
	CFLAGS          = $(CFLAGS) -Ogaisb1
	! endif

11.6.2:  Turning off optimization (Michael's way)

[Fixed in version 2.02 with the addition of the COPTFLAGS define.]

[Contributed by Michael Grabelkovsky (]

All of us have had a problem when the debugger (ICE) shifts the lines of the
program.  This is a recommendation improve the situation:

The next fragment is added to the project MAK file after the "!include
$(VTOOLSD)\..." statement:

	! if $(DEBUG) == 1
	! endif

If the macros such as VxDJmp and VxDCall are used, they will not work
correctly without optimization.  The next pragma corrects the situation:

	#pragma optimize( "gas", on )   // enable optimization
	#pragma optimize( "gas", off )   // disable optimization

The last statements may be correctly used together with #ifdef DEBUG...
statement for the same goals.

11.6.3:  Version resource

[Fixed in version 2.02.]

If you have a version resource file, such as <project>.vrc, it will be
overwritten by VtoolsD every time you do a build-all.

This can be avoided by editing the VtoolsD makefile.  For example, in
\VTD95\Include\MS9VXD.MAK, you can comment out the following lines:

	#$(VRCNAME):     $(VTOOLSD)\include\default.vrc
	#        copy $(VTOOLSD)\include\default.vrc $(VRCNAME)

11.6.4:  Dependencies

Remember that your project makefile does not have full dependencies, unless
you generate them by hand.  For example, if you change a .H file, the
appropriate .C or .CPP file will not recompile.

This can be avoided by always doing a build-all (takes longer to compile),
generating the full makefile dependencies by hand (annoying to keep
up-to-date), or finding a PC version of the funky Unix tool MAKEDEPEND.

If anyone finds a PC version of MAKEDEPEND, please let the list know.
Surprisingly enough, it is not in the ever-dependable MKS Toolkit.

11.6.5:  Assert versus ASSERT

[Fixed in version 2.03 with the addition of a global #define.]

If you have used the ASSERT macro in the past, then you are used to ASSERT.
The VtoolsD version is spelled as Assert.  To make matters worse, ASSERT is
defined in MINIPORT.H as nothing!

To get around this, I commented the line out of MINIPORT.H, and added the
following to my project makefile:


11.6.6:  DEBUG versus _DEBUG

Microsoft VC++ users are used to seeing the #define for _DEBUG.  VtoolsD uses
DEBUG.  (It may actually be useful to have different #defines for some
people.)  This is a trivial change to \VTD95\Include\MS9.MAK:


11.6.7:  Avoiding the dprintf() call

When not compiling with DEBUG, the dprintf() function is still called, but it
is just a stub which does nothing.  The reason for this is that the C
pre-processor cannot handle macros with variable number of arguments.

To avoid this minimal overhead, many solutions have been proposed, but the one
suggested by David McCullough ( seems to be the best:

	#ifdef DEBUG
	#define DPRINTF		dprintf
	#define DPRINTF		0 && (* (int (*)(...)) 0)

For the non-DEBUG case, it will first test the "0", which will never be TRUE,
and therfore it will never continue with the function call.  A NULL function
pointer is used, instead of dprintf(), to avoid the function being linked in.
With optimizations on, the entire statement should not generate any code.
(Although the format strings may still exist after linking.)

User Contributions:

Comment about this article, ask questions, or add new information about this topic:


[ Usenet FAQs | Web FAQs | Documents | RFC Index ]

Send corrections/additions to the FAQ Maintainer: (Taed Nelson)

Last Update March 27 2014 @ 02:12 PM