Detlef Riekenberg : winspool: Implement EnumPortsW.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Nov 6 08:48:49 CST 2006
Module: wine
Branch: master
Commit: 412acdeb79d4731b62fea9699510954c25042fd2
URL: http://source.winehq.org/git/wine.git/?a=commit;h=412acdeb79d4731b62fea9699510954c25042fd2
Author: Detlef Riekenberg <wine.dev at web.de>
Date: Sat Nov 4 00:27:16 2006 +0100
winspool: Implement EnumPortsW.
---
dlls/winspool.drv/info.c | 221 ++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 213 insertions(+), 8 deletions(-)
diff --git a/dlls/winspool.drv/info.c b/dlls/winspool.drv/info.c
index 735662b..9f2f236 100644
--- a/dlls/winspool.drv/info.c
+++ b/dlls/winspool.drv/info.c
@@ -98,6 +98,10 @@ typedef struct {
HMODULE hdll;
DWORD refcount;
DWORD dwMonitorSize;
+ LPPORT_INFO_2W cache; /* cached PORT_INFO_2W data */
+ DWORD pi1_needed; /* size for PORT_INFO_1W */
+ DWORD pi2_needed; /* size for PORT_INFO_2W */
+ DWORD returned; /* number of cached PORT_INFO_2W - entries */
} monitor_t;
typedef struct {
@@ -863,6 +867,26 @@ static void monitor_unload(monitor_t * p
}
/******************************************************************
+ * monitor_unloadall [internal]
+ *
+ * release all printmonitors and unload them from memory, when needed
+ */
+
+static void monitor_unloadall(void)
+{
+ monitor_t * pm;
+ monitor_t * next;
+
+ EnterCriticalSection(&monitor_handles_cs);
+ /* iterate through the list, with safety against removal */
+ LIST_FOR_EACH_ENTRY_SAFE(pm, next, &monitor_handles, monitor_t, entry)
+ {
+ monitor_unload(pm);
+ }
+ LeaveCriticalSection(&monitor_handles_cs);
+}
+
+/******************************************************************
* monitor_load [internal]
*
* load a printmonitor, get the dllname from the registry, when needed
@@ -1014,6 +1038,134 @@ cleanup:
}
/******************************************************************
+ * monitor_loadall [internal]
+ *
+ * Load all registered monitors
+ *
+ */
+static DWORD monitor_loadall(void)
+{
+ monitor_t * pm;
+ DWORD registered = 0;
+ DWORD loaded = 0;
+ HKEY hmonitors;
+ WCHAR buffer[MAX_PATH];
+ DWORD id = 0;
+
+ if (RegOpenKeyW(HKEY_LOCAL_MACHINE, MonitorsW, &hmonitors) == ERROR_SUCCESS) {
+ RegQueryInfoKeyW(hmonitors, NULL, NULL, NULL, ®istered, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+
+ TRACE("%d monitors registered\n", registered);
+
+ EnterCriticalSection(&monitor_handles_cs);
+ while (id < registered) {
+ buffer[0] = '\0';
+ RegEnumKeyW(hmonitors, id, buffer, MAX_PATH);
+ pm = monitor_load(buffer, NULL);
+ if (pm) loaded++;
+ id++;
+ }
+ LeaveCriticalSection(&monitor_handles_cs);
+ RegCloseKey(hmonitors);
+ }
+ TRACE("%d monitors loaded\n", loaded);
+ return loaded;
+}
+
+/******************************************************************
+ * enumerate the local Ports from all loaded monitors (internal)
+ *
+ * returns the needed size (in bytes) for pPorts
+ * and *lpreturned is set to number of entries returned in pPorts
+ *
+ */
+static DWORD get_ports_from_all_monitors(DWORD level, LPBYTE pPorts, DWORD cbBuf, LPDWORD lpreturned)
+{
+ monitor_t * pm;
+ LPWSTR ptr;
+ LPPORT_INFO_2W cache;
+ LPPORT_INFO_2W out;
+ DWORD res;
+ DWORD cacheindex;
+ DWORD outindex = 0;
+ DWORD needed = 0;
+ DWORD numentries;
+ DWORD entrysize;
+
+
+ TRACE("(%d, %p, %d, %p)\n", level, pPorts, cbBuf, lpreturned);
+ entrysize = (level == 1) ? sizeof(PORT_INFO_1W) : sizeof(PORT_INFO_2W);
+
+ numentries = *lpreturned; /* this is 0, when we scan the registry */
+ needed = entrysize * numentries;
+ ptr = (LPWSTR) &pPorts[needed];
+
+ numentries = 0;
+ needed = 0;
+
+ LIST_FOR_EACH_ENTRY(pm, &monitor_handles, monitor_t, entry)
+ {
+ if ((pm->monitor) && (pm->monitor->pfnEnumPorts)) {
+ if (pm->cache == NULL) {
+ res = pm->monitor->pfnEnumPorts(NULL, 2, NULL, 0, &(pm->pi2_needed), &(pm->returned));
+ if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
+ pm->cache = HeapAlloc(GetProcessHeap(), 0, (pm->pi2_needed));
+ res = pm->monitor->pfnEnumPorts(NULL, 2, (LPBYTE) pm->cache, pm->pi2_needed, &(pm->pi2_needed), &(pm->returned));
+ }
+ TRACE("(%s) got %d with %d (cache need %d byte for %d entries)\n",
+ debugstr_w(pm->name), res, GetLastError(), pm->pi2_needed, pm->returned);
+ res = FALSE;
+ }
+ if (pm->cache && (level == 1) && (pm->pi1_needed == 0) && (pm->returned > 0)) {
+ cacheindex = 0;
+ cache = pm->cache;
+ while (cacheindex < (pm->returned)) {
+ pm->pi1_needed += sizeof(PORT_INFO_1W);
+ pm->pi1_needed += (lstrlenW(cache->pPortName) + 1) * sizeof(WCHAR);
+ cache++;
+ cacheindex++;
+ }
+ TRACE("%d byte for %d cached PORT_INFO_1W entries (%s)\n",
+ pm->pi1_needed, cacheindex, debugstr_w(pm->name));
+ }
+ numentries += pm->returned;
+ needed += (level == 1) ? pm->pi1_needed : pm->pi2_needed;
+
+ /* fill the buffer, if we have one */
+ if (pPorts && (cbBuf >= needed )) {
+ cacheindex = 0;
+ cache = pm->cache;
+ while (cacheindex < pm->returned) {
+ out = (LPPORT_INFO_2W) &pPorts[outindex * entrysize];
+ out->pPortName = ptr;
+ lstrcpyW(ptr, cache->pPortName);
+ ptr += (lstrlenW(ptr)+1);
+ if (level > 1) {
+ out->pMonitorName = ptr;
+ lstrcpyW(ptr, cache->pMonitorName);
+ ptr += (lstrlenW(ptr)+1);
+
+ out->pDescription = ptr;
+ lstrcpyW(ptr, cache->pDescription);
+ ptr += (lstrlenW(ptr)+1);
+ out->fPortType = cache->fPortType;
+ out->Reserved = cache->Reserved;
+ }
+ cache++;
+ cacheindex++;
+ outindex++;
+ }
+ }
+ }
+ }
+
+ *lpreturned = numentries;
+ TRACE("need %d byte for %d entries\n", needed, numentries);
+ return needed;
+}
+
+/******************************************************************
* get_opened_printer_entry
* Get the first place empty in the opened printer table
*
@@ -4685,16 +4837,69 @@ BOOL WINAPI EnumPortsA(LPSTR name,DWORD
* Success: TRUE
* Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small
*
- * BUGS
- * UNICODE-Version is a stub
- *
*/
-BOOL WINAPI EnumPortsW(LPWSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
- LPDWORD bufneeded,LPDWORD bufreturned)
+
+BOOL WINAPI EnumPortsW(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
{
- FIXME("(%s,%d,%p,%d,%p,%p) - stub\n",
- debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned);
- return FALSE;
+ DWORD needed = 0;
+ DWORD numentries = 0;
+ BOOL res = FALSE;
+
+ TRACE("(%s, %d, %p, %d, %p, %p)\n", debugstr_w(pName), Level, pPorts,
+ cbBuf, pcbNeeded, pcReturned);
+
+ if (pName && (pName[0])) {
+ FIXME("not implemented for Server %s\n", debugstr_w(pName));
+ SetLastError(ERROR_ACCESS_DENIED);
+ goto emP_cleanup;
+ }
+
+ /* Level is not checked in win9x */
+ if (!Level || (Level > 2)) {
+ WARN("level (%d) is ignored in win9x\n", Level);
+ SetLastError(ERROR_INVALID_LEVEL);
+ goto emP_cleanup;
+ }
+ if (!pcbNeeded) {
+ SetLastError(RPC_X_NULL_REF_POINTER);
+ goto emP_cleanup;
+ }
+
+ EnterCriticalSection(&monitor_handles_cs);
+ monitor_loadall();
+
+ /* Scan all local Ports */
+ numentries = 0;
+ needed = get_ports_from_all_monitors(Level, NULL, 0, &numentries);
+
+ /* we calculated the needed buffersize. now do the error-checks */
+ if (cbBuf < needed) {
+ monitor_unloadall();
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto emP_cleanup_cs;
+ }
+ else if (!pPorts || !pcReturned) {
+ monitor_unloadall();
+ SetLastError(RPC_X_NULL_REF_POINTER);
+ goto emP_cleanup_cs;
+ }
+
+ /* Fill the Buffer */
+ needed = get_ports_from_all_monitors(Level, pPorts, cbBuf, &numentries);
+ res = TRUE;
+ monitor_unloadall();
+
+emP_cleanup_cs:
+ LeaveCriticalSection(&monitor_handles_cs);
+
+emP_cleanup:
+ if (pcbNeeded) *pcbNeeded = needed;
+ if (pcReturned) *pcReturned = (res) ? numentries : 0;
+
+ TRACE("returning %d with %d (%d byte for %d of %d entries)\n",
+ (res), GetLastError(), needed, (res)? numentries : 0, numentries);
+
+ return (res);
}
/******************************************************************************
More information about the wine-cvs
mailing list