winspool: Implement EnumPortsW.

This commit is contained in:
Detlef Riekenberg 2006-11-04 00:27:16 +01:00 committed by Alexandre Julliard
parent 0bd336a573
commit 412acdeb79
1 changed files with 213 additions and 8 deletions

View File

@ -98,6 +98,10 @@ typedef struct {
HMODULE hdll; HMODULE hdll;
DWORD refcount; DWORD refcount;
DWORD dwMonitorSize; 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; } monitor_t;
typedef struct { typedef struct {
@ -862,6 +866,26 @@ static void monitor_unload(monitor_t * pm)
LeaveCriticalSection(&monitor_handles_cs); LeaveCriticalSection(&monitor_handles_cs);
} }
/******************************************************************
* 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] * monitor_load [internal]
* *
@ -1013,6 +1037,134 @@ cleanup:
return pm; return pm;
} }
/******************************************************************
* 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, &registered, 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_opened_printer_entry
* Get the first place empty in the opened printer table * Get the first place empty in the opened printer table
@ -4685,16 +4837,69 @@ BOOL WINAPI EnumPortsA(LPSTR name,DWORD level,LPBYTE buffer,DWORD bufsize,
* Success: TRUE * Success: TRUE
* Failure: FALSE and in bufneeded the Bytes required for buffer, if bufsize is too small * 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", DWORD needed = 0;
debugstr_w(name),level,buffer,bufsize,bufneeded,bufreturned); DWORD numentries = 0;
return FALSE; 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);
} }
/****************************************************************************** /******************************************************************************