winspool: Implement EnumPortsW.
This commit is contained in:
parent
0bd336a573
commit
412acdeb79
|
@ -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, ®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_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|
Loading…
Reference in New Issue