From d68405550db3852d760cbc105e0d9925f8df0536 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Tue, 24 Feb 2026 20:03:34 -0600 Subject: [PATCH] Fix COMM.DRV calling conventions and add ComDEB compatibility Resolve GPFs in both USER.EXE and COMMTASK.DLL by correcting RETF sizes for SETCOM and GETDCB, confirmed by disassembling CyberCom.DRV. Add stock-compatible ComDEB structure so third-party code (ProComm COMMTASK.DLL) can safely access internal fields at known offsets per Microsoft KB Q101417. COMM.DRV changes: - SETCOM (ord 2): RETF 4, takes DCB FAR * only (not commId + DCB*) - GETDCB (ord 15): RETF 2, takes commId, returns DCB FAR * in DX:AX - Add 40-byte ComDebT matching stock COMM.DRV internal layout (evtWord at +0, MSR shadow at +35, queue counts at +8/+18) - cevt returns pointer to ComDebT for third-party compatibility - Sync ComDEB fields in ISR dispatch, reccom, sndcom, cflush, setque - Move WEP to ordinal 16, add ordinal 101 stub (match stock/CyberCom) - Default DBG_ENABLED to 0 (set to 1 to re-enable debug logging) VBX control fixes: - Fix SETBREAK/CLRBREAK constants (use numeric 8/9, not undefined macros) - Fix serialEnableNotify return type (BOOL, not int16_t) - Fix mscomm.h to work with RC compiler (#ifndef RC_INVOKED) - Fix vbapi.h USHORT typedef and MODEL.flWndStyle type - Add vbapi.lib dependency to makefile Co-Authored-By: Claude Opus 4.6 --- drv/commdrv.c | 393 ++++++++++++++++++++++++++++++++++++++++++++---- drv/commdrv.def | 2 + drv/commdrv.h | 107 +++++++++++-- drv/isr.c | 45 ++++-- drv/makefile | 4 +- vbx/makefile | 2 +- vbx/mscomm.h | 14 +- vbx/serial.c | 2 +- vbx/serial.h | 8 +- vbx/vbapi.h | 12 +- 10 files changed, 517 insertions(+), 72 deletions(-) diff --git a/drv/commdrv.c b/drv/commdrv.c index a614d96..52bec43 100644 --- a/drv/commdrv.c +++ b/drv/commdrv.c @@ -10,12 +10,154 @@ #include #include +// ----------------------------------------------------------------------- +// Debug logging via OutputDebugString +// ----------------------------------------------------------------------- +#define DBG_ENABLED 0 + +#if DBG_ENABLED +static void dbgStr(const char FAR *msg) +{ + OutputDebugString(msg); +} + +// Log a label and a 16-bit hex value: "label: 0xNNNN\r\n" +static void dbgHex16(const char FAR *label, uint16_t val) +{ + static const char hex[] = "0123456789ABCDEF"; + char buf[48]; + int i; + + for (i = 0; i < 40 && label[i]; i++) { + buf[i] = label[i]; + } + buf[i++] = ':'; + buf[i++] = ' '; + buf[i++] = '0'; + buf[i++] = 'x'; + buf[i++] = hex[(val >> 12) & 0xF]; + buf[i++] = hex[(val >> 8) & 0xF]; + buf[i++] = hex[(val >> 4) & 0xF]; + buf[i++] = hex[val & 0xF]; + buf[i++] = '\r'; + buf[i++] = '\n'; + buf[i] = '\0'; + OutputDebugString(buf); +} + +// Log a label and a signed 16-bit value: "label: -NNNN\r\n" +static void dbgInt16(const char FAR *label, int16_t val) +{ + char buf[48]; + int i; + uint16_t uv; + + for (i = 0; i < 40 && label[i]; i++) { + buf[i] = label[i]; + } + buf[i++] = ':'; + buf[i++] = ' '; + + if (val < 0) { + buf[i++] = '-'; + uv = (uint16_t)(-(int)val); + } else { + uv = (uint16_t)val; + } + + // Print decimal (up to 5 digits) + { + char digits[6]; + int n = 0; + do { + digits[n++] = (char)('0' + (uv % 10)); + uv /= 10; + } while (uv > 0); + while (n > 0) { + buf[i++] = digits[--n]; + } + } + + buf[i++] = '\r'; + buf[i++] = '\n'; + buf[i] = '\0'; + OutputDebugString(buf); +} + +// Log a FAR pointer as "label: SSSS:OOOO\r\n" +static void dbgFarPtr(const char FAR *label, void FAR *ptr) +{ + static const char hex[] = "0123456789ABCDEF"; + char buf[48]; + int i; + uint16_t seg; + uint16_t off; + + seg = _FP_SEG(ptr); + off = _FP_OFF(ptr); + + for (i = 0; i < 32 && label[i]; i++) { + buf[i] = label[i]; + } + buf[i++] = ':'; + buf[i++] = ' '; + buf[i++] = hex[(seg >> 12) & 0xF]; + buf[i++] = hex[(seg >> 8) & 0xF]; + buf[i++] = hex[(seg >> 4) & 0xF]; + buf[i++] = hex[seg & 0xF]; + buf[i++] = ':'; + buf[i++] = hex[(off >> 12) & 0xF]; + buf[i++] = hex[(off >> 8) & 0xF]; + buf[i++] = hex[(off >> 4) & 0xF]; + buf[i++] = hex[off & 0xF]; + buf[i++] = '\r'; + buf[i++] = '\n'; + buf[i] = '\0'; + OutputDebugString(buf); +} + +// Hex dump first 'count' bytes at a FAR pointer +static void dbgDump(const char FAR *label, void FAR *ptr, int count) +{ + static const char hex[] = "0123456789ABCDEF"; + char buf[80]; + uint8_t FAR *p; + int i; + int bi; + + p = (uint8_t FAR *)ptr; + + // Print label + for (bi = 0; bi < 32 && label[bi]; bi++) { + buf[bi] = label[bi]; + } + buf[bi++] = ':'; + buf[bi++] = ' '; + + for (i = 0; i < count && bi < 70; i++) { + buf[bi++] = hex[(p[i] >> 4) & 0xF]; + buf[bi++] = hex[p[i] & 0xF]; + buf[bi++] = ' '; + } + buf[bi++] = '\r'; + buf[bi++] = '\n'; + buf[bi] = '\0'; + OutputDebugString(buf); +} +#else +#define dbgStr(msg) ((void)0) +#define dbgHex16(label, val) ((void)0) +#define dbgInt16(label, val) ((void)0) +#define dbgFarPtr(label, p) ((void)0) +#define dbgDump(l, p, n) ((void)0) +#endif + // ----------------------------------------------------------------------- // Prototypes // ----------------------------------------------------------------------- -int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize); +int16_t FAR PASCAL _export inicom(DCB FAR *dcb); int16_t FAR PASCAL _export setcom(DCB FAR *dcb); -int16_t FAR PASCAL _export setque(int16_t commId, char FAR *rxBuf, int16_t rxSize, char FAR *txBuf, int16_t txSize); +int16_t FAR PASCAL _export setque(int16_t commId, int16_t rxSize, int16_t txSize); int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch); @@ -27,13 +169,14 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func); int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue); int16_t FAR PASCAL _export csetbrk(int16_t commId); int16_t FAR PASCAL _export cclrbrk(int16_t commId); -int16_t FAR PASCAL _export getdcb(int16_t commId, DCB FAR *dcb); +DCB FAR * FAR PASCAL _export getdcb(int16_t commId); void FAR PASCAL _export suspendOpenCommPorts(void); void FAR PASCAL _export reactivateOpenCommPorts(void); int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t rxThresh, int16_t txThresh); +int FAR PASCAL _export commNotifyWndProc(void); int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpCmdLine); int FAR PASCAL _export WEP(int nParam); @@ -46,7 +189,7 @@ static int16_t freeBuffers(PortStateT *port); static int16_t initBuffers(PortStateT *port, uint16_t rxSz, uint16_t txSz); static void initPortState(PortStateT *port, int16_t commId); void primeTx(PortStateT *port); -static void readPortConfig(int16_t commId, uint16_t *baseAddr, uint8_t *irq); +static void readPortConfig(int16_t commId, uint16_t FAR *baseAddr, uint8_t FAR *irq); static uint16_t readSystemIni(const char FAR *section, const char FAR *key, uint16_t defVal); // ----------------------------------------------------------------------- @@ -70,6 +213,18 @@ PortStateT ports[MAX_PORTS]; // ----------------------------------------------------------------------- static HANDLE ghInstance = NULL; +// ----------------------------------------------------------------------- +// Dynamically resolved PostMessage +// +// comm.drv is loaded from [boot] before USER.EXE, so we can't have a +// static import for PostMessage. Resolve it on first use via +// GetProcAddress(GetModuleHandle("USER"), "PostMessage"). +// ----------------------------------------------------------------------- +PostMessageProcT pfnPostMessage = NULL; + +// ISR hit counter for diagnostics +volatile uint16_t isrHitCount = 0; + // ----------------------------------------------------------------------- // applyBaudRate - Set the baud rate divisor on the UART @@ -215,6 +370,8 @@ int16_t FAR PASCAL _export cclrbrk(int16_t commId) PortStateT *port; uint8_t lcr; + dbgInt16("COMM.DRV: cclrbrk Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } @@ -243,6 +400,22 @@ int32_t FAR PASCAL _export cevt(int16_t commId, int16_t evtMask) { PortStateT *port; uint16_t FAR *ptr; + int32_t retVal; + +#if DBG_ENABLED + { + uint16_t ssSeg; + uint16_t bpVal; + _asm mov ssSeg, ss + _asm mov bpVal, bp + dbgHex16("COMM.DRV: cevt SS", ssSeg); + dbgHex16("COMM.DRV: cevt BP", bpVal); + dbgDump("COMM.DRV: cevt stk", (void FAR *)((uint32_t)ssSeg << 16 | (bpVal + 6)), 16); + } +#endif + + dbgInt16("COMM.DRV: cevt Id", commId); + dbgHex16("COMM.DRV: cevt mask", (uint16_t)evtMask); if (commId < 0 || commId >= MAX_PORTS) { return 0L; @@ -250,13 +423,18 @@ int32_t FAR PASCAL _export cevt(int16_t commId, int16_t evtMask) port = &ports[commId]; if (!port->isOpen) { + dbgStr("COMM.DRV: cevt not open\r\n"); return 0L; } - port->evtMask = (uint16_t)evtMask; + port->comDeb.evtMask = (uint16_t)evtMask; - ptr = &port->evtWord; - return (int32_t)(void FAR *)ptr; + ptr = &port->comDeb.evtWord; + retVal = (int32_t)(void FAR *)ptr; + dbgHex16("COMM.DRV: cevt retSeg", (uint16_t)(retVal >> 16)); + dbgHex16("COMM.DRV: cevt retOff", (uint16_t)(retVal & 0xFFFF)); + dbgStr("COMM.DRV: cevt OK\r\n"); + return retVal; } @@ -270,6 +448,8 @@ uint16_t FAR PASCAL _export cevtget(int16_t commId, int16_t evtMask) PortStateT *port; uint16_t events; + dbgInt16("COMM.DRV: cevtget Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return 0; } @@ -280,8 +460,8 @@ uint16_t FAR PASCAL _export cevtget(int16_t commId, int16_t evtMask) } _disable(); - events = port->evtWord & (uint16_t)evtMask; - port->evtWord &= ~(uint16_t)evtMask; + events = port->comDeb.evtWord & (uint16_t)evtMask; + port->comDeb.evtWord &= ~(uint16_t)evtMask; _enable(); return events; @@ -299,6 +479,9 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func) uint8_t mcr; uint16_t base; + dbgInt16("COMM.DRV: cextfcn Id", commId); + dbgInt16("COMM.DRV: cextfcn func", func); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } @@ -328,9 +511,9 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func) mcr &= ~MCR_RTS; port->rtsState = FALSE; break; - case SETBREAK: + case ESC_SETBREAK: return csetbrk(commId); - case CLRBREAK: + case ESC_CLRBREAK: return cclrbrk(commId); case RESETDEV: // No-op for serial ports @@ -364,6 +547,8 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue) { PortStateT *port; + dbgInt16("COMM.DRV: cflush Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } @@ -378,6 +563,9 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue) port->rxHead = 0; port->rxTail = 0; port->rxCount = 0; + port->comDeb.qInHead = 0; + port->comDeb.qInTail = 0; + port->comDeb.qInCount = 0; // Reset FIFO to clear hardware buffer too if (port->is16550 && port->fifoEnabled) { _outp(port->baseAddr + UART_FCR, FCR_ENABLE | FCR_RX_RESET | port->fifoTrigger); @@ -386,6 +574,9 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue) port->txHead = 0; port->txTail = 0; port->txCount = 0; + port->comDeb.qOutHead = 0; + port->comDeb.qOutTail = 0; + port->comDeb.qOutCount = 0; if (port->is16550 && port->fifoEnabled) { _outp(port->baseAddr + UART_FCR, FCR_ENABLE | FCR_TX_RESET | port->fifoTrigger); } @@ -401,10 +592,26 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue) // ----------------------------------------------------------------------- int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len) { + dbgInt16("COMM.DRV: commWriteStr Id", commId); return sndcom(commId, buf, len); } +// ----------------------------------------------------------------------- +// commNotifyWndProc - Ordinal 101 stub (undocumented, Win 3.1 compat) +// +// The stock COMM.DRV and CyberCom export an unnamed function at ordinal +// 101. Purpose is undocumented; may be an internal callback used by +// USER.EXE. CyberCom's implementation uses plain RETF (no params). +// Return 0 (not handled). +// ----------------------------------------------------------------------- +int FAR PASCAL _export commNotifyWndProc(void) +{ + dbgStr("COMM.DRV: ord101 called\r\n"); + return 0; +} + + // ----------------------------------------------------------------------- // csetbrk - Assert break signal (ordinal 13) // ----------------------------------------------------------------------- @@ -413,6 +620,8 @@ int16_t FAR PASCAL _export csetbrk(int16_t commId) PortStateT *port; uint8_t lcr; + dbgInt16("COMM.DRV: csetbrk Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } @@ -437,6 +646,8 @@ int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch) { PortStateT *port; + dbgInt16("COMM.DRV: ctx Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } @@ -504,19 +715,35 @@ int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t { PortStateT *port; + dbgInt16("COMM.DRV: enableNotif Id", commId); + dbgHex16("COMM.DRV: enableNotif hwnd", (uint16_t)hwnd); + dbgInt16("COMM.DRV: enableNotif rxTh", rxThresh); + dbgInt16("COMM.DRV: enableNotif txTh", txThresh); + if (commId < 0 || commId >= MAX_PORTS) { return FALSE; } port = &ports[commId]; if (!port->isOpen) { + dbgStr("COMM.DRV: enableNotif not open\r\n"); return FALSE; } + // Lazily resolve PostMessage from USER.EXE + // (not available at boot when comm.drv is loaded from [boot]) + if (!pfnPostMessage) { + HMODULE hUser = GetModuleHandle("USER"); + if (hUser) { + pfnPostMessage = (PostMessageProcT)GetProcAddress(hUser, "PostMessage"); + } + } + port->hwndNotify = hwnd; port->rxNotifyThresh = rxThresh; port->txNotifyThresh = txThresh; + dbgStr("COMM.DRV: enableNotif OK\r\n"); return TRUE; } @@ -551,23 +778,32 @@ static int16_t freeBuffers(PortStateT *port) // ----------------------------------------------------------------------- -// getdcb - Copy current DCB settings (ordinal 15) +// getdcb - Return pointer to internal DCB (ordinal 15) +// +// Takes int16_t commId (2 bytes, RETF 2). Returns DCB FAR * in DX:AX. +// The caller (USER.EXE / COMMTASK.DLL) copies from this pointer. +// CyberCom confirms: RETF 2, return pointer. // ----------------------------------------------------------------------- -int16_t FAR PASCAL _export getdcb(int16_t commId, DCB FAR *dcb) +DCB FAR * FAR PASCAL _export getdcb(int16_t commId) { PortStateT *port; + dbgInt16("COMM.DRV: getdcb Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { - return -1; + dbgStr("COMM.DRV: getdcb bad id\r\n"); + return NULL; } port = &ports[commId]; if (!port->isOpen) { - return -1; + dbgStr("COMM.DRV: getdcb not open\r\n"); + return NULL; } - _fmemcpy(dcb, &port->dcb, sizeof(DCB)); - return 0; + dbgHex16("COMM.DRV: getdcb isrHits", isrHitCount); + dbgStr("COMM.DRV: getdcb OK\r\n"); + return &port->dcb; } @@ -581,7 +817,7 @@ int16_t FAR PASCAL _export getdcb(int16_t commId, DCB FAR *dcb) // // Returns commId (0-3) on success, negative error code on failure. // ----------------------------------------------------------------------- -int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize) +int16_t FAR PASCAL _export inicom(DCB FAR *dcb) { int16_t commId; PortStateT *port; @@ -589,25 +825,52 @@ int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize) uint16_t txBufSize; uint8_t mcr; - (void)rxBuf; - (void)rxSize; + dbgStr("COMM.DRV: inicom enter\r\n"); + + // Dump raw stack to see actual parameters passed by caller + { + uint16_t bpVal; + uint16_t ssVal; + void FAR *stkPtr; + _asm mov bpVal, bp + _asm mov ssVal, ss + stkPtr = (void FAR *)((uint32_t)ssVal << 16 | (bpVal + 6)); + dbgHex16("COMM.DRV: inicom SS", ssVal); + dbgHex16("COMM.DRV: inicom BP", bpVal); + dbgDump("COMM.DRV: inicom stk", stkPtr, 24); + } if (!dcb) { + dbgStr("COMM.DRV: inicom NULL dcb\r\n"); return IE_DEFAULT; } + dbgFarPtr("COMM.DRV: inicom dcb", (void FAR *)dcb); + dbgDump("COMM.DRV: inicom raw", (void FAR *)dcb, 16); + dbgHex16("COMM.DRV: sizeof(DCB)", (uint16_t)sizeof(DCB)); + commId = dcb->Id; + dbgInt16("COMM.DRV: inicom Id", commId); + dbgHex16("COMM.DRV: inicom BaudRate", dcb->BaudRate); + dbgHex16("COMM.DRV: inicom ByteSize", (uint16_t)dcb->ByteSize); + dbgHex16("COMM.DRV: inicom Parity", (uint16_t)dcb->Parity); + dbgHex16("COMM.DRV: inicom StopBits", (uint16_t)dcb->StopBits); + if (commId < 0 || commId >= MAX_PORTS) { + dbgStr("COMM.DRV: inicom IE_BADID\r\n"); return IE_BADID; } port = &ports[commId]; if (port->isOpen) { + dbgStr("COMM.DRV: inicom IE_OPEN\r\n"); return IE_OPEN; } // Initialize port state initPortState(port, commId); + dbgHex16("COMM.DRV: inicom baseAddr", port->baseAddr); + dbgHex16("COMM.DRV: inicom irq", (uint16_t)port->irq); // Read buffer sizes from SYSTEM.INI if available (COMnBuffer key) { @@ -626,20 +889,26 @@ int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize) rxBufSize = readSystemIni("386Enh", bufKey, DEFAULT_RX_SIZE); } txBufSize = rxBufSize; + dbgHex16("COMM.DRV: inicom rxBufSize", rxBufSize); // Allocate ring buffers if (initBuffers(port, rxBufSize, txBufSize) != 0) { + dbgStr("COMM.DRV: inicom IE_MEMORY\r\n"); return IE_MEMORY; } + dbgStr("COMM.DRV: inicom buffers OK\r\n"); // Detect 16550 FIFO port->is16550 = (uint8_t)detect16550(port->baseAddr); + dbgHex16("COMM.DRV: inicom is16550", (uint16_t)port->is16550); // Hook ISR if (hookIsr(port) != 0) { + dbgStr("COMM.DRV: inicom hookIsr FAIL\r\n"); freeBuffers(port); return IE_HARDWARE; } + dbgStr("COMM.DRV: inicom ISR hooked\r\n"); port->isOpen = TRUE; @@ -675,12 +944,19 @@ int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize) // Clear any pending status _inp(port->baseAddr + UART_LSR); - _inp(port->baseAddr + UART_MSR); + port->comDeb.msrShadow = (uint8_t)_inp(port->baseAddr + UART_MSR); _inp(port->baseAddr + UART_RBR); + // Populate ComDEB for third-party compatibility + port->comDeb.port = port->baseAddr; + port->comDeb.baudRate = port->baudRate; + port->comDeb.qInSize = port->rxSize; + port->comDeb.qOutSize = port->txSize; + // Enable receive and line status interrupts _outp(port->baseAddr + UART_IER, IER_RDA | IER_LSI | IER_MSI); + dbgInt16("COMM.DRV: inicom OK, ret", commId); return commId; } @@ -833,6 +1109,8 @@ void FAR PASCAL _export reactivateOpenCommPorts(void) PortStateT *port; uint8_t mcr; + dbgStr("COMM.DRV: reactivate\r\n"); + for (i = 0; i < MAX_PORTS; i++) { port = &ports[i]; if (!port->isOpen) { @@ -873,6 +1151,7 @@ void FAR PASCAL _export reactivateOpenCommPorts(void) // ----------------------------------------------------------------------- int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len) { + dbgInt16("COMM.DRV: readCommStr Id", commId); return reccom(commId, buf, len); } @@ -883,7 +1162,7 @@ int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t // Checks [386Enh] for COMnBase (hex) and COMnIRQ overrides. // Falls back to standard defaults if not present. // ----------------------------------------------------------------------- -static void readPortConfig(int16_t commId, uint16_t *baseAddr, uint8_t *irq) +static void readPortConfig(int16_t commId, uint16_t FAR *baseAddr, uint8_t FAR *irq) { char key[10]; char buf[16]; @@ -963,6 +1242,8 @@ int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len) uint8_t FAR *dst; int16_t bytesRead; + dbgInt16("COMM.DRV: reccom Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } @@ -1002,29 +1283,47 @@ int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len) _enable(); } + // Sync ComDEB queue counts + port->comDeb.qInCount = port->rxCount; + port->comDeb.qInTail = port->rxTail; + return bytesRead; } // ----------------------------------------------------------------------- // setcom - Apply DCB settings to hardware (ordinal 2) +// +// Takes DCB FAR * (4 bytes, RETF 4). CommId is in dcb->Id. +// Both USER.EXE and COMMTASK.DLL push 4 bytes for this call. // ----------------------------------------------------------------------- int16_t FAR PASCAL _export setcom(DCB FAR *dcb) { int16_t commId; PortStateT *port; + dbgStr("COMM.DRV: setcom enter\r\n"); + if (!dcb) { + dbgStr("COMM.DRV: setcom NULL dcb\r\n"); return -1; } commId = dcb->Id; + dbgInt16("COMM.DRV: setcom Id", commId); + dbgHex16("COMM.DRV: setcom BaudRate", dcb->BaudRate); + dbgHex16("COMM.DRV: setcom ByteSize", (uint16_t)dcb->ByteSize); + dbgHex16("COMM.DRV: setcom Parity", (uint16_t)dcb->Parity); + dbgHex16("COMM.DRV: setcom StopBits", (uint16_t)dcb->StopBits); + if (commId < 0 || commId >= MAX_PORTS) { + dbgStr("COMM.DRV: setcom IE_BADID\r\n"); return IE_BADID; } port = &ports[commId]; if (!port->isOpen) { + dbgStr("COMM.DRV: setcom port not open\r\n"); return -1; } @@ -1053,8 +1352,14 @@ int16_t FAR PASCAL _export setcom(DCB FAR *dcb) port->xonLim = dcb->XonLim; port->xoffLim = dcb->XoffLim; + // Sync ComDEB shadow fields + port->comDeb.baudRate = port->baudRate; + port->comDeb.lcrShadow = (uint8_t)_inp(port->baseAddr + UART_LCR); + port->comDeb.mcrShadow = (uint8_t)_inp(port->baseAddr + UART_MCR); + _enable(); + dbgStr("COMM.DRV: setcom OK\r\n"); return 0; } @@ -1062,22 +1367,25 @@ int16_t FAR PASCAL _export setcom(DCB FAR *dcb) // ----------------------------------------------------------------------- // setque - Resize RX/TX buffers (ordinal 3) // -// The stock driver ignores the buffer pointers passed by the caller -// and manages its own. We do the same: free old buffers, alloc new. +// Caller passes port ID and requested RX/TX buffer sizes. +// We manage our own GlobalAlloc'd buffers. // ----------------------------------------------------------------------- -int16_t FAR PASCAL _export setque(int16_t commId, char FAR *rxBufArg, int16_t rxSz, char FAR *txBufArg, int16_t txSz) +int16_t FAR PASCAL _export setque(int16_t commId, int16_t rxSz, int16_t txSz) { PortStateT *port; - (void)rxBufArg; - (void)txBufArg; + dbgInt16("COMM.DRV: setque Id", commId); + dbgInt16("COMM.DRV: setque rxSz", rxSz); + dbgInt16("COMM.DRV: setque txSz", txSz); if (commId < 0 || commId >= MAX_PORTS) { + dbgStr("COMM.DRV: setque bad id\r\n"); return -1; } port = &ports[commId]; if (!port->isOpen) { + dbgStr("COMM.DRV: setque port not open\r\n"); return -1; } @@ -1085,10 +1393,21 @@ int16_t FAR PASCAL _export setque(int16_t commId, char FAR *rxBufArg, int16_t rx freeBuffers(port); if (initBuffers(port, (uint16_t)rxSz, (uint16_t)txSz) != 0) { _enable(); + dbgStr("COMM.DRV: setque IE_MEMORY\r\n"); return IE_MEMORY; } + // Sync ComDEB queue sizes + port->comDeb.qInSize = port->rxSize; + port->comDeb.qInCount = 0; + port->comDeb.qInHead = 0; + port->comDeb.qInTail = 0; + port->comDeb.qOutSize = port->txSize; + port->comDeb.qOutCount = 0; + port->comDeb.qOutHead = 0; + port->comDeb.qOutTail = 0; _enable(); + dbgStr("COMM.DRV: setque OK\r\n"); return 0; } @@ -1105,6 +1424,8 @@ int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len) uint8_t FAR *src; int16_t bytesWritten; + dbgInt16("COMM.DRV: sndcom Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } @@ -1134,6 +1455,10 @@ int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len) } _enable(); + // Sync ComDEB queue counts + port->comDeb.qOutCount = port->txCount; + port->comDeb.qOutHead = port->txHead; + // Prime transmitter if we wrote anything if (bytesWritten > 0 && !port->txStopped) { primeTx(port); @@ -1154,12 +1479,16 @@ int16_t FAR PASCAL _export stacom(int16_t commId, COMSTAT FAR *stat) PortStateT *port; int16_t errors; + dbgInt16("COMM.DRV: stacom Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { + dbgStr("COMM.DRV: stacom bad id\r\n"); return -1; } port = &ports[commId]; if (!port->isOpen) { + dbgStr("COMM.DRV: stacom not open\r\n"); return -1; } @@ -1177,6 +1506,7 @@ int16_t FAR PASCAL _export stacom(int16_t commId, COMSTAT FAR *stat) stat->cbOutQue = port->txCount; } + dbgHex16("COMM.DRV: stacom errors", (uint16_t)errors); return errors; } @@ -1192,6 +1522,8 @@ void FAR PASCAL _export suspendOpenCommPorts(void) int16_t i; PortStateT *port; + dbgStr("COMM.DRV: suspend\r\n"); + for (i = 0; i < MAX_PORTS; i++) { port = &ports[i]; if (!port->isOpen) { @@ -1221,12 +1553,15 @@ int16_t FAR PASCAL _export trmcom(int16_t commId) { PortStateT *port; + dbgInt16("COMM.DRV: trmcom Id", commId); + if (commId < 0 || commId >= MAX_PORTS) { return -1; } port = &ports[commId]; if (!port->isOpen) { + dbgStr("COMM.DRV: trmcom port not open\r\n"); return -1; } @@ -1252,6 +1587,8 @@ int16_t FAR PASCAL _export trmcom(int16_t commId) port->isOpen = FALSE; + dbgHex16("COMM.DRV: trmcom isrHits", isrHitCount); + dbgStr("COMM.DRV: trmcom OK\r\n"); return 0; } @@ -1268,6 +1605,8 @@ int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lp ghInstance = hInstance; + dbgStr("COMM.DRV: LibMain\r\n"); + if (wHeapSize > 0) { UnlockData(0); } diff --git a/drv/commdrv.def b/drv/commdrv.def index 8bb0682..df50fd2 100644 --- a/drv/commdrv.def +++ b/drv/commdrv.def @@ -20,8 +20,10 @@ EXPORTS CSETBRK @13 CCLRBRK @14 GETDCB @15 + WEP @16 RESIDENTNAME SUSPENDOPENCOMMPORTS @17 REACTIVATEOPENCOMMPORTS @18 COMMWRITESTRING @19 READCOMMSTRING @20 ENABLENOTIFICATION @100 + COMMNOTIFYWNDPROC @101 diff --git a/drv/commdrv.h b/drv/commdrv.h index 5892361..4f604c5 100644 --- a/drv/commdrv.h +++ b/drv/commdrv.h @@ -8,6 +8,7 @@ #define COMMDRV_H #include +#include // ----------------------------------------------------------------------- // stdint types for MSVC 1.52 (no stdint.h available) @@ -168,6 +169,7 @@ typedef signed char int8_t; // exceeds 65535, high baud rates use CBR_* index constants instead // of raw values. Values >= 0xFF00 are indices, not raw rates. // ----------------------------------------------------------------------- +// Most CBR_* constants defined by windows.h; add any missing ones #ifndef CBR_110 #define CBR_110 0xFF10 #define CBR_300 0xFF11 @@ -176,10 +178,20 @@ typedef signed char int8_t; #define CBR_2400 0xFF14 #define CBR_4800 0xFF15 #define CBR_9600 0xFF16 +#endif +#ifndef CBR_14400 #define CBR_14400 0xFF17 +#endif +#ifndef CBR_19200 #define CBR_19200 0xFF18 +#endif +#ifndef CBR_38400 #define CBR_38400 0xFF1B +#endif +#ifndef CBR_56000 #define CBR_56000 0xFF1F +#endif +#ifndef CBR_115200 #define CBR_115200 0xFF24 #endif @@ -189,15 +201,29 @@ typedef signed char int8_t; #define FIFO_DEPTH 16 // ----------------------------------------------------------------------- -// Comm error flags (CE_* -- matches Windows SDK definitions) +// Comm error flags (CE_* -- most defined by windows.h, fill any gaps) // ----------------------------------------------------------------------- -#define CE_RXOVER 0x0001 // Receive Queue overflow -#define CE_OVERRUN 0x0002 // Hardware overrun -#define CE_RXPARITY 0x0004 // Parity error -#define CE_FRAME 0x0008 // Framing error -#define CE_BREAK 0x0010 // Break detected -#define CE_TXFULL 0x0020 // TX Queue is full -#define CE_MODE 0x8000 // Requested mode unsupported +#ifndef CE_RXOVER +#define CE_RXOVER 0x0001 +#endif +#ifndef CE_OVERRUN +#define CE_OVERRUN 0x0002 +#endif +#ifndef CE_RXPARITY +#define CE_RXPARITY 0x0004 +#endif +#ifndef CE_FRAME +#define CE_FRAME 0x0008 +#endif +#ifndef CE_BREAK +#define CE_BREAK 0x0010 +#endif +#ifndef CE_TXFULL +#define CE_TXFULL 0x0020 +#endif +#ifndef CE_MODE +#define CE_MODE 0x8000 +#endif // ----------------------------------------------------------------------- // Comm event flags (EV_* -- matches Windows SDK definitions) @@ -237,7 +263,10 @@ typedef signed char int8_t; #define HS_BOTH 3 // ----------------------------------------------------------------------- -// EscapeCommFunction codes (matches Windows SDK) +// EscapeCommFunction codes +// +// SETXON through RESETDEV defined by windows.h. +// SETBREAK/CLRBREAK are our extensions for routing through cextfcn. // ----------------------------------------------------------------------- #ifndef SETXON #define SETXON 1 @@ -247,9 +276,9 @@ typedef signed char int8_t; #define SETDTR 5 #define CLRDTR 6 #define RESETDEV 7 -#define SETBREAK 8 -#define CLRBREAK 9 #endif +#define ESC_SETBREAK 8 +#define ESC_CLRBREAK 9 // ----------------------------------------------------------------------- // Flush queue selectors @@ -257,10 +286,48 @@ typedef signed char int8_t; #define FLUSH_RX 0 #define FLUSH_TX 1 +// ----------------------------------------------------------------------- +// Stock COMM.DRV compatible ComDEB structure +// +// SetCommEventMask (cevt) returns a FAR pointer to offset 0 of this +// structure. Third-party code (ProComm COMMTASK.DLL, etc.) accesses +// fields at known offsets -- most importantly offset 35 (MSR shadow) +// per Microsoft KB Q101417. Our layout must match the stock driver. +// ----------------------------------------------------------------------- +typedef struct { + uint16_t evtWord; // +0: Accumulated event flags (EV_*) + uint16_t evtMask; // +2: Event enable mask + uint16_t qInAddr; // +4: RX queue offset (compat, unused) + uint16_t qInSize; // +6: RX buffer size + uint16_t qInCount; // +8: RX bytes in buffer + uint16_t qInHead; // +10: RX write position + uint16_t qInTail; // +12: RX read position + uint16_t qOutAddr; // +14: TX queue offset (compat, unused) + uint16_t qOutSize; // +16: TX buffer size + uint16_t qOutCount; // +18: TX bytes in buffer + uint16_t qOutHead; // +20: TX write position + uint16_t qOutTail; // +22: TX read position + uint16_t port; // +24: UART base I/O address + uint16_t baudRate; // +26: Current baud rate + uint8_t lcrShadow; // +28: LCR shadow + uint8_t mcrShadow; // +29: MCR shadow + uint8_t ierShadow; // +30: IER shadow + uint8_t commErr; // +31: Error flags (low byte) + uint8_t flags1; // +32: Internal flags + uint8_t flags2; // +33: More internal flags + uint8_t recvTrigger; // +34: FIFO trigger level + uint8_t msrShadow; // +35: MSR shadow (documented KB Q101417) + uint8_t padding[4]; // +36: Pad to 40 bytes +} ComDebT; + // ----------------------------------------------------------------------- // Port state structure // ----------------------------------------------------------------------- typedef struct { + // Stock-compatible ComDEB -- must be kept synchronized. + // cevt returns a FAR pointer to this. + ComDebT comDeb; + uint16_t baseAddr; // UART base I/O address uint8_t irq; // IRQ number (3 or 4) int16_t commId; // Port ID (0=COM1, 1=COM2, ...) @@ -305,8 +372,6 @@ typedef struct { uint16_t errorFlags; // CE_* error flags (sticky until read) // Event notification - uint16_t evtMask; // Event enable mask - uint16_t evtWord; // Accumulated events HWND hwndNotify; // Window for WM_COMMNOTIFY int16_t rxNotifyThresh; // CN_RECEIVE threshold (-1=disabled) int16_t txNotifyThresh; // CN_TRANSMIT threshold (-1=disabled) @@ -328,14 +393,23 @@ typedef struct { // ----------------------------------------------------------------------- extern PortStateT ports[MAX_PORTS]; +// ----------------------------------------------------------------------- +// Dynamically resolved PostMessage (USER.EXE not loaded at boot) +// ----------------------------------------------------------------------- +typedef BOOL (FAR PASCAL *PostMessageProcT)(HWND, UINT, WPARAM, LPARAM); +extern PostMessageProcT pfnPostMessage; + +// ISR hit counter for diagnostics +extern volatile uint16_t isrHitCount; + // ----------------------------------------------------------------------- // Exported function prototypes (COMM.DRV API) // // These use the Windows COMM.DRV calling convention: FAR PASCAL // ----------------------------------------------------------------------- -int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize); +int16_t FAR PASCAL _export inicom(DCB FAR *dcb); int16_t FAR PASCAL _export setcom(DCB FAR *dcb); -int16_t FAR PASCAL _export setque(int16_t commId, char FAR *rxBuf, int16_t rxSize, char FAR *txBuf, int16_t txSize); +int16_t FAR PASCAL _export setque(int16_t commId, int16_t rxSize, int16_t txSize); int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch); @@ -347,12 +421,13 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func); int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue); int16_t FAR PASCAL _export csetbrk(int16_t commId); int16_t FAR PASCAL _export cclrbrk(int16_t commId); -int16_t FAR PASCAL _export getdcb(int16_t commId, DCB FAR *dcb); +DCB FAR * FAR PASCAL _export getdcb(int16_t commId); void FAR PASCAL _export suspendOpenCommPorts(void); void FAR PASCAL _export reactivateOpenCommPorts(void); int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t rxThresh, int16_t txThresh); +int FAR PASCAL _export commNotifyWndProc(void); // ----------------------------------------------------------------------- // ISR prototypes (isr.c) diff --git a/drv/isr.c b/drv/isr.c index df9af8f..85a6bae 100644 --- a/drv/isr.c +++ b/drv/isr.c @@ -106,12 +106,12 @@ static void checkNotify(PortStateT *port) } // CN_EVENT: any event bits accumulated - if (port->evtWord & port->evtMask) { + if (port->comDeb.evtWord & port->comDeb.evtMask) { notifyBits |= CN_EVENT; } - if (notifyBits) { - PostMessage(port->hwndNotify, WM_COMMNOTIFY, (WPARAM)port->commId, (LPARAM)notifyBits); + if (notifyBits && pfnPostMessage) { + pfnPostMessage(port->hwndNotify, WM_COMMNOTIFY, (WPARAM)port->commId, (LPARAM)notifyBits); } } @@ -132,10 +132,10 @@ static void handleLsr(PortStateT *port, uint8_t lsr) } if (lsr & LSR_BI) { port->errorFlags |= CE_BREAK; - port->evtWord |= EV_BREAK; + port->comDeb.evtWord |= EV_BREAK; } if (lsr & (LSR_OE | LSR_PE | LSR_FE)) { - port->evtWord |= EV_ERR; + port->comDeb.evtWord |= EV_ERR; } } @@ -149,8 +149,11 @@ static void handleMsr(PortStateT *port) msr = (uint8_t)_inp(port->baseAddr + UART_MSR); + // Update ComDEB MSR shadow (offset 35) for third-party code + port->comDeb.msrShadow = msr; + if (msr & MSR_DCTS) { - port->evtWord |= EV_CTS; + port->comDeb.evtWord |= EV_CTS; // RTS/CTS flow control: stop/start TX based on CTS if (port->hsMode == HS_RTSCTS || port->hsMode == HS_BOTH) { @@ -167,15 +170,15 @@ static void handleMsr(PortStateT *port) } if (msr & MSR_DDSR) { - port->evtWord |= EV_DSR; + port->comDeb.evtWord |= EV_DSR; } if (msr & MSR_TERI) { - port->evtWord |= EV_RING; + port->comDeb.evtWord |= EV_RING; } if (msr & MSR_DDCD) { - port->evtWord |= EV_RLSD; + port->comDeb.evtWord |= EV_RLSD; } } @@ -230,7 +233,7 @@ static void handleRx(PortStateT *port, uint8_t lsr) } // Set event bit - port->evtWord |= EV_RXCHAR; + port->comDeb.evtWord |= EV_RXCHAR; // Read LSR again for next byte lsr = (uint8_t)_inp(base + UART_LSR); @@ -270,7 +273,7 @@ static void handleTx(PortStateT *port) // Nothing to send -- disable THRE interrupt _outp(base + UART_IER, (uint8_t)(_inp(base + UART_IER) & ~IER_THRE)); // TX empty event - port->evtWord |= EV_TXEMPTY; + port->comDeb.evtWord |= EV_TXEMPTY; return; } @@ -421,6 +424,14 @@ void isrDispatch(PortStateT *port) } } + // Sync queue counts into ComDEB for third-party code + port->comDeb.qInCount = port->rxCount; + port->comDeb.qInHead = port->rxHead; + port->comDeb.qInTail = port->rxTail; + port->comDeb.qOutCount = port->txCount; + port->comDeb.qOutHead = port->txHead; + port->comDeb.qOutTail = port->txTail; + checkNotify(port); } @@ -478,6 +489,12 @@ void _far _interrupt isr3(void) { int16_t i; + // Load DLL's data segment -- _interrupt saves/restores DS but doesn't + // set it. Without this, DS belongs to whatever code was interrupted + // and all global accesses (ports[], ring buffers) read garbage. + _asm mov ax, seg ports + _asm mov ds, ax + for (i = 0; i < MAX_PORTS; i++) { if (ports[i].isOpen && ports[i].irq == 3) { isrDispatch(&ports[i]); @@ -496,6 +513,12 @@ void _far _interrupt isr4(void) { int16_t i; + // Load DLL's data segment -- see comment in isr3 + _asm mov ax, seg ports + _asm mov ds, ax + + isrHitCount++; + for (i = 0; i < MAX_PORTS; i++) { if (ports[i].isOpen && ports[i].irq == 4) { isrDispatch(&ports[i]); diff --git a/drv/makefile b/drv/makefile index 06e7484..e869638 100644 --- a/drv/makefile +++ b/drv/makefile @@ -28,9 +28,9 @@ LINK = link # -ASw Small model, SS!=DS (Windows DLL) # -Gsw No stack probes, Windows prolog/epilog # -Ow Safe optimizations for Windows -# -Zp1 Pack structures on 1-byte boundaries (hardware register layouts) +# -Zp2 Pack structures on 2-byte boundaries (matches Windows SDK) # -Ze Enable Microsoft extensions -CFLAGS = -c -W3 -ASw -Gsw -Ow -Zp1 -Ze +CFLAGS = -c -W3 -ASw -Gsw -Ow -Zp2 -Ze # Linker flags: # /NOD No default libraries diff --git a/vbx/makefile b/vbx/makefile index 285a004..4671f56 100644 --- a/vbx/makefile +++ b/vbx/makefile @@ -61,7 +61,7 @@ OBJS = mscomm.obj serial.obj # ----------------------------------------------------------------------- all: $(TARGET) -$(TARGET): $(OBJS) mscomm.def mscomm.res +$(TARGET): $(OBJS) mscomm.def mscomm.res vbapi.lib $(LINK) $(LFLAGS) $(OBJS), $(TARGET),,$(LIBS), mscomm.def $(RC) mscomm.res $(TARGET) diff --git a/vbx/mscomm.h b/vbx/mscomm.h index cbda195..6499424 100644 --- a/vbx/mscomm.h +++ b/vbx/mscomm.h @@ -5,6 +5,13 @@ #ifndef MSCOMM_H #define MSCOMM_H +// ----------------------------------------------------------------------- +// Resource IDs +// ----------------------------------------------------------------------- +#define IDB_MSCOMM 8000 + +#ifndef RC_INVOKED + #include "vbapi.h" #include "serial.h" @@ -21,11 +28,6 @@ typedef signed char int8_t; #define _STDINT_DEFINED #endif -// ----------------------------------------------------------------------- -// Resource IDs -// ----------------------------------------------------------------------- -#define IDB_MSCOMM 8000 - // ----------------------------------------------------------------------- // Property indices (position in npproplist array) // ----------------------------------------------------------------------- @@ -138,4 +140,6 @@ typedef struct { // ----------------------------------------------------------------------- extern HANDLE ghInstance; +#endif // RC_INVOKED + #endif // MSCOMM_H diff --git a/vbx/serial.c b/vbx/serial.c index 05cc0fe..0cb2845 100644 --- a/vbx/serial.c +++ b/vbx/serial.c @@ -12,7 +12,7 @@ // ----------------------------------------------------------------------- int16_t serialClose(int16_t commId); int16_t serialConfigure(int16_t commId, int16_t port, const char FAR *settings); -int16_t serialEnableNotify(int16_t commId, HWND hwnd, int16_t rxThreshold, int16_t txThreshold); +BOOL serialEnableNotify(int16_t commId, HWND hwnd, int16_t rxThreshold, int16_t txThreshold); int16_t serialEscape(int16_t commId, int16_t func); int16_t serialFlush(int16_t commId, int16_t queue); UINT serialGetEventMask(int16_t commId, UINT mask); diff --git a/vbx/serial.h b/vbx/serial.h index 2abe8a7..84bfc73 100644 --- a/vbx/serial.h +++ b/vbx/serial.h @@ -37,13 +37,17 @@ typedef signed char int8_t; // ----------------------------------------------------------------------- // Escape function constants (mirrors EscapeCommFunction values) +// +// SETDTR through RESETDEV are defined by windows.h. +// SETBREAK/CLRBREAK are not in windows.h (SetCommBreak/ClearCommBreak +// are separate API functions), so we define numeric values directly. // ----------------------------------------------------------------------- #define SERIAL_SETDTR SETDTR #define SERIAL_CLRDTR CLRDTR #define SERIAL_SETRTS SETRTS #define SERIAL_CLRRTS CLRRTS -#define SERIAL_SETBREAK SETBREAK -#define SERIAL_CLRBREAK CLRBREAK +#define SERIAL_SETBREAK 8 +#define SERIAL_CLRBREAK 9 // ----------------------------------------------------------------------- // Function prototypes diff --git a/vbx/vbapi.h b/vbx/vbapi.h index a40a5d6..f971406 100644 --- a/vbx/vbapi.h +++ b/vbx/vbapi.h @@ -17,17 +17,15 @@ // ----------------------------------------------------------------------- // Core types // ----------------------------------------------------------------------- +#ifndef USHORT +typedef unsigned short USHORT; +#endif + typedef WORD HCTL; // Handle to a VBX control instance typedef WORD HSZ; // Handle to a VB-managed string typedef LONG HLSTR; // Handle to a VB long string typedef USHORT ERR; // Error code -// Segment type for MSVC 1.52 -#ifndef _SEGMENT_DEFINED -typedef unsigned short _segment; -#define _SEGMENT_DEFINED -#endif - // Flag type typedef DWORD FL; @@ -196,7 +194,7 @@ struct tagMODEL { FL fl; // MODEL_* flags PCTLPROC pctlproc; // Control procedure USHORT fsClassStyle; // Window class style bits - USHORT flWndStyle; // Window style bits + FL flWndStyle; // Window style bits USHORT cbCtlExtra; // Bytes of per-instance data USHORT idBmpPalette; // Toolbox bitmap resource ID PSTR npszDefCtlName; // Default control name (near)