winspool: (EnumPorts #3) Implement EnumPortsA

Detlef Riekenberg wine.dev at web.de
Fri Nov 3 17:27:31 CST 2006


Changelog:
 winspool: (EnumPorts #3) Implement EnumPortsA

Faults in the old implementation of EnumPortsA:
- Only the serial Ports where returned
- Settings in the Registry where ignored
  HKLM\Software\Microsoft\Windows NT\CurrentVersion\Ports
- Port-Overwrite used the old key from the config-file
  (HKLM\Software\Wine\Wine\Config\Spooler)
- Port to Overwrite had a maximum of 9 characters
- Not implemented on top of EnumPortsW


(Portmonitors for NT are UNICODE-Only.)



-- 
 
By by ... Detlef

-------------- next part --------------
>From f8cd6ed5c1c8afac0012334c9c5ed9c5ed23df8c Mon Sep 17 00:00:00 2001
From: Detlef Riekenberg <wine.dev at web.de>
Date: Sat, 4 Nov 2006 00:03:13 +0100
Subject: [PATCH] winspool: (EnumPorts #3) Implement EnumPortsA
---
 dlls/winspool.drv/info.c |  232 +++++++++++++++++++++-------------------------
 1 files changed, 107 insertions(+), 125 deletions(-)

diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index b1fafd6..ebcd320 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -4666,159 +4666,141 @@ BOOL WINAPI EnumPrinterDriversA(LPSTR pN
     return ret;
 }
 
-static CHAR PortMonitor[] = "Wine Port Monitor";
-static CHAR PortDescription[] = "Wine Port";
-
-static BOOL WINSPOOL_ComPortExists( LPCSTR name )
-{
-    HANDLE handle;
-
-    handle = CreateFileA( name, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
-                         NULL, OPEN_EXISTING, 0, NULL );
-    if (handle == INVALID_HANDLE_VALUE)
-        return FALSE;
-    TRACE("Checking %s exists\n", name );
-    CloseHandle( handle );
-    return TRUE;
-}
-
-static DWORD WINSPOOL_CountSerialPorts(void)
-{
-    CHAR name[6];
-    DWORD n = 0, i;
-
-    for (i=0; i<4; i++)
-    {
-        strcpy( name, "COMx:" );
-        name[3] = '1' + i;
-        if (WINSPOOL_ComPortExists( name ))
-            n++;
-    }
-
-    return n;
-}
-
 /******************************************************************************
  *		EnumPortsA   (WINSPOOL.@)
  *
  * See EnumPortsW.
  *
- * BUGS
- *  ANSI-Version did not call the UNICODE-Version
- *
  */
-BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
-                       LPDWORD bufneeded,LPDWORD bufreturned)
+BOOL WINAPI EnumPortsA( LPSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,
+                        LPDWORD pcbNeeded, LPDWORD pcReturned)
 {
-    CHAR portname[10];
-    DWORD info_size, ofs, i, printer_count, serial_count, count, n, r;
-    const LPCSTR szPrinterPortKey = "Software\\Wine\\Wine\\Config\\spooler";
-    HKEY hkey_printer;
-    BOOL retval = TRUE;
+    BOOL    res;
+    LPBYTE  bufferW = NULL;
+    LPWSTR  nameW = NULL;
+    DWORD   needed = 0;
+    DWORD   numentries = 0;
+    INT     len;
 
-    TRACE("(%s,%d,%p,%d,%p,%p)\n",
-          debugstr_a(name),level,buffer,bufsize,bufneeded,bufreturned);
+    TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_a(pName), Level, pPorts,
+          cbBuf, pcbNeeded, pcReturned);
 
-    switch( level )
-    {
-    case 1:
-        info_size = sizeof (PORT_INFO_1A);
-        break;
-    case 2:
-        info_size = sizeof (PORT_INFO_2A);
-        break;
-    default:
-        SetLastError(ERROR_INVALID_LEVEL);
-        return FALSE;
+    /* convert servername to unicode */
+    if (pName) {
+        len = MultiByteToWideChar(CP_ACP, 0, pName, -1, NULL, 0);
+        nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, pName, -1, nameW, len);
     }
-    
-    /* see how many exist */
+    /* alloc (userbuffersize*sizeof(WCHAR) and try to enum the Ports */
+    needed = cbBuf * sizeof(WCHAR);    
+    if (needed) bufferW = HeapAlloc(GetProcessHeap(), 0, needed);
+    res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
 
-    hkey_printer = 0;
-    serial_count = WINSPOOL_CountSerialPorts();
-    printer_count = 0;
+    if(!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+        if (pcbNeeded) needed = *pcbNeeded;
+        /* HeapReAlloc return NULL, when bufferW was NULL */
+        bufferW = (bufferW) ? HeapReAlloc(GetProcessHeap(), 0, bufferW, needed) :
+                              HeapAlloc(GetProcessHeap(), 0, needed);
 
-    r = RegOpenKeyA( HKEY_LOCAL_MACHINE, szPrinterPortKey, &hkey_printer);
-    if ( r == ERROR_SUCCESS )
-    {
-        RegQueryInfoKeyA( hkey_printer, NULL, NULL, NULL, NULL, NULL, NULL,
-	    &printer_count, NULL, NULL, NULL, NULL);
+        /* Try again with the large Buffer */
+        res = EnumPortsW(nameW, Level, bufferW, needed, pcbNeeded, pcReturned);
     }
-    count = serial_count + printer_count;
+    needed = pcbNeeded ? *pcbNeeded : 0;
+    numentries = pcReturned ? *pcReturned : 0;
 
-    /* then fill in the structure info structure once
-       we know the offset to the first string */
+    /*
+       W2k require the buffersize from EnumPortsW also for EnumPortsA.
+       We use the smaller Ansi-Size to avoid conflicts with fixed Buffers of old Apps.
+     */
+    if (res) {
+        /* EnumPortsW collected all Data. Parse them to caclulate ANSI-Size */
+        DWORD   entrysize = 0;
+        DWORD   index;
+        LPSTR   ptr;
+        LPPORT_INFO_2W pi2w;
+        LPPORT_INFO_2A pi2a;
 
-    memset( buffer, 0, bufsize );
-    n = 0;
-    ofs = info_size*count; 
-    for ( i=0; i<count; i++)
-    {
-        DWORD vallen = sizeof(portname) - 1;
+        needed = 0;
+        entrysize = (Level == 1) ? sizeof(PORT_INFO_1A) : sizeof(PORT_INFO_2A);
 
-        /* get the serial port values, then the printer values */
-        if ( i < serial_count )
-        {
-            strcpy( portname, "COMx:" );
-            portname[3] = '1' + i;
-            if (!WINSPOOL_ComPortExists( portname ))
-                continue;
+        /* First pass: calculate the size for all Entries */
+        pi2w = (LPPORT_INFO_2W) bufferW;
+        pi2a = (LPPORT_INFO_2A) pPorts;
+        index = 0;
+        while (index < numentries) {
+            index++;
+            needed += entrysize;    /* PORT_INFO_?A */
+            TRACE("%p: parsing #%d (%s)\n", pi2w, index, debugstr_w(pi2w->pPortName));
 
-            TRACE("Found %s\n", portname );
-            vallen = strlen( portname );
+            needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
+                                            NULL, 0, NULL, NULL);
+            if (Level > 1) {
+                needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
+                                                NULL, 0, NULL, NULL);
+                needed += WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
+                                                NULL, 0, NULL, NULL);
+            }
+            /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
+            pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
+            pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
         }
-        else
-        {
-            r = RegEnumValueA( hkey_printer, i-serial_count, 
-                     portname, &vallen, NULL, NULL, NULL, 0 );
-            if ( r )
-                continue;
+
+        /* check for errors and quit on failure */
+        if (cbBuf < needed) {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            res = FALSE;
+            goto cleanup;
         }
+        len = entrysize * numentries;       /* room for all PORT_INFO_?A */
+        ptr = (LPSTR) &pPorts[len];         /* room for strings */
+        cbBuf -= len ;                      /* free Bytes in the user-Buffer */
+        pi2w = (LPPORT_INFO_2W) bufferW;
+        pi2a = (LPPORT_INFO_2A) pPorts;
+        index = 0;
+        /* Second Pass: Fill the User Buffer (if we have one) */
+        while ((index < numentries) && pPorts) {
+            index++;
+            TRACE("%p: writing PORT_INFO_%dA #%d\n", pi2a, Level, index);
+            pi2a->pPortName = ptr;
+            len = WideCharToMultiByte(CP_ACP, 0, pi2w->pPortName, -1,
+                                            ptr, cbBuf , NULL, NULL);
+            ptr += len;
+            cbBuf -= len;
+            if (Level > 1) {
+                pi2a->pMonitorName = ptr;
+                len = WideCharToMultiByte(CP_ACP, 0, pi2w->pMonitorName, -1,
+                                            ptr, cbBuf, NULL, NULL);
+                ptr += len;
+                cbBuf -= len;
 
-        /* add a colon if necessary, and make it upper case */
-        CharUpperBuffA(portname,vallen);
-        if (strcasecmp(portname,"nul")!=0)
-            if (vallen && (portname[vallen-1] != ':') )
-                lstrcatA(portname,":");
+                pi2a->pDescription = ptr;
+                len = WideCharToMultiByte(CP_ACP, 0, pi2w->pDescription, -1,
+                                            ptr, cbBuf, NULL, NULL);
+                ptr += len;
+                cbBuf -= len;
 
-        /* add the port info structure if we can fit it */
-        if ( info_size*(n+1) < bufsize )
-        {
-            if ( level == 1)
-            {
-                PORT_INFO_1A *info = (PORT_INFO_1A*) &buffer[info_size*n];
-                info->pName = (LPSTR) &buffer[ofs];
-            }
-            else if ( level == 2)
-            {
-                PORT_INFO_2A *info = (PORT_INFO_2A*) &buffer[info_size*n];
-                info->pPortName = (LPSTR) &buffer[ofs];
-                /* FIXME: fill in more stuff here */
-                info->pMonitorName = PortMonitor;
-                info->pDescription = PortDescription;
-                info->fPortType = PORT_TYPE_WRITE|PORT_TYPE_READ;
+                pi2a->fPortType = pi2w->fPortType;
+                pi2a->Reserved = 0;              /* documented: "must be zero" */
+                
             }
-
-            /* add the name of the port if we can fit it */
-            if ( ofs < bufsize )
-                lstrcpynA((LPSTR)&buffer[ofs],portname,bufsize - ofs);
-
-            n++;
+            /* use LPBYTE with entrysize to avoid double code (PORT_INFO_1 + PORT_INFO_2) */
+            pi2w = (LPPORT_INFO_2W) (((LPBYTE)pi2w) + entrysize);
+            pi2a = (LPPORT_INFO_2A) (((LPBYTE)pi2a) + entrysize);
         }
-        else
-            retval = FALSE;
-        ofs += lstrlenA(portname)+1;
     }
 
-    RegCloseKey(hkey_printer);
+cleanup:
+    if (pcbNeeded)  *pcbNeeded = needed;
+    if (pcReturned) *pcReturned = (res) ? numentries : 0;
 
-    if(bufneeded)
-        *bufneeded = ofs;
+    HeapFree(GetProcessHeap(), 0, nameW);
+    HeapFree(GetProcessHeap(), 0, bufferW);
+
+    TRACE("returning %d with %d (%d byte for %d of %d entries)\n", 
+            (res), GetLastError(), needed, (res)? numentries : 0, numentries);
 
-    if(bufreturned)
-        *bufreturned = n;
+    return (res);
 
-    return retval;
 }
 
 /******************************************************************************
-- 
1.4.1



More information about the wine-patches mailing list