Newsgroups: comp.os.ms-windows.programmer.vxd,comp.answers,news.answers Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!news.media.mit.edu!uhog.mit.edu!nntp.uac.net!cancer.vividnet.com!hunter.premier.net!www.nntp.primenet.com!nntp.primenet.com!news-peer.gsl.net!news.gsl.net!news.mathworks.com!newsfeed.internetmci.com!nntp-hub2.barrnet.net!nntp-hub3.barrnet.net!voder!nsc!desktop!nelson From: nelson@desktop.nsc.com (Taed Nelson) Subject: VCOMM Frequently Asked Questions (FAQ) Message-ID: Followup-To: comp.os.ms-windows.programmer.vxd Summary: Common topics about VCOMM port drivers for Microsoft Windows. Sender: nelson@desktop (Taed Nelson) Nntp-Posting-Host: desktop.nsc.com Organization: National Semiconductor Corporation (Santa Clara CA USA) X-Newsreader: xrn 8.02-beta-2 Date: Fri, 13 Sep 1996 23:45:13 GMT Approved: news-answers-request@MIT.EDU Lines: 1280 Xref: senator-bedfellow.mit.edu comp.os.ms-windows.programmer.vxd:5582 comp.answers:21124 news.answers:81649 Archive-name: windows/programming/vcomm Posting-Frequency: bimonthly Last-modified: 1996/09/13 Version: 1.8 ====================================== 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 majordomo@corp.nsc.com, 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 (michael@slink.co.il). Taed Nelson, National Semiconductor Corporation (nelson@lan.nsc.com). The editor of this document is Taed Nelson (nelson@lan.nsc.com). ============================ 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 authors. 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 majordomo@corp.nsc.com.) 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 (vcomm@corp.nsc.com). 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 majordomo@corp.nsc.com to subscribe, or contact owner-vcomm@corp.nsc.com 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 (ddk-l@eva.dc.lsoft.com). 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 listserv@peach.ease.lsoft.com to subscribe, or owner-ddk-l@chsw.com for other requests. DDK Mailing List (ddk@cfn.ist.utl.pt). This covers general VxD development. Mail the body "subscribe vcomm" to majordomo@cfn.ist.utl.pt to subscribe, or contact owner-vcomm@cfn.ist.utl.pt for other requests. Comp.os.ms-windows.programmer.vxd 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 http://world.std.com/~vireo/. 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 ftp://ftp.ora.com/pub/examples/windows/win95.update/vxdmon.html. 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 ftp://ftp.hayes.com/. ================== 7: General Issues ================== 7.1: Serial.vxd Source Won't Compile ===================================== [Contributed by Taed Nelson (nelson@lan.nsc.com).] 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 (billstu@microsoft.com).] 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:\masm611\binr\new-vars.bat 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 (michael@slink.co.il).] 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 [esi.QOutMod]. 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 (nelson@lan.nsc.com).] 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: HKR,,EnumPropPages,0,"serialui.dll,EnumPropPages". 7.3: Non-Standard Ports ======================== [Contributed by Taed Nelson (nelson@lan.nsc.com).] 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 application. 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 (nelson@lan.nsc.com).] 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 MyComputer\HKEY_LOCAL_MACHINE\Enum\Root\Ports\0000. 7.5: Logical Memory Resources ============================== [Contributed by David McCullough (davidm@stallion.com).] 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 stopped. I don't know about multiple IO addresses yet. 7.6: Init Order ================ [Contributed by Taed Nelson (nelson@lan.nsc.com).] 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 (nelson@lan.nsc.com).] 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 driver. 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 W95. A similar approach can be taken for printers. 7.8: Point-to-Point Protocol (PPP) =================================== [Contributed by Taed Nelson (nelson@lan.nsc.com).] 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 "vcomm.9602".] 7.10: HyperTerminal Function Trace =================================== [Contributed by Taed Nelson (nelson@lan.nsc.com).] 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". 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. OnSysDynamicDeviceInit 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) Callback: CN_TRANSMIT 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_TRANSMIT Callback: CN_EVENT=00000004 Callback: CN_TRANSMIT Callback: CN_EVENT=00000004 Callback: CN_TRANSMIT Callback: CN_EVENT=00000004 Callback: CN_TRANSMIT Callback: CN_EVENT=00000004 Callback: CN_TRANSMIT Callback: CN_EVENT=00000004 Callback: CN_TRANSMIT Callback: CN_EVENT=00000004 Callback: CN_TRANSMIT Callback: CN_EVENT=00000004 Callback: CN_EVENT=00000004 Close 7.11: Blockable Functions ========================== [Contributed by Joe Cossette (joec@infoark.com).] 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, etc.,...). 7.11.1: Blockable Port functions --------------------------------- PortOpen() PortClose() PortGetCommState() PortGetProperties() PortSetup() PortPurge() PortEnableNotification() PortSetEventMask() PortSetModemStatusShadow() PortSetReadCallBack() PortSetWriteCallBack() 7.11.2: Non-Blockable Port functions ------------------------------------- PortSetCommState() PortTransmitChar() PortGetQueueStatus() PortClearError() PortEscapeFunction() PortGetEventMask() PortWrite() PortRead() PortGetModemStatus() PortGetCommConfig() PortSetCommConfig() PortGetWin32Error() PortDeviceIOCtl() 7.12: Support for DOS Applications =================================== [Contributed by John Loram (johnl@turbocom.com).] 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 capability. 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 johnl@turbocom.com, call him at 541-482-2744 (Ashland, Oregon), or check their web site at http://www.turbocom.com/. ============================== 8: Problems With Applications ============================== 8.1: HyperTerminal Closes the Port Unexpectedly ================================================ [Contributed by Taed Nelson (nelson@lan.nsc.com).] 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 (http://web.aimnet.com/~jnavas/modem/faq.html) 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 (michael@slink.co.il).] 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 understandable. 8.4: HyperTerminal can't work at high DTE speed ================================================ [Contributed by Michael Grabelkovsky (michael@slink.co.il).] 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 (michael@slink.co.il).] 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 "at+fclass=?". ======================= 9: Problems with VCOMM ======================= 9.1: PortOpen Causes VCOMM to Crash ==================================== [Contributed by Michael Grabelkovsky (michael@slink.co.il).] 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 (nelson@lan.nsc.com).] 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 (nelson@lan.nsc.com).] 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 (nelson@lan.nsc.com) and Michael Grabelkovsky (michael@slink.co.il).] 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 else.) 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 GETPORTHANDLE. 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 SDK. 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 Get_System_Time_Address.) 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: IE_CHARWAITING and IE_TIMEOUT. 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 (nelson@lan.nsc.com) and Michael Grabelkovsky (michael@slink.co.il).] 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 EscapeFunction. [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 (xwang@wco.com).] 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 (nelson@lan.nsc.com).] 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\Vcommw32.inc. [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 nonetheless. 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 (nelson@lan.nsc.com).] 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 following: CFLAGS = -W2 -Zp -Gs -c -bzalign -Zl -D_X86_ -DIS_32 \ -DWANTVXDWRAPS -DVTOOLSD ASMFLAGS = -DMASM6 -c -W2 -Cx -DCOFF -coff ! if $(DEBUG) != 0 CFLAGS = $(CFLAGS) -Od -Oi -DDEBUG -Zi ASMFLAGS = $(ASMFLAGS) -DDEBUG -Zi ! else CFLAGS = $(CFLAGS) -Ogaisb1 ASMFLAGS = $(ASMFLAGS) ! 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 (michael@slink.co.il).] 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 CFLAGS = $(CFLAGS) -Od ! 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 .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: XFLAGS = -DASSERT=Assert 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: CFLAGS = ... -DDEBUG -D_DEBUG ... AFLAGS = ... -DDEBUG -D_DEBUG ... 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 (davidm@stallion.oz.au) seems to be the best: #ifdef DEBUG #define DPRINTF dprintf #else #define DPRINTF 0 && (* (int (*)(...)) 0) #endif 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.)