You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1160 lines
39 KiB
1160 lines
39 KiB
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <winspool.h>
|
|
//#include <wchar.h>
|
|
#include <setupapi.h>
|
|
//#include <stdlib.h>
|
|
#include "enumports.h"
|
|
#include "usbmon.h"
|
|
|
|
void vOldAddItemToPortList(PUSBMON_PORT_INFO *pHead,PUSBMON_PORT_INFO pNew);
|
|
PUSBMON_PRINTER_INFO pOldGetPrinterList();
|
|
LONG UpdateAssociations(PUSBMON_PORT_INFO *ppPortList,PUSBMON_PRINTER_INFO pPrinterList);
|
|
LONG AllocateNewPorts(PUSBMON_PORT_INFO *ppPortList,PUSBMON_PRINTER_INFO pPrinterList);
|
|
LONG DoBestEffortMatches(PUSBMON_PORT_INFO pPortList,PUSBMON_PRINTER_INFO pPrinterList);
|
|
LONG ReattachExactMatches(PUSBMON_PORT_INFO pPortList,PUSBMON_PRINTER_INFO pPrinterList);
|
|
//void InitPortBits(PUSBMON_PORT_INFO pPortList);
|
|
//PUSBMON_PORT_INFO pGetNewPortNode(PUSBMON_PORT_INFO *ppListHead);
|
|
LONG WriteNewAssociations(int *iNumberOfPorts,PUSBMON_PORT_INFO pPortList,HKEY hPortRoot);
|
|
void FreePrinterList(PUSBMON_PRINTER_INFO pPrinterList);
|
|
LONG BuildReturnTable(int iNumberOfPorts,PUSBMON_PORT_INFO pPortList,DWORD Level,LPBYTE Ports,DWORD cBuf,LPDWORD pcbNeeded,LPDWORD pcReturned);
|
|
char szDebugBuff[512];
|
|
char *WtoA(WCHAR *pInString);
|
|
long lAddPrinterToList(PUSBMON_PORT_INFO *ppHead,HDEVINFO hDeviceList,PSP_DEVICE_INTERFACE_DATA prDeviceInfo,PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceDetail,PUSBMON_BASENAME *ppBaseNames);
|
|
int iCountPresentPrinters(PUSBMON_PORT_INFO pHead);
|
|
LONG lGetPrintersAndPorts(PUSBMON_PORT_INFO *ppHead,PUSBMON_BASENAME *);
|
|
LONG lGetQueues(PUSBMON_QUEUE_INFO *ppQueueList,PUSBMON_BASENAME pBaseNames);
|
|
LONG lAddQueueToList(LPWSTR pPortName,LPWSTR pPrinterName,PUSBMON_QUEUE_INFO *ppQueueHead);
|
|
void vDestroyQueueList(PUSBMON_QUEUE_INFO pQueueList);
|
|
void vCleanUpQueuesAndPorts(PUSBMON_PORT_INFO * pPortInfo,int iNumberOfPorts,PUSBMON_BASENAME pBaseNames);
|
|
DWORD WINAPI CleanupThread(LPVOID pParam);
|
|
void vEliminateOldQueuesAndPorts(PUSBMON_QUEUE_INFO pQueueInfo,PUSBMON_PORT_INFO * fpPortInfo);
|
|
void vDeletePort(PUSBMON_PORT_INFO pPort, HDEVINFO hDeviceList);
|
|
void vGreyOutQueue(PUSBMON_QUEUE_INFO pQueue);
|
|
void vUnGreyQueue(PUSBMON_QUEUE_INFO pQueue);
|
|
HANDLE hGetPortRegKey(PUSBMON_PORT_INFO pPort, HDEVINFO hDeviceList);
|
|
void vAddNameToBaseNameList(PUSBMON_BASENAME *ppBaseNames,WCHAR *wcPortBaseName);
|
|
BOOL bCheckPortName(LPTSTR pPortName,PUSBMON_BASENAME pBaseNames);
|
|
int iGetNumberOfPorts(PUSBMON_PORT_INFO pHead);
|
|
|
|
|
|
int iCleanupThreads=0;
|
|
HKEY hPortsKeyG; //global
|
|
PUSBMON_PORT_INFO pPortInfoG=NULL;
|
|
int iLastPrintersHere=-1;
|
|
|
|
|
|
|
|
typedef struct CLEANUP_THREAD_PARAMS_DEF
|
|
{
|
|
PUSBMON_PORT_INFO * ppPortInfo;
|
|
PUSBMON_BASENAME pBaseNames;
|
|
int iPortCount;
|
|
HANDLE hSemaphore;
|
|
} CLEANUP_THREAD_PARAMS,*PCLEANUP_THREAD_PARAMS;
|
|
|
|
|
|
|
|
BOOL WINAPI USBMON_EnumPorts(LPWSTR pName, DWORD Level, LPBYTE pPorts, DWORD cbBuf,LPDWORD pcbNeeded, LPDWORD pcReturned)
|
|
{
|
|
PUSBMON_PRINTER_INFO pPrinterList;
|
|
LONG lResult;
|
|
DWORD dwStatus;
|
|
int iNumberOfPorts;
|
|
static int iOldNumberOfPorts=0;
|
|
static int iNumCalls=0;
|
|
int iThisCall;
|
|
int iPrintersHere;
|
|
|
|
|
|
OutputDebugStringD2("USBMON ++=Head of EnumPorts, before WaitForSingleObject\n");
|
|
iThisCall=++iNumCalls;
|
|
wsprintfA(szDebugBuff,"USBMON: +++++++++++++++++++++++++++++++++++++++++++++++++EnumPorts call # %d, handle = %x\n",iThisCall,hMonitorSemaphore);
|
|
OutputDebugStringD2(szDebugBuff);
|
|
dwStatus=WaitForSingleObject(hMonitorSemaphore,INFINITE);
|
|
if(dwStatus==WAIT_FAILED)
|
|
{
|
|
OutputDebugStringD1("USBMON: WaitForSingleObject failed!\n");
|
|
}
|
|
wsprintfA(szDebugBuff,"USBMON Head of EnumPrts, ++++++++++++++++++++++++++++++++++++ Instance # %d, after WaitForSingleObject, return code=%d\n",iThisCall,dwStatus);
|
|
OutputDebugStringD2(szDebugBuff);
|
|
|
|
|
|
lResult=lGetPrintersAndPorts(&pPortInfoG,&GpBaseNameList);
|
|
iNumberOfPorts=iGetNumberOfPorts(pPortInfoG);
|
|
|
|
if(iCleanupThreads==0)
|
|
{
|
|
iPrintersHere=iCountPresentPrinters(pPortInfoG);
|
|
if(iPrintersHere!=iLastPrintersHere)
|
|
{
|
|
iLastPrintersHere=iPrintersHere;
|
|
iCleanupThreads++;
|
|
OutputDebugStringD3("USBMON: About to clean up queues and ports\n");
|
|
|
|
vCleanUpQueuesAndPorts(&pPortInfoG,iNumberOfPorts,GpBaseNameList);
|
|
|
|
} //end printer count changed
|
|
}
|
|
|
|
|
|
lResult=BuildReturnTable(iNumberOfPorts,pPortInfoG,Level,pPorts,cbBuf,pcbNeeded,pcReturned);
|
|
|
|
if(lResult!=ERROR_SUCCESS)
|
|
{
|
|
OutputDebugStringD2("USBMON: Unable to build return buffer (this is normal for first call)\n");
|
|
goto EnumPortsError;
|
|
}
|
|
|
|
OutputDebugStringD3("USBMON tail of EnumPorts, before ReleaseSemaphore\n");
|
|
|
|
ReleaseSemaphore(hMonitorSemaphore,1,NULL);
|
|
return TRUE;
|
|
EnumPortsError:
|
|
wsprintfA(szDebugBuff,"USBMON tail of EnumPorts, error path, before ReleaseSemaphore, *pcbNeeded=%d\n",*pcbNeeded);
|
|
OutputDebugStringD3(szDebugBuff);
|
|
|
|
|
|
if(!ReleaseSemaphore(hMonitorSemaphore,1,NULL))
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: EnumPorts Release sempahore failed for instance %d \n",iThisCall);
|
|
OutputDebugStringD1(szDebugBuff);
|
|
}
|
|
else
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: EnumPortsRelease sempahore succeeded for instance %d \n",iThisCall);
|
|
OutputDebugStringD2(szDebugBuff);
|
|
}
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
} /*End EnumPorts*/
|
|
|
|
|
|
int iGetNumberOfPorts(PUSBMON_PORT_INFO pHead)
|
|
{
|
|
PUSBMON_PORT_INFO pWalk;
|
|
int iCount=0;
|
|
|
|
pWalk=pHead;
|
|
while(pWalk!=NULL)
|
|
{
|
|
iCount++;
|
|
pWalk=pWalk->pNext;
|
|
}/*end while*/
|
|
return iCount;
|
|
} /*end function iGetNumberOfPorts*/
|
|
|
|
/***********************************
|
|
* lGetQueues
|
|
*
|
|
* This function builds a linked list of print queues
|
|
* who's port names start with a registered basename.
|
|
*
|
|
* This list is used to grey out queues who's printers are
|
|
* Unavailable, and to delete ports who's printers are gone
|
|
************************************************************/
|
|
LONG lGetQueues(PUSBMON_QUEUE_INFO *ppQueueList,PUSBMON_BASENAME pBaseNames)
|
|
{
|
|
DWORD dwBufferSize=1024;
|
|
DWORD dwBufferNeeded=0;
|
|
DWORD dwNumStructs;
|
|
LPBYTE lpBuffer;
|
|
BOOL bStatus;
|
|
DWORD dwLoop;
|
|
PRINTER_INFO_5 *pEnumInfo;
|
|
LONG lStatus;
|
|
|
|
OutputDebugStringD2("USBMON: Head of lGetQueues \n");
|
|
lpBuffer=(LPBYTE)GlobalAlloc(0,dwBufferSize);
|
|
if(lpBuffer==NULL)
|
|
{
|
|
OutputDebugStringD1("USBMON: Unable to allocate memory in lGetQueues\n");
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
OutputDebugStringD3("USBMON: Before EnumPrinters \n");
|
|
|
|
bStatus=EnumPrinters(PRINTER_ENUM_LOCAL,NULL,5,lpBuffer,dwBufferSize,&dwBufferNeeded,&dwNumStructs);
|
|
|
|
OutputDebugStringD3("USBMON: After EnumPrinters \n");
|
|
if(dwBufferNeeded>dwBufferSize)
|
|
{
|
|
dwBufferSize=dwBufferNeeded;
|
|
lpBuffer=GlobalReAlloc(lpBuffer,dwBufferSize,0);
|
|
if(lpBuffer==NULL)
|
|
{
|
|
OutputDebugStringD1("USBMON: Unable to re-allocate memory in lGetQueues\n");
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
OutputDebugStringD3("USBMON: Before EnumPrinters2 \n");
|
|
bStatus=EnumPrinters(PRINTER_ENUM_LOCAL,NULL,5,lpBuffer,dwBufferSize,&dwBufferNeeded,&dwNumStructs);
|
|
OutputDebugStringD3("USBMON: After EnumPrinters2 \n");
|
|
}
|
|
if(bStatus==FALSE)
|
|
{
|
|
OutputDebugStringD1("USBMON: lGetQueues: EnumPrinters failed\n");
|
|
return GetLastError();
|
|
}
|
|
OutputDebugStringD3("USBMON: lGetQueues: Before for loop \n");
|
|
pEnumInfo=(PRINTER_INFO_5 *)lpBuffer;
|
|
for(dwLoop=0;dwLoop<dwNumStructs;dwLoop++)
|
|
{
|
|
OutputDebugStringD3("USBMON: lGetQueues: Head of for loop \n");
|
|
if(pEnumInfo->pPortName!=NULL)
|
|
{
|
|
OutputDebugStringD2("USBMON: lGetQueues: Valid port name \n");
|
|
// if(wcsncmp(pEnumInfo->pPortName,PORT_NAME_BASE,wcslen(PORT_NAME_BASE))==0)
|
|
if(bCheckPortName(pEnumInfo->pPortName,pBaseNames))
|
|
{
|
|
OutputDebugStringD3("USBMON: lGetQueues: Valid port name, that starts with registered base name, add it to list \n");
|
|
lStatus=lAddQueueToList(pEnumInfo->pPortName,pEnumInfo->pPrinterName,ppQueueList);
|
|
if(lStatus!=ERROR_SUCCESS)
|
|
{
|
|
GlobalFree(lpBuffer);
|
|
return lStatus;
|
|
}
|
|
} /*end if found a USB print queue*/
|
|
} /*end if pPortName not NULL*/
|
|
pEnumInfo++;
|
|
} /*end for loop*/
|
|
GlobalFree(lpBuffer);
|
|
return ERROR_SUCCESS;
|
|
} /*end function lGetQueues*/
|
|
|
|
|
|
|
|
BOOL bCheckPortName(LPTSTR pPortName,PUSBMON_BASENAME pBaseNames)
|
|
{
|
|
BOOL bFound=FALSE;
|
|
PUSBMON_BASENAME pWalk;
|
|
|
|
OutputDebugStringD3("USBMON: Head of bCheckPortName\n");
|
|
pWalk=pBaseNames;
|
|
while((pWalk!=NULL)&&(!bFound))
|
|
{
|
|
|
|
wsprintf((WCHAR *)szDebugBuff,L"USBMON: PortBaseName==%s\n",pWalk->wcBaseName);
|
|
OutputDebugStringWD3((WCHAR *)szDebugBuff);
|
|
|
|
if(wcsncmp(pPortName,pWalk->wcBaseName,wcslen(pWalk->wcBaseName))==0)
|
|
{
|
|
bFound=TRUE;
|
|
}
|
|
else
|
|
{
|
|
pWalk=pWalk->pNext;
|
|
}
|
|
} /*end while not found*/
|
|
return bFound;
|
|
} /*end function bCheckPortName*/
|
|
|
|
|
|
|
|
|
|
|
|
LONG lAddQueueToList(LPWSTR pPortName,LPWSTR pPrinterName,PUSBMON_QUEUE_INFO *ppQueueHead)
|
|
{
|
|
PUSBMON_QUEUE_INFO pNew,pWalk;
|
|
BOOL bFound;
|
|
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON: Head of lAddQueueToList, about to add queue with port %s\n",pPortName);
|
|
OutputDebugStringWD3((WCHAR *)szDebugBuff);
|
|
|
|
|
|
pNew=(PUSBMON_QUEUE_INFO)GlobalAlloc(0,sizeof(USBMON_QUEUE_INFO));
|
|
if(pNew==NULL)
|
|
{
|
|
OutputDebugStringD1("USBMON: vAddQueueToList, Out of memory\n");
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
wcscpy(pNew->wcPortName,pPortName);
|
|
if(pPrinterName!=NULL)
|
|
wcscpy(pNew->wcPrinterName,pPrinterName);
|
|
else
|
|
pNew->wcPrinterName[0]=L'\0';
|
|
|
|
if(*ppQueueHead==NULL)
|
|
{
|
|
*ppQueueHead=pNew;
|
|
pNew->pNext=NULL;
|
|
}
|
|
else if(lstrcmp(pNew->wcPortName,(*ppQueueHead)->wcPortName)<0)
|
|
{
|
|
pNew->pNext=*ppQueueHead;
|
|
*ppQueueHead=pNew;
|
|
}
|
|
else
|
|
{
|
|
pWalk=*ppQueueHead;
|
|
bFound=FALSE;
|
|
while((!bFound)&&(pWalk->pNext!=NULL))
|
|
{
|
|
if(lstrcmp(pNew->wcPortName,pWalk->pNext->wcPortName)<0)
|
|
bFound=TRUE;
|
|
else
|
|
pWalk=pWalk->pNext;
|
|
}
|
|
pNew->pNext=pWalk->pNext;
|
|
pWalk->pNext=pNew;
|
|
} /*end else, we need to walk the list*/
|
|
return ERROR_SUCCESS;
|
|
} /*end function vAddQueueToList*/
|
|
|
|
void vDestroyQueueList(PUSBMON_QUEUE_INFO pQueueList)
|
|
{
|
|
PUSBMON_QUEUE_INFO pWalk,pLast;
|
|
|
|
pWalk=pQueueList;
|
|
while(pWalk!=NULL)
|
|
{
|
|
pLast=pWalk;
|
|
pWalk=pWalk->pNext;
|
|
GlobalFree(pLast);
|
|
} /*end while pWalk!=NULL*/
|
|
} /*end function vDestroyQueueList*/
|
|
|
|
|
|
|
|
LONG BuildReturnTable(int iNumberOfPorts, // Internal variable,
|
|
PUSBMON_PORT_INFO pPortList,// List of ports
|
|
DWORD Level, // IN specifies structure type to return
|
|
LPBYTE Ports, // OUT Buffer to write to
|
|
DWORD cBuf, // IN size of buffer provided
|
|
LPDWORD pcbNeeded, // OUT specifies bytes written to buffer, or the size the buffer should have been if it's to small
|
|
LPDWORD pcReturned) // OUT specifies the number of structures (ports) stored in the buffer
|
|
{
|
|
PORT_INFO_1 *pInfo1;
|
|
PORT_INFO_2 *pInfo2;
|
|
|
|
VOID *pNextStruct;
|
|
WCHAR *pszNextString;
|
|
|
|
|
|
int iNodeSize;
|
|
LONG lResult;
|
|
unsigned int iStringsSize;
|
|
unsigned int iStaticSize; //size of "overhead" strings that are only created once for all ports
|
|
|
|
unsigned int iAllStructsSize;
|
|
unsigned int iAllStringsSize;
|
|
unsigned int iTotalSize;
|
|
PUSBMON_PORT_INFO pPortWalk;
|
|
|
|
OutputDebugStringD2("USBMON: Head of BuildReturnTable\n");
|
|
wsprintfA(szDebugBuff,"USBMON: iNumberOfPorts==%d, iLevel=%d\n",iNumberOfPorts,Level);
|
|
OutputDebugStringD3(szDebugBuff);
|
|
if(Level==1)
|
|
{
|
|
iNodeSize=sizeof(PORT_INFO_1);
|
|
iStringsSize=MAX_PORT_LEN*2;
|
|
iStaticSize=0;
|
|
}
|
|
else if(Level==2)
|
|
{
|
|
iNodeSize=sizeof(PORT_INFO_2);
|
|
iStaticSize=(wcslen(MONITOR_NAME)+1)*2;
|
|
iStringsSize=(MAX_PORT_LEN*2)+(MAX_PORT_DESC_LEN*2)+iStaticSize;
|
|
|
|
}
|
|
else
|
|
{
|
|
OutputDebugStringD1("USBMON: Unsupported structure level in BuildReturnTable\n");
|
|
lResult=ERROR_INVALID_LEVEL;
|
|
goto BuildTableError;
|
|
} /*end else it's a level we don't support*/
|
|
iAllStructsSize=iNodeSize*iNumberOfPorts;
|
|
iAllStringsSize=iStringsSize*iNumberOfPorts;
|
|
iTotalSize=iAllStructsSize+iAllStringsSize;
|
|
wsprintfA(szDebugBuff,"USBMON: spooler gave us a %lu byte buffer at %X, we need a %lu byte buffer\n",cBuf,Ports,iTotalSize);
|
|
OutputDebugStringD3(szDebugBuff);
|
|
*pcbNeeded=iTotalSize;
|
|
if(iTotalSize>cBuf)
|
|
{
|
|
OutputDebugStringD3("USBMON: Buffer provided by spooler is not large enough\n");
|
|
lResult=ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
goto BuildTableError;
|
|
|
|
}
|
|
pNextStruct=(VOID *)Ports;
|
|
pszNextString=(WCHAR *)(Ports+cBuf-iAllStringsSize); //ports+cbuff == end of the buffer, - iAllStringsSize == start of the strings
|
|
// if(Level==2)
|
|
// {
|
|
// pszMonitorName=(WCHAR *)pszNextString;
|
|
// wcscpy(pszMonitorName,MONITOR_NAME);
|
|
// pszNextString+=(iStaticSize);
|
|
// }
|
|
pPortWalk=pPortList;
|
|
if(iNumberOfPorts>0)
|
|
while(pPortWalk!=NULL)
|
|
{
|
|
|
|
if(Level==1)
|
|
{
|
|
|
|
|
|
pInfo1=(PORT_INFO_1 *)pNextStruct;
|
|
pInfo1->pName=pszNextString; //crashing line
|
|
|
|
wcscpy((WCHAR *)(pInfo1->pName),pPortWalk->szPortName);
|
|
pszNextString+=(MAX_PORT_LEN);
|
|
|
|
|
|
|
|
} /*end if level == 1*/
|
|
else
|
|
{
|
|
OutputDebugStringD2("USBMON: Head of build PORT_INFO 2\n"); //yy
|
|
pInfo2=(PORT_INFO_2 *)pNextStruct;
|
|
pInfo2->pPortName=pszNextString;
|
|
wcscpy((WCHAR *)(pInfo2->pPortName),pPortWalk->szPortName);
|
|
pszNextString+=(MAX_PORT_LEN);
|
|
pInfo2->pDescription=pszNextString;
|
|
wcscpy((WCHAR *)(pInfo2->pDescription),pPortWalk->szPortDescription);
|
|
pszNextString+=MAX_PORT_DESC_LEN;
|
|
pInfo2->pMonitorName=pszNextString;
|
|
wcscpy((WCHAR *)(pInfo2->pMonitorName),MONITOR_NAME);
|
|
pszNextString+=(iStaticSize/2); //iStaticSize is bytes, pszNextString in WCHARs
|
|
pInfo2->Reserved=0;
|
|
pInfo2->fPortType=PORT_TYPE_WRITE;
|
|
wsprintfW((WCHAR *)szDebugBuff,L"pInfo2=0x%x\n",pInfo2);
|
|
OutputDebugStringWD3((WCHAR *)szDebugBuff);
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON in BuildBuff, PortName=%s|\n, Description=%s|\n, MonitorName=%s|\n",pInfo2->pPortName,pInfo2->pDescription,pInfo2->pMonitorName);
|
|
OutputDebugStringWD3((WCHAR *)szDebugBuff);
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON in BuildBuff, PortName=0x%x\n, Description=0x%x\n, MonitorName=0x%x\n",pInfo2->pPortName,pInfo2->pDescription,pInfo2->pMonitorName);
|
|
OutputDebugStringWD3((WCHAR *)szDebugBuff); //yy
|
|
|
|
} /*else level == 2*/
|
|
((PBYTE)pNextStruct)+=iNodeSize;
|
|
pPortWalk=pPortWalk->pNext;
|
|
} /*end while iLoop*/
|
|
*pcReturned=iNumberOfPorts;
|
|
return ERROR_SUCCESS;
|
|
BuildTableError:
|
|
return lResult;
|
|
} /*end function BuildReturnTable*/
|
|
|
|
|
|
void FreePrinterList(PUSBMON_PRINTER_INFO pPrinterList)
|
|
{
|
|
PUSBMON_PRINTER_INFO pWalk,pNext;
|
|
|
|
pWalk=pPrinterList;
|
|
while(pWalk!=NULL)
|
|
{
|
|
pNext=pWalk->pNext;
|
|
GlobalFree(pWalk);
|
|
pWalk=pNext;
|
|
}
|
|
} /*end function vFreePrinterList*/
|
|
|
|
|
|
int iCountPresentPrinters(PUSBMON_PORT_INFO pHead)
|
|
{
|
|
int iReturn=0;
|
|
PUSBMON_PORT_INFO pWalk;
|
|
pWalk=pHead;
|
|
OutputDebugStringD3("USBMON: ************************************* Head of iCountPresentPrinters\n");
|
|
while(pWalk!=NULL)
|
|
{
|
|
if((pWalk->dwDeviceFlags)&SPINT_ACTIVE)
|
|
iReturn++;
|
|
pWalk=pWalk->pNext;
|
|
}
|
|
return iReturn;
|
|
} /*end function iCountPrinters*/
|
|
|
|
|
|
/*******************************************************
|
|
* FUNCTION: pGetPrintersAndPorts
|
|
* Uses SetupDi calls to obtain list of USB printers
|
|
* present in the system, and reads the port name
|
|
* of the printer from the registry. This function
|
|
* replaces pGetPrinterList, UpdateAssociations,
|
|
* AllocateNewPorts, DoBestEffortMatches, and
|
|
* ReattachExactMatches
|
|
*
|
|
* This function is called initially with a null pointer
|
|
* And is then called again on each EnumPorts
|
|
* PARAMETERS:
|
|
* PUSBMON_PORT_INFO *ppHead
|
|
* Pointer to the head pointer of the list to by modified
|
|
* or Created
|
|
* RETURN:
|
|
* status code
|
|
********************************************************/
|
|
|
|
LONG lGetPrintersAndPorts(PUSBMON_PORT_INFO *ppHead,PUSBMON_BASENAME *ppBaseNames)
|
|
{
|
|
int iLoop;
|
|
LONG lStatus;
|
|
HDEVINFO hDeviceList;
|
|
SP_DEVICE_INTERFACE_DATA rDeviceInfo;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceDetail;
|
|
GUID *pPrinterGuid;
|
|
BOOL bMoreDevices;
|
|
DWORD dwRequiredSize;
|
|
PUSBMON_PRINTER_INFO pPrinterList=NULL,pNew;
|
|
HKEY hDeviceKey;
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
|
|
OutputDebugStringD2("USBMON: Head of pGetPrinterAndPortList\n");
|
|
pPrinterGuid=(GUID *)&USB_PRINTER_GUID;
|
|
OutputDebugStringD3("USBMON: before SetupDiGetClassDevs\n");
|
|
hDeviceList=SetupDiGetClassDevs(pPrinterGuid,NULL,NULL,DIGCF_INTERFACEDEVICE);
|
|
OutputDebugStringD3("USBMON: after SetupDiGetClassDevs\n");
|
|
|
|
|
|
if(hDeviceList==INVALID_HANDLE_VALUE)
|
|
{
|
|
dwError = GetLastError();
|
|
OutputDebugStringD1("USBMON: SetupDiGetClassDevs failed\n");
|
|
goto SetupDiPrinterAndPortError;
|
|
}
|
|
else
|
|
{
|
|
iLoop=0;
|
|
rDeviceInfo.cbSize=sizeof(rDeviceInfo);
|
|
bMoreDevices=SetupDiEnumDeviceInterfaces(hDeviceList,0,pPrinterGuid,iLoop,&rDeviceInfo);
|
|
wsprintfA(szDebugBuff,"USBMON: SetupDiEnumDeviceInterfaces, data.flags=%u\n",rDeviceInfo.Flags);
|
|
OutputDebugStringD3(szDebugBuff);
|
|
while(bMoreDevices)
|
|
{
|
|
if(!SetupDiGetDeviceInterfaceDetail(hDeviceList,&rDeviceInfo,NULL,0,&dwRequiredSize,NULL))
|
|
{
|
|
dwError=GetLastError();
|
|
wsprintfA(szDebugBuff,"USBMON: SetupDiGetDeviceInterfaceDetail first call failed, error=%x\n",dwError);
|
|
OutputDebugStringD3(szDebugBuff);
|
|
// goto SetupDiPrinterAndPortError; //the first call is just to get this size, so of course it should fail. Don't goto anywhere
|
|
}
|
|
pDeviceDetail=(PSP_DEVICE_INTERFACE_DETAIL_DATA)GlobalAlloc(0,dwRequiredSize);
|
|
if(pDeviceDetail==NULL)
|
|
{
|
|
OutputDebugStringD1("USBMON: Unable to allocate memory in pGetPrinterList\n");
|
|
SetupDiDestroyDeviceInfoList(hDeviceList);
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto SetupDiPrinterAndPortError;
|
|
}
|
|
pDeviceDetail->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
if(!SetupDiGetDeviceInterfaceDetail(hDeviceList,&rDeviceInfo,pDeviceDetail,dwRequiredSize,&dwRequiredSize,NULL))
|
|
{
|
|
dwError = GetLastError();
|
|
OutputDebugStringD1("USBMON: SetupDiGetDeviceInterfaceDetail (second call) failed\n");
|
|
SetupDiDestroyDeviceInfoList(hDeviceList);
|
|
goto SetupDiPrinterAndPortError;
|
|
}
|
|
else
|
|
OutputDebugStringD3("USBMON: SetupDiGetDeviceInterfaceDetail (second call) OK\n");
|
|
|
|
lStatus=lAddPrinterToList(ppHead,hDeviceList,&rDeviceInfo,pDeviceDetail,ppBaseNames);
|
|
GlobalFree(pDeviceDetail);
|
|
OutputDebugStringD3("USBMON: Before end of loop SetupDiEnumDeviceInterfaces\n"); //yy
|
|
bMoreDevices=SetupDiEnumDeviceInterfaces(hDeviceList,0,pPrinterGuid,++iLoop,&rDeviceInfo);
|
|
wsprintfA(szDebugBuff,"USBMON: SetupDiEnumDeviceInterfaces, data.flags=%u\n",rDeviceInfo.Flags);
|
|
OutputDebugStringD3(szDebugBuff);
|
|
|
|
} /*end while more devices*/
|
|
SetupDiDestroyDeviceInfoList(hDeviceList);
|
|
return STATUS_SUCCESS;
|
|
} /*end else*/
|
|
SetupDiPrinterAndPortError:;
|
|
if ( dwError == ERROR_SUCCESS )
|
|
dwError = ERROR_INVALID_DATA;
|
|
OutputDebugStringD1("USBMON: Erroring out of pGetPrinterList\n");
|
|
return dwError;
|
|
} /*end function lGetPrintersAndPorts*/
|
|
|
|
|
|
long lAddPrinterToList(PUSBMON_PORT_INFO *ppHead,HDEVINFO hDeviceList,SP_DEVICE_INTERFACE_DATA * prDeviceInfo,PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceDetail,PUSBMON_BASENAME *ppBaseNames)
|
|
{
|
|
PUSBMON_PORT_INFO pWalk,pTemp,pNew = NULL;
|
|
BOOL bFound=FALSE;
|
|
HANDLE hDeviceKey = INVALID_HANDLE_VALUE;
|
|
DWORD dwPortNumberSize;
|
|
WCHAR wcPortName[MAX_PORT_LEN+1];
|
|
WCHAR wcPortBaseName[MAX_PORT_LEN]; //arbitrary size, bigger than it needs to be
|
|
DWORD dwPortNumber,dwStringSize;
|
|
DWORD dwReturn = ERROR_SUCCESS;
|
|
int iResult;
|
|
|
|
pWalk=*ppHead;
|
|
while((pWalk!=NULL)&&(!bFound))
|
|
{
|
|
if(lstrcmp(pWalk->DevicePath,pDeviceDetail->DevicePath)==0)
|
|
bFound=TRUE;
|
|
else
|
|
pWalk=pWalk->pNext;
|
|
}
|
|
|
|
if(pWalk!=NULL) //it's not a new node
|
|
{
|
|
if((!((pWalk->dwDeviceFlags)&SPINT_ACTIVE)) && ((prDeviceInfo->Flags)&SPINT_ACTIVE)) //If we just became active
|
|
{
|
|
hDeviceKey=SetupDiOpenDeviceInterfaceRegKey(hDeviceList,prDeviceInfo,0,KEY_ALL_ACCESS);
|
|
if(hDeviceKey==INVALID_HANDLE_VALUE)
|
|
{
|
|
OutputDebugStringD1("USBMON: reactivation: SetupDiOpenDeviceInterfaceRegKey failed\n");
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
RegDeleteValue(hDeviceKey,L"recyclable");
|
|
dwStringSize = sizeof(pWalk->szPortDescription);
|
|
if(RegQueryValueEx(hDeviceKey,L"Port Description",0,NULL,(LPBYTE)(pWalk->szPortDescription),&dwStringSize)!=ERROR_SUCCESS)
|
|
{
|
|
OutputDebugStringD2("USBMON: RegQueryValueEx, get \"Port Description\" in lAddPrinterToList (refresh) failed, defaulting to \"Virtual printer port for USB\"\n");
|
|
wcscpy(pWalk->szPortDescription,L"Virtual printer port for USB");
|
|
}
|
|
|
|
RegCloseKey(hDeviceKey);
|
|
hDeviceKey=INVALID_HANDLE_VALUE;
|
|
} /*end if re-activated port*/
|
|
pWalk->dwDeviceFlags=prDeviceInfo->Flags; //even if we don't need to reload the whole device detail, we need to recheck the flags
|
|
}
|
|
else
|
|
{
|
|
pNew=GlobalAlloc(0,sizeof(USBMON_PORT_INFO));
|
|
if(pNew==NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
wcscpy(pNew->DevicePath,pDeviceDetail->DevicePath);
|
|
pNew->iRefCount=0;
|
|
hDeviceKey=SetupDiOpenDeviceInterfaceRegKey(hDeviceList,prDeviceInfo,0,KEY_ALL_ACCESS);
|
|
if(hDeviceKey==INVALID_HANDLE_VALUE)
|
|
{
|
|
dwReturn = GetLastError();
|
|
OutputDebugStringD1("USBMON: SetupDiOpenDeviceInterfaceRegKey failed\n");
|
|
goto Done;
|
|
}
|
|
dwPortNumberSize=sizeof(dwPortNumber);
|
|
dwReturn = RegQueryValueEx(hDeviceKey,L"Port Number",0,NULL,(LPBYTE)&dwPortNumber, &dwPortNumberSize);
|
|
if ( dwReturn != ERROR_SUCCESS )
|
|
{
|
|
OutputDebugStringD2("USBMON: RegQueryValueEx get \"Port Number\" in lAddPrinterToList failed\n");
|
|
goto Done;
|
|
}
|
|
dwStringSize=sizeof(wcPortBaseName);
|
|
if(RegQueryValueEx(hDeviceKey,L"Base Name",0,NULL,(LPBYTE)wcPortBaseName,&dwStringSize)!=ERROR_SUCCESS)
|
|
{
|
|
OutputDebugStringD2("USBMON: RegQueryValueEx, get \"Base Name\" in lAddPrinterToList failed, defaulting to USB\n");
|
|
wcscpy(wcPortBaseName,L"USB");
|
|
}
|
|
vAddNameToBaseNameList(ppBaseNames,wcPortBaseName);
|
|
dwStringSize=sizeof(pNew->szPortDescription);
|
|
dwReturn=RegQueryValueEx(hDeviceKey,L"Port Description",0,NULL,(LPBYTE)(pNew->szPortDescription),&dwStringSize);
|
|
|
|
if(dwReturn!=ERROR_SUCCESS)
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: RegQueryValueEx returned (signed) %d, (unsigned) %u\n",dwReturn,dwReturn);
|
|
OutputDebugStringD2(szDebugBuff);
|
|
|
|
OutputDebugStringD2("USBMON: *************************************************RegQueryValueEx, get \"Port Description\" in lAddPrinterToList failed, defaulting to \"Virtual printer port for USB\"\n");
|
|
wcscpy(pNew->szPortDescription,L"Virtual printer port for USB");
|
|
|
|
}
|
|
else
|
|
{
|
|
OutputDebugStringD2("USBMON: *****************************************RegQueryValueEx on baseName OK\n");
|
|
}
|
|
|
|
wsprintf(wcPortName,L"%s%03u",wcPortBaseName,dwPortNumber);
|
|
OutputDebugStringD3("USBMON: computed port name ==");
|
|
OutputDebugStringWD3(wcPortName);
|
|
wcscpy(pNew->szPortName,wcPortName);
|
|
pNew->dwDeviceFlags=prDeviceInfo->Flags;
|
|
if((pNew->dwDeviceFlags)&SPINT_ACTIVE)
|
|
RegDeleteValue(hDeviceKey,L"recyclable");
|
|
|
|
|
|
OutputDebugStringD3("USBMON: AddPrinterToList Start of insertion\n");
|
|
pWalk=*ppHead;
|
|
if(pWalk==NULL)
|
|
{
|
|
*ppHead=pNew;
|
|
pNew->pNext=NULL;
|
|
pNew = NULL;
|
|
}
|
|
else if(lstrcmp(pNew->szPortName,pWalk->szPortName)<0)
|
|
{
|
|
OutputDebugStringD3("USBMON: AddPrinterToList New Head\n");
|
|
pNew->pNext=*ppHead;
|
|
(*ppHead)=pNew;
|
|
pNew = NULL;
|
|
}
|
|
else if(lstrcmp(pNew->szPortName,pWalk->szPortName)==0)
|
|
{
|
|
pNew->pNext=(*ppHead)->pNext;
|
|
(*ppHead)=pNew;
|
|
GlobalFree(pWalk);
|
|
pNew = NULL;
|
|
}
|
|
else
|
|
{
|
|
if(pWalk->pNext!=NULL)
|
|
{
|
|
iResult=lstrcmp(pNew->szPortName,pWalk->pNext->szPortName);
|
|
}
|
|
while((iResult>0)&&(pWalk->pNext!=NULL))
|
|
{
|
|
pWalk=pWalk->pNext;
|
|
if(pWalk->pNext!=NULL)
|
|
{
|
|
iResult=lstrcmp(pNew->szPortName,pWalk->pNext->szPortName);
|
|
}
|
|
} /*end while*/
|
|
if(pWalk->pNext!=NULL)
|
|
if(iResult==0) //they match
|
|
{
|
|
pTemp=pWalk->pNext;
|
|
pWalk->pNext=pWalk->pNext->pNext;
|
|
GlobalFree(pTemp);
|
|
|
|
}
|
|
pNew->pNext=pWalk->pNext;
|
|
pWalk->pNext=pNew;
|
|
pNew = NULL;
|
|
} /*end else*/
|
|
} /*end else pWalk==NULL, therefore it's a new node*/
|
|
|
|
dwReturn = ERROR_SUCCESS;
|
|
Done:
|
|
if ( pNew )
|
|
GlobalFree(pNew);
|
|
|
|
if ( hDeviceKey != INVALID_HANDLE_VALUE )
|
|
RegCloseKey(hDeviceKey);
|
|
return dwReturn;
|
|
} /*end function lAddPrinterToList*/
|
|
|
|
|
|
void vAddNameToBaseNameList(PUSBMON_BASENAME *ppBaseNames,WCHAR *wcPortBaseName)
|
|
{
|
|
BOOL bFound;
|
|
PUSBMON_BASENAME pWalk,pNew;
|
|
|
|
pWalk=*ppBaseNames;
|
|
bFound=FALSE;
|
|
while((pWalk!=NULL)&&(!bFound))
|
|
{
|
|
if(wcscmp(pWalk->wcBaseName,wcPortBaseName)==0)
|
|
bFound=TRUE;
|
|
pWalk=pWalk->pNext;
|
|
} /*end while more items*/
|
|
if(!bFound)
|
|
{
|
|
pWalk=*ppBaseNames;
|
|
pNew=GlobalAlloc(0,sizeof(USBMON_BASENAME));
|
|
if(pNew==NULL)
|
|
return;
|
|
wcscpy(pNew->wcBaseName,wcPortBaseName);
|
|
if(*ppBaseNames==NULL)
|
|
{
|
|
*ppBaseNames=pNew;
|
|
pNew->pNext=NULL;
|
|
}
|
|
else if(wcscmp(pNew->wcBaseName,pWalk->wcBaseName)<0)
|
|
{
|
|
pNew->pNext=*ppBaseNames;
|
|
*ppBaseNames=pNew;
|
|
}
|
|
else
|
|
{
|
|
while((!bFound)&&(pWalk->pNext!=NULL))
|
|
{
|
|
if(wcscmp(pNew->wcBaseName,pWalk->pNext->wcBaseName)>0)
|
|
bFound=TRUE;
|
|
else
|
|
pWalk=pWalk->pNext;
|
|
}
|
|
pNew->pNext=pWalk->pNext;
|
|
pWalk->pNext=pNew;
|
|
} /*end else we need to insert it (not new head)*/
|
|
} /*end if need to add*/
|
|
} /*end function vAddNameToBaseNameList*/
|
|
|
|
|
|
|
|
char *WtoA(WCHAR *pInString)
|
|
{
|
|
static char szDest[256];
|
|
char *pSourceWalk;
|
|
char *pszDestWalk;
|
|
|
|
pszDestWalk=szDest;
|
|
pSourceWalk=(char *)pInString;
|
|
while(*pSourceWalk!='\0')
|
|
{
|
|
*(pszDestWalk++)=*pSourceWalk;
|
|
pSourceWalk+=2;
|
|
}
|
|
(*pszDestWalk)='\0';
|
|
wsprintfA(szDebugBuff,"USBMON, WtoA, About to return %s\n",szDest);
|
|
OutputDebugStringD3(szDebugBuff); //yy
|
|
return szDest;
|
|
}
|
|
|
|
|
|
void vCleanUpQueuesAndPorts(PUSBMON_PORT_INFO * ppPortInfo,int iNumberOfPorts,PUSBMON_BASENAME pBaseNames)
|
|
{
|
|
DWORD dwThreadID;
|
|
PCLEANUP_THREAD_PARAMS pCleanupParams;
|
|
|
|
pCleanupParams=(PCLEANUP_THREAD_PARAMS)GlobalAlloc(0,sizeof(CLEANUP_THREAD_PARAMS));
|
|
if(pCleanupParams==NULL)
|
|
{
|
|
OutputDebugStringD1("USBMON: failed to allocate memory in vCleanupQueuesAndPorts\n");
|
|
return;
|
|
}
|
|
pCleanupParams->ppPortInfo=ppPortInfo;
|
|
pCleanupParams->iPortCount=iNumberOfPorts;
|
|
pCleanupParams->hSemaphore=hMonitorSemaphore;
|
|
pCleanupParams->pBaseNames=pBaseNames;
|
|
CreateThread(NULL,0,CleanupThread,pCleanupParams,0,&dwThreadID);
|
|
}
|
|
|
|
DWORD WINAPI CleanupThread(LPVOID pParam)
|
|
{
|
|
PCLEANUP_THREAD_PARAMS pParams;
|
|
PUSBMON_QUEUE_INFO pQueueList;
|
|
DWORD dwStatus;
|
|
|
|
pParams=(PCLEANUP_THREAD_PARAMS)pParam;
|
|
pQueueList=NULL;
|
|
lGetQueues(&pQueueList,pParams->pBaseNames);
|
|
if(pQueueList==NULL)
|
|
{
|
|
OutputDebugStringD3("USBMON: CleanupThread, pQueueList==NULL\n");
|
|
}
|
|
else
|
|
{
|
|
OutputDebugStringD3("USBMON: CleanupThread, pQueueList!=NULL\n");
|
|
}
|
|
wsprintfA(szDebugBuff,"USBMON:+++++++++++++++++++++++++++++++++++++++ Head of CleanupThread, before WaitForSingleObject, hMonitorSemaphore=%x\n",hMonitorSemaphore);
|
|
OutputDebugStringD2(szDebugBuff);
|
|
dwStatus=WaitForSingleObject(hMonitorSemaphore,INFINITE);
|
|
if(dwStatus==WAIT_FAILED)
|
|
OutputDebugStringD1("USBMON: WaitForSingleObject failed!\n");
|
|
wsprintfA(szDebugBuff,"USBMON: CleanupThread: WaitForSingleObject returned %d\n",dwStatus);
|
|
OutputDebugStringD3(szDebugBuff);
|
|
OutputDebugStringD2("USBMON: Head of CleanupThread, after WaitForSingleObject\n");
|
|
vEliminateOldQueuesAndPorts(pQueueList,pParams->ppPortInfo);
|
|
vDestroyQueueList(pQueueList);
|
|
GlobalFree(pParams);
|
|
OutputDebugStringD2("USBMON: tail of CleanupThread, about to release semaphore++++++++++++++++++++++++++++++++++++++++++++\n");
|
|
iCleanupThreads--;
|
|
ReleaseSemaphore(hMonitorSemaphore,1,NULL);
|
|
return 0;
|
|
}
|
|
|
|
void vEliminateOldQueuesAndPorts(PUSBMON_QUEUE_INFO pQueueInfo,PUSBMON_PORT_INFO * ppPortHead)
|
|
{
|
|
PUSBMON_QUEUE_INFO pQueueWalk;
|
|
PUSBMON_PORT_INFO pPortWalk;
|
|
HDEVINFO hDevInfo;
|
|
int iCompare;
|
|
BOOL bNull=FALSE;
|
|
|
|
hDevInfo=SetupDiGetClassDevs((GUID *)&USB_PRINTER_GUID,NULL,NULL,DIGCF_INTERFACEDEVICE);
|
|
if ( hDevInfo == INVALID_HANDLE_VALUE )
|
|
return;
|
|
|
|
pQueueWalk=pQueueInfo;
|
|
pPortWalk= *ppPortHead;
|
|
pPortWalk=*ppPortHead;
|
|
if((pPortWalk!=NULL)&&(pQueueWalk!=NULL))
|
|
{
|
|
iCompare=lstrcmp(pPortWalk->szPortName,pQueueWalk->wcPortName);
|
|
wsprintf((WCHAR *)szDebugBuff,L"USBMON: About to compare %s and %s\n",pPortWalk->szPortName,pQueueWalk->wcPortName);
|
|
OutputDebugStringWD2((WCHAR *)szDebugBuff);
|
|
}
|
|
else
|
|
bNull=TRUE;
|
|
while(!bNull)
|
|
{
|
|
//Walk through matching items loop
|
|
while((iCompare==0)&&(!bNull))
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: in cleanup loop, flags=%d\n",pPortWalk->dwDeviceFlags);
|
|
OutputDebugStringD2(szDebugBuff);
|
|
|
|
if((pPortWalk->dwDeviceFlags)&SPINT_ACTIVE)
|
|
vUnGreyQueue(pQueueWalk);
|
|
else
|
|
vGreyOutQueue(pQueueWalk);
|
|
pPortWalk=pPortWalk->pNext;
|
|
pQueueWalk=pQueueWalk->pNext;
|
|
if((pPortWalk!=NULL)&&(pQueueWalk!=NULL))
|
|
{
|
|
iCompare=lstrcmp(pPortWalk->szPortName,pQueueWalk->wcPortName);
|
|
} /*end if no nulls*/
|
|
else
|
|
bNull=TRUE;
|
|
} /*end while matching items*/
|
|
|
|
// grey out "detached" printers loop
|
|
while((iCompare>0)&&(!bNull))
|
|
{
|
|
|
|
OutputDebugStringD3("USBMON: About to grey out queue inside the \"grey queue\" inner loop\n");
|
|
//vGreyOutQueue(pQueueWalk); //perhaps something else should happen here. What does it mean if a port is gone but the queue is still around?
|
|
|
|
pQueueWalk=pQueueWalk->pNext;
|
|
if(pQueueWalk!=NULL)
|
|
{
|
|
wsprintf((WCHAR *)szDebugBuff,L"USBMON: About to compare %s and %s\n",pPortWalk->szPortName,pQueueWalk->wcPortName);
|
|
OutputDebugStringWD2((WCHAR *)szDebugBuff);
|
|
iCompare=lstrcmp(pPortWalk->szPortName,pQueueWalk->wcPortName);
|
|
}
|
|
else
|
|
bNull=TRUE;
|
|
} /*end grey out loop*/
|
|
|
|
// delete orphaned port names loop
|
|
while((iCompare<0)&&(!bNull))
|
|
{
|
|
if(!((pPortWalk->dwDeviceFlags)&SPINT_ACTIVE))
|
|
vDeletePort(pPortWalk, hDevInfo);
|
|
pPortWalk=pPortWalk->pNext;
|
|
if(pPortWalk!=NULL)
|
|
{
|
|
wsprintf((WCHAR *)szDebugBuff,L"USBMON: About to compare %s and %s\n",pPortWalk->szPortName,pQueueWalk->wcPortName);
|
|
OutputDebugStringWD2((WCHAR *)szDebugBuff);
|
|
iCompare=lstrcmp(pPortWalk->szPortName,pQueueWalk->wcPortName);
|
|
}
|
|
else
|
|
bNull=TRUE;
|
|
} /*end delete ports loop*/
|
|
} /*end while both lists not null (outer loop)*/
|
|
|
|
//grey out "detached" printers at end of list loop
|
|
while(pQueueWalk!=NULL)
|
|
{
|
|
OutputDebugStringD2("USBMON: About to grey out queue inside the \"grey queue\" cleanup loop\n");
|
|
vGreyOutQueue(pQueueWalk); //perhaps something else should happen here. What does it mean if a port is gone but the queue is still around?
|
|
pQueueWalk=pQueueWalk->pNext;
|
|
} //end end of list disable queues list
|
|
|
|
//delete orphaned ports names at end of list loop
|
|
while(pPortWalk!=NULL)
|
|
{
|
|
if(!((pPortWalk->dwDeviceFlags)&SPINT_ACTIVE))
|
|
vDeletePort(pPortWalk, hDevInfo);
|
|
pPortWalk=pPortWalk->pNext;
|
|
} //end end of list delete ports loop
|
|
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
} /*end function vEliminateOldQueuesAndPorts*/
|
|
|
|
|
|
void vGreyOutQueue(PUSBMON_QUEUE_INFO pQueue)
|
|
{
|
|
#define SET_PRINTER_BUFFER_SIZE 1024
|
|
HANDLE hPrinterHandle;
|
|
PRINTER_DEFAULTS rPrinterDefaults;
|
|
BYTE bPrinterInfo[SET_PRINTER_BUFFER_SIZE];
|
|
int iSizeNeeded;
|
|
PRINTER_INFO_5 *pPrinterInfo;
|
|
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GreyOut Queue %s attached to %s\n",pQueue->wcPrinterName,pQueue->wcPortName);
|
|
OutputDebugStringWD2((WCHAR *)szDebugBuff);
|
|
|
|
rPrinterDefaults.pDatatype=NULL;
|
|
rPrinterDefaults.pDevMode=NULL;
|
|
rPrinterDefaults.DesiredAccess=PRINTER_ACCESS_ADMINISTER|STANDARD_RIGHTS_ALL|SPECIFIC_RIGHTS_ALL;
|
|
if(!OpenPrinter(pQueue->wcPrinterName,&hPrinterHandle,&rPrinterDefaults))
|
|
OutputDebugStringD1("USBMON: Unable to OpenPrinter in vGreyOutQueue\n");
|
|
if(!GetPrinter(hPrinterHandle,5,bPrinterInfo,SET_PRINTER_BUFFER_SIZE,&iSizeNeeded))
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: GetPrinter failed, error code==%d\n",GetLastError());
|
|
OutputDebugStringD1(szDebugBuff);
|
|
}
|
|
|
|
if(iSizeNeeded>SET_PRINTER_BUFFER_SIZE)
|
|
OutputDebugStringD1("USBMON: Buffer size not big enough in vGreyOutQueue\n");
|
|
pPrinterInfo=(PRINTER_INFO_5 *)bPrinterInfo;
|
|
(pPrinterInfo->Attributes)|=PRINTER_ATTRIBUTE_WORK_OFFLINE;
|
|
OutputDebugStringD2("USBMON: about to SetPrinter\n");
|
|
if(!SetPrinter(hPrinterHandle,5,bPrinterInfo,0))
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: SetPrinter failed, error code==%d\n",GetLastError());
|
|
OutputDebugStringD1(szDebugBuff);
|
|
}
|
|
|
|
ClosePrinter(hPrinterHandle);
|
|
|
|
} /*end function vGreyOutQueue*/
|
|
|
|
void vUnGreyQueue(PUSBMON_QUEUE_INFO pQueue)
|
|
{
|
|
HANDLE hPrinterHandle;
|
|
PRINTER_DEFAULTS rPrinterDefaults;
|
|
BYTE bPrinterInfo[SET_PRINTER_BUFFER_SIZE];
|
|
int iSizeNeeded;
|
|
PRINTER_INFO_5 *pPrinterInfo;
|
|
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UnGrey Queue %s attached to %s\n",pQueue->wcPrinterName,pQueue->wcPortName);
|
|
OutputDebugStringWD3((WCHAR *)szDebugBuff);
|
|
|
|
rPrinterDefaults.pDatatype=NULL;
|
|
rPrinterDefaults.pDevMode=NULL;
|
|
rPrinterDefaults.DesiredAccess=PRINTER_ACCESS_ADMINISTER|STANDARD_RIGHTS_ALL|SPECIFIC_RIGHTS_ALL;
|
|
if(!OpenPrinter(pQueue->wcPrinterName,&hPrinterHandle,&rPrinterDefaults))
|
|
OutputDebugStringD1("USBMON: Unable to OpenPrinter in vGreyOutQueue\n");
|
|
if(!GetPrinter(hPrinterHandle,5,bPrinterInfo,SET_PRINTER_BUFFER_SIZE,&iSizeNeeded))
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: GetPrinter failed, error code==%d\n",GetLastError());
|
|
OutputDebugStringD1(szDebugBuff);
|
|
}
|
|
|
|
if(iSizeNeeded>SET_PRINTER_BUFFER_SIZE)
|
|
OutputDebugStringD1("USBMON: Buffer size not big enough in vUnGreyQueue\n");
|
|
pPrinterInfo=(PRINTER_INFO_5 *)bPrinterInfo;
|
|
(pPrinterInfo->Attributes)&=(~PRINTER_ATTRIBUTE_WORK_OFFLINE);
|
|
OutputDebugStringD3("USBMON: about to SetPrinter\n");
|
|
if(!SetPrinter(hPrinterHandle,5,bPrinterInfo,0))
|
|
{
|
|
wsprintfA(szDebugBuff,"USBMON: SetPrinter failed, error code==%d\n",GetLastError());
|
|
OutputDebugStringD1(szDebugBuff);
|
|
}
|
|
|
|
ClosePrinter(hPrinterHandle);
|
|
|
|
|
|
|
|
} /*end function vUnGreyQueue*/
|
|
|
|
/*******************************************
|
|
* vDletePort -- marks a port struct as *
|
|
* Deleted by setting it's device name to *
|
|
* Null and deleting the port name value *
|
|
* from the registry *
|
|
*******************************************/
|
|
void vDeletePort(PUSBMON_PORT_INFO pPort, HDEVINFO hDeviceList)
|
|
{
|
|
HANDLE hDeviceKey;
|
|
|
|
// DebugBreak();
|
|
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON: /********************Head of vDeletePort for %s.\n",pPort->szPortName);
|
|
OutputDebugStringWD2((WCHAR *)szDebugBuff);
|
|
|
|
|
|
hDeviceKey=hGetPortRegKey(pPort, hDeviceList);
|
|
if(hDeviceKey!=INVALID_HANDLE_VALUE)
|
|
{
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON: Opened key for port %s.\n",pPort->szPortName);
|
|
OutputDebugStringWD3((WCHAR *)szDebugBuff);
|
|
// if(RegDeleteValue(hDeviceKey,L"Port Number")==ERROR_SUCCESS)
|
|
if(RegSetValueEx(hDeviceKey,L"recyclable",0,REG_NONE,0,0)==ERROR_SUCCESS)
|
|
{
|
|
OutputDebugStringD3("USBMON: RegSetValue Success\n");
|
|
}
|
|
else
|
|
{
|
|
OutputDebugStringD2("USBMON: RegSetValue Failure\n");
|
|
}
|
|
RegCloseKey(hDeviceKey);
|
|
} /*end if hGetProtRegKey worked*/
|
|
else
|
|
{
|
|
wsprintfW((WCHAR *)szDebugBuff,L"USBMON: Unable to locate and delete reg key for %s\n",pPort->szPortName);
|
|
OutputDebugStringWD1((WCHAR *)szDebugBuff);
|
|
}
|
|
} /*end function vDeletePort*/
|
|
|
|
|
|
BOOL
|
|
MatchingRegKey(
|
|
HKEY hKey,
|
|
PUSBMON_PORT_INFO pPort
|
|
)
|
|
{
|
|
WCHAR wcBaseName[MAX_PORT_LEN];
|
|
WCHAR wcPortName[MAX_PORT_LEN];
|
|
DWORD dwPortNumber;
|
|
DWORD dwReadSize;
|
|
|
|
dwReadSize=sizeof(DWORD);
|
|
if(RegQueryValueEx(hKey,L"Port Number",0,NULL,(LPBYTE)&dwPortNumber,&dwReadSize)==ERROR_SUCCESS)
|
|
{
|
|
dwReadSize=sizeof(wcBaseName);
|
|
if(RegQueryValueEx(hKey,L"Base Name",0,NULL,(LPBYTE)wcBaseName,&dwReadSize)!=ERROR_SUCCESS)
|
|
{
|
|
OutputDebugStringD2("USBMON: Unable to locate basename. Defaulting to \"USB\"\n"); //yy
|
|
wcscpy(wcBaseName,L"USB");
|
|
}
|
|
|
|
wsprintf(wcPortName,L"%s%03u",wcBaseName,dwPortNumber);
|
|
return wcscmp(wcPortName,pPort->szPortName)==0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
HANDLE hGetPortRegKey(PUSBMON_PORT_INFO pPort, HDEVINFO hDeviceList)
|
|
{
|
|
GUID *pPrinterGuid;
|
|
int iLoop=0;
|
|
SP_DEVICE_INTERFACE_DATA rDeviceInfo;
|
|
BOOL bMoreDevices,bFound=FALSE;
|
|
DWORD dwRequiredSize;
|
|
HANDLE hRegHandle;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceDetail;
|
|
WCHAR wcBaseName[MAX_PORT_LEN];
|
|
|
|
rDeviceInfo.cbSize=sizeof(rDeviceInfo);
|
|
|
|
if ( !SetupDiOpenDeviceInterface(hDeviceList, pPort->DevicePath,
|
|
DIODI_NO_ADD, &rDeviceInfo) )
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
hRegHandle = SetupDiOpenDeviceInterfaceRegKey(hDeviceList,
|
|
&rDeviceInfo,
|
|
0,
|
|
KEY_ALL_ACCESS);
|
|
|
|
if ( hRegHandle != INVALID_HANDLE_VALUE ) {
|
|
|
|
if ( MatchingRegKey(hRegHandle, pPort) )
|
|
return hRegHandle;
|
|
|
|
CloseHandle(hRegHandle);
|
|
}
|
|
|
|
pPrinterGuid=(GUID *)&USB_PRINTER_GUID;
|
|
bMoreDevices=SetupDiEnumDeviceInterfaces(hDeviceList,0,pPrinterGuid,iLoop,&rDeviceInfo);
|
|
while((bMoreDevices)&&(!bFound))
|
|
{
|
|
|
|
SetupDiGetDeviceInterfaceDetail(hDeviceList,&rDeviceInfo,NULL,0,&dwRequiredSize,NULL);
|
|
pDeviceDetail=(PSP_DEVICE_INTERFACE_DETAIL_DATA)GlobalAlloc(0,dwRequiredSize);
|
|
if(pDeviceDetail==NULL)
|
|
{
|
|
OutputDebugStringD1("USBMON: Unable to allocate memory in pGetPrinterList\n");
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
pDeviceDetail->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
|
if(!SetupDiGetDeviceInterfaceDetail(hDeviceList,&rDeviceInfo,pDeviceDetail,dwRequiredSize,&dwRequiredSize,NULL))
|
|
{
|
|
OutputDebugStringD1("USBMON: SetupDiGetDeviceInterfaceDetail (second call) failed\n");
|
|
return INVALID_HANDLE_VALUE;
|
|
} /*end if SetupDiGetDeviceInterfaceDetail, call2 failed*/
|
|
|
|
hRegHandle=SetupDiOpenDeviceInterfaceRegKey(hDeviceList,&rDeviceInfo,0,KEY_ALL_ACCESS);
|
|
if(hRegHandle!=INVALID_HANDLE_VALUE)
|
|
{
|
|
if ( MatchingRegKey(hRegHandle, pPort) )
|
|
bFound=TRUE;
|
|
else
|
|
CloseHandle(hRegHandle);
|
|
} /*end if SetupDiOpenDeviceInterfaceRegKey successful*/
|
|
GlobalFree(pDeviceDetail);
|
|
bMoreDevices=SetupDiEnumDeviceInterfaces(hDeviceList,0,pPrinterGuid,++iLoop,&rDeviceInfo);
|
|
} /*end while more devices & !found*/
|
|
|
|
if(!bFound)
|
|
hRegHandle=INVALID_HANDLE_VALUE;
|
|
return hRegHandle;
|
|
} /*end function hGetPortRegKey*/
|
|
|