/*************************************************************************** * * File Name: WPNPIN16.C * * Copyright 1997 Hewlett-Packard Company. * All rights reserved. * * 11311 Chinden Blvd. * Boise, Idaho 83714 * * * Description: Source code for WPNPIN16.DLL * * Author: Garth Schmeling * * * Modification history: * * Date Initials Change description * * 10-10-97 GFS Initial checkin * * * ***************************************************************************/ #include "wpnpin16.h" /*--------------- For Debug -------------------------*/ //#define GARTH_DEBUG 1 /*****************************************************************************\ * strFree * * Free allocated string. * \*****************************************************************************/ VOID strFree( HANDLE hszStr, LPSTR pszStr) { if (hszStr && pszStr) GlobalUnlock(hszStr); if (hszStr) GlobalFree(hszStr); } /*****************************************************************************\ * strAlloc * * Allocates a string from the heap. This pointer must be freed with * a call to strFree(). * \*****************************************************************************/ LPSTR strAlloc( LPHANDLE phSrc, LPCSTR pszSrc) { DWORD cbSize; LPSTR pszDst = NULL; *phSrc = NULL; cbSize = (pszSrc ? (lstrlen(pszSrc) + 1) : 0); if (cbSize && (*phSrc = GlobalAlloc(GPTR, cbSize))) { if (pszDst = (LPSTR)GlobalLock(*phSrc)) lstrcpy(pszDst, pszSrc); } return pszDst; } /*****************************************************************************\ * strLoad * * Get string from resource based upon the ID passed in. * \*****************************************************************************/ LPSTR strLoad( LPHANDLE phszStr, UINT ids) { char szStr[_MAX_RESBUF]; if (LoadString(g_hInst, ids, szStr, sizeof(szStr)) == 0) szStr[0] = '\0'; return strAlloc(phszStr, szStr); } /*****************************************************************************\ * InitStrings * * \*****************************************************************************/ BOOL InitStrings(VOID) { cszDefaultPrintProcessor = strLoad(&hszDefaultPrintProcessor, IDS_DEFAULT_PRINTPROCESSOR); cszMSDefaultDataType = strLoad(&hszMSDefaultDataType , IDS_DEFAULT_DATATYPE); cszDefaultColorPath = strLoad(&hszDefaultColorPath , IDS_COLOR_PATH); cszFileInUse = strLoad(&hszFileInUse , IDS_ERR_FILE_IN_USE); return (cszDefaultPrintProcessor && cszMSDefaultDataType && cszDefaultColorPath && cszFileInUse); } /*****************************************************************************\ * FreeeStrings * * \*****************************************************************************/ VOID FreeStrings(VOID) { strFree(hszDefaultPrintProcessor, cszDefaultPrintProcessor); strFree(hszMSDefaultDataType , cszMSDefaultDataType); strFree(hszDefaultColorPath , cszDefaultColorPath); strFree(hszFileInUse , cszFileInUse); } /*****************************************************************************\ * DllEntryPoint * * \*****************************************************************************/ BOOL FAR PASCAL DllEntryPoint( DWORD dwReason, WORD hInst, WORD wDS, WORD wHeapSize, DWORD dwReserved1, WORD wReserved2) { if (g_hInst == NULL) { g_hInst = (HINSTANCE)hInst; if (InitStrings() == FALSE) return FALSE; } return thk_ThunkConnect16(cszDll16, cszDll32, hInst, dwReason); } //----------------------------------------------------------------------- // Function: lstrpbrk(lpSearch,lpTargets) // // Action: DBCS-aware version of strpbrk. // // Return: Pointer to the first character that in lpSearch that is also // in lpTargets. NULL if not found. // // Comment: Use nested loops to avoid allocating memory for DBCS stuff. //----------------------------------------------------------------------- LPSTR WINAPI lstrpbrk(LPSTR lpSearch, LPSTR lpTargets) { LPSTR lpOneTarget; if (lpSearch AND lpTargets) { for (; *lpSearch; lpSearch=AnsiNext(lpSearch)) { for (lpOneTarget=lpTargets; *lpOneTarget; lpOneTarget=AnsiNext(lpOneTarget)) { if (*lpSearch==*lpOneTarget) { // First byte matches--see if we need to check // second byte if (IsDBCSLeadByte(*lpOneTarget)) { if (*(lpSearch+1) == *(lpOneTarget+1)) return lpSearch; } else return lpSearch; } } } } return NULL; } //----------------------------------------------------------------------- // Function: lstrtok(lpSearch,lpTargets) // // Action: DBCS-aware version of strtok. // // Return: Pointer to next non-NULL token if found, NULL if not. //----------------------------------------------------------------------- LPSTR WINAPI lstrtok(LPSTR lpSearch, LPSTR lpTargets) { static LPSTR lpLastSearch; LPSTR lpFound; LPSTR lpReturn=NULL; if (lpSearch) lpLastSearch=lpSearch; for (; lpLastSearch AND *lpLastSearch; lpLastSearch=AnsiNext(lpLastSearch)) { // Skip leading white space while (' '==*lpLastSearch OR '\t'==*lpLastSearch) lpLastSearch++; if (lpFound=lstrpbrk(lpLastSearch,lpTargets)) { if (lpFound==lpLastSearch) // Ignore NULL tokens continue; lpReturn=lpLastSearch; *lpFound='\0'; lpLastSearch=lpFound+1; break; } else { lpReturn=lpLastSearch; lpLastSearch=NULL; break; } } return lpReturn; } //-------------------------------------------------------------------- // Function: FindCorrectSection(szInfFile,szManufacturer,szModel,szSection) // // Action: Find the install section in the inf file that corresponds // to the model name. This may require several different approaches. // Try the most likely first and then try others. // // Side effect: Put the section name in szSection. // // Return: TRUE if the section was found, FALSE if not. // //-------------------------------------------------------------------- BOOL WINAPI FindCorrectSection( LPSTR szInfFile, LPSTR szManufacturer, LPSTR szModel, LPSTR szSection) { HINF hInf = 0; HINFLINE hInfLine = 0; int i = 0; int nCount = 0; int nCopied = 0; int nFields = 0; BOOL bHaveManu = FALSE; char lpszBuf[_MAX_LINE]; char lpszTemp[_MAX_LINE]; char lpszTemp2[_MAX_LINE]; // Open the INF file. if (OK != IpOpen(szInfFile, &hInf)) { return FALSE; } lstrcpy(lpszBuf, cszNull); lstrcpy(lpszTemp, cszNull); lstrcpy(lpszTemp2, cszNull); // Try # 1 to get the manufacturer's section name // Look for a section corresponding to the manufacturer's // name. Copy it to lpszBuf. Open that section below. if (OK == IpFindFirstLine(hInf, szManufacturer, NULL, &hInfLine)) { lstrcpy(lpszBuf, szManufacturer); bHaveManu = TRUE; DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #1, Main [HP] Section")); } // Try # 1 // Try # 2 to get the manufacturer's section name // Try the main [Manufacturer] section. // Cycle through each name expecting the name to be in the // Strings section. if (!bHaveManu AND (OK == IpFindFirstLine(hInf, "Manufacturer", NULL, &hInfLine))) { // Get the number of lines if (OK == IpGetLineCount(hInf, "Manufacturer", &nCount)) { for (i = 0; i < nCount; i++) { lpszBuf[0] = '\0'; lpszTemp[0] = '\0'; if (OK == IpGetStringField(hInf, hInfLine, 0, lpszTemp, _MAX_LINE, &nCopied)) { GenFormStrWithoutPlaceHolders(lpszBuf,lpszTemp,hInf); // Garth: Use CompareString with the // IGNORE_CASE, IGNORE_KANATYPE, and IGNORE_WIDTH flags if (lstrcmpi(szManufacturer, lpszBuf) == 0) { // We have found the manufacturer name, see if // there is a key on the right nFields = 0; if ( (OK == IpGetFieldCount(hInf, hInfLine, &nFields)) AND (nFields > 0) ) { if (OK == IpGetStringField(hInf, hInfLine, 1, lpszBuf, _MAX_LINE, &nCopied)) { // There was a value on the right. It is stored in lpszBuf. // Just try to use it below as the name of the main section. DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #2 Before NULL, lpszTemp = %s", lpszTemp)); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : Manual Install = %s", lpszBuf)); lpszTemp[0] = '\0'; } } else { // There was no value on the right, use the name from // lpszTemp lpszBuf[0] = '\0'; lstrcpy(lpszBuf, lpszTemp); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #3 Manual")); } bHaveManu = TRUE; break; } } if (OK != IpFindNextLine(hInf, &hInfLine)) { break; } } } } // Try # 2 // Try # 3 to get the manufacturer's section name // Try the main [Manufacturer] section. // The printer manufacturer name does not match the // driver manufacturer name. (IE Canon and Epson with GCA) // Check to see if there is only one name in the manufacturer section. if (!bHaveManu AND (OK == IpFindFirstLine(hInf, "Manufacturer", NULL, &hInfLine))) { // Get the number of lines if (OK == IpGetLineCount(hInf, "Manufacturer", &nCount)) { if (nCount IS 1) { // Only one line in manufaturer section. // This has to be our guy. // See if there is a key on the right nFields = 0; lpszBuf[0] = '\0'; IpGetFieldCount(hInf, hInfLine, &nFields); if (nFields > 0) { if (OK == IpGetStringField(hInf, hInfLine, 1, lpszBuf, _MAX_LINE, &nCopied)) { // There was a value on the right. It is stored in lpszBuf. // Try to use it below as the name of the main section. // DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : Before NULL <%s>", lpszTemp)); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #4 One Manual <%s>", lpszBuf)); lpszTemp[0] = '\0'; bHaveManu = TRUE; } } else { // There was no value on the right. Get the key on the left. if (OK == IpGetStringField(hInf, hInfLine, 0, lpszBuf, _MAX_LINE, &nCopied)) { lpszTemp[0] = '\0'; bHaveManu = TRUE; DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #6 One Manual")); } } } } } // Try # 3 // Try # 4 to get the manufacturer's section name // Try a [PnP] section. if (!bHaveManu AND (OK == IpFindFirstLine(hInf, "PnP", NULL, &hInfLine))) { lpszBuf[0] = '\0'; lstrcpy(lpszBuf, "PnP"); bHaveManu = TRUE; DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #6 [Pnp]")); } // Try # 4 // Try # 6. Get the install section associated with this // manufacturer and model. // // Look for a manufacturer's section with a profile key // corresponding to the model name. The first key on the RHS // should be the model section name. // if (bHaveManu AND (OK == IpFindFirstLine(hInf, lpszBuf, NULL, &hInfLine))) { DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : Found first line <%s>", lpszBuf)); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : Search for this model <%s>", szModel)); lstrcpy(lpszTemp, cszNull); if (OK == IpGetProfileString(hInf,lpszBuf,szModel,lpszTemp,_MAX_LINE)) { DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : Profile string before lstrtok")); lstrtok(lpszTemp, cszComma); // quick check of model section name // if (OK == IpFindFirstLine(hInf, lpszTemp, NULL, &hInfLine)) { if ( (OK == IpGetProfileString(hInf,lpszTemp,"CopyFiles",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszTemp,"DataSection",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszTemp,"DriverFile",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszTemp,"DataFile",lpszTemp2,_MAX_LINE))) { lstrcpyn(szSection, lpszTemp, _MAX_PATH_); IpClose(hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #7 Found Correct Section")); return TRUE; } // We have a bad INF file: // We have the manufacturer name and the model name and an // install section, but it doesn't have any of the keys we need. // bail. // IpClose(hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #8 Bad INF file")); return FALSE; } } // The model name doesn't appear as a profile string. // Perhaps a variable from the Strings sections appears in its place. // Try that. if ( (OK == IpGetLineCount(hInf, lpszBuf, &nCount)) AND (OK == IpFindFirstLine(hInf, lpszBuf, NULL, &hInfLine)) ) { for (i = 0; i < nCount; i++) { lstrcpy(lpszTemp, cszNull); if (OK == IpGetStringField(hInf, hInfLine, 0, lpszTemp, _MAX_LINE, &nCopied)) { GenFormStrWithoutPlaceHolders(lpszTemp2,lpszTemp,hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : lpszTemp2=%s, lpszTemp=%s", lpszTemp2, lpszTemp)); if (lstrcmpi(szModel, lpszTemp2) == 0) { // The model name has a string var on the left // Get field 1. This is the install section name. if (OK == IpGetStringField(hInf, hInfLine, 1, lpszTemp, _MAX_LINE, &nCopied)) { DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : Before lstrtok comma")); lstrtok(lpszTemp, cszComma); // quick check of model section name // if (OK == IpFindFirstLine(hInf, lpszTemp, NULL, &hInfLine)) { if ((OK == IpGetProfileString(hInf,lpszTemp,"CopyFiles",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszTemp,"DataSection",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszTemp,"DriverFile",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszTemp,"DataFile",lpszTemp2,_MAX_LINE))) { lstrcpyn(szSection, lpszTemp, _MAX_PATH_); IpClose(hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #9 Strings Found Correct Section")); return TRUE; } // We have a bad INF file: // We have the manufacturer name and the model name and an // install section, but it doesn't have any of the keys we need. // bail. // IpClose(hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #10 Strings Bad INF File")); return FALSE; } } } } if (OK != IpFindNextLine(hInf, &hInfLine)) { break; } } } } // Try # 6 // Try # 7 // Check to see if there is a valid InstallSection. // if (OK == IpFindFirstLine(hInf, "InstallSection", NULL, &hInfLine)) { // quick check of InstallSection if (OK == IpFindFirstLine(hInf, "InstallSection", NULL, &hInfLine)) { if ((OK == IpGetProfileString(hInf,"InstallSection","CopyFiles",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,"InstallSection","DataSection",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,"InstallSection","DriverFile",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,"InstallSection","DataFile",lpszTemp2,_MAX_LINE))) { lstrcpyn(szSection, "InstallSection", _MAX_PATH_); IpClose(hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #11 Found correct InstallSection")); return TRUE; } } } // Try # 7 // Try # 8. // Try the [Strings] section. if (OK == IpFindFirstLine(hInf, "Strings", NULL, &hInfLine)) { // Get the number of lines if (OK == IpGetLineCount(hInf, "Strings", &nCount)) { for (i = 0; i < nCount; i++) { lpszBuf[0] = '\0'; lpszTemp[0] = '\0'; if (OK == IpGetStringField(hInf, hInfLine, 1, lpszTemp, _MAX_LINE, &nCopied)) { // Garth: Use CompareString with the // IGNORE_CASE, IGNORE_KANATYPE, and IGNORE_WIDTH flags if (lstrcmpi(szModel, lpszTemp) == 0) { // The model name has a string var on the left if (OK == IpGetStringField(hInf, hInfLine, 0, lpszBuf, _MAX_LINE, &nCopied)) { // There was a value on the left, try to use it if (OK == IpFindFirstLine(hInf, lpszBuf, NULL, &hInfLine)) { // quick check of Strings if (OK == IpFindFirstLine(hInf, lpszBuf, NULL, &hInfLine)) { if ((OK == IpGetProfileString(hInf,lpszBuf,"CopyFiles",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszBuf,"DataSection",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszBuf,"DriverFile",lpszTemp2,_MAX_LINE)) OR (OK == IpGetProfileString(hInf,lpszBuf,"DataFile",lpszTemp2,_MAX_LINE))) { lstrcpyn(szSection, lpszBuf, _MAX_PATH_); IpClose(hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #12 Found String = Model Section")); return TRUE; } } } } } } } } } // Try # 8 // No more ideas, Give up. // IpClose(hInf); DBG_MSG(DBG_LEV_INFO, ("FindCorrectSection : #13 Failed to find section")); return FALSE; } //----------------------------------------------------------------------- // Function: GetInfOption(hInf,lpszSection,bDataSection,bLocalize, // lpszDataSection,lpszKeyName,lpszBuffer,wBufSize) // // Action: Get the specified keyword from the INF file. Look in the // appropriate section(s) // // Note: Keys may always appear in lpszSection, and may appear in // lpszDataSection if bDataSection is TRUE. If the key appears // in both sections, the value from lpszSection takes precedence. // // Return: TRUE if we got the option, FALSE if not //----------------------------------------------------------------------- BOOL NEAR PASCAL GetInfOption(HINF hInf, LPSTR lpszSection, BOOL bDataSection, BOOL bLocalize, LPSTR lpszDataSection, LPSTR lpszKeyName, LPSTR lpszBuffer, WORD wBufSize) { LPSTR lpszTemp; BOOL bAllocated; BOOL bSuccess; if (bLocalize && wBufSize && (lpszTemp=(LPSTR)(HP_GLOBAL_ALLOC_DLL(max(wBufSize,_MAX_PATH_))))) { bAllocated=TRUE; } else { lpszTemp=lpszBuffer; bAllocated=FALSE; } if (OK == IpGetProfileString(hInf,lpszSection,lpszKeyName,lpszTemp,wBufSize)) { bSuccess=TRUE; } else if (bDataSection && (OK == IpGetProfileString(hInf,lpszDataSection, lpszKeyName,lpszTemp,wBufSize))) { bSuccess=TRUE; } else bSuccess=FALSE; if (bAllocated) { if (bSuccess) GenFormStrWithoutPlaceHolders(lpszBuffer,lpszTemp,hInf); HP_GLOBAL_FREE(lpszTemp); } return bSuccess; } //----------------------------------------------------------------------- // Function: myatoi(pszInt) // // Yup, the first function that everyone writes! //----------------------------------------------------------------------- int WINAPI myatoi( LPSTR pszInt) { int nRet; char cSave; for (nRet = 0; ; ++pszInt) { if ((cSave = (*pszInt - (char)'0')) > 9) break; nRet = (nRet * 10) + cSave; } return nRet; } //------------------------------------------------------------------------ // Function: ZeroMem(lpData,wCount) // // Action: Zero-initialize wCount bytes at lpData (duh) // // Return: VOID //------------------------------------------------------------------------ VOID WINAPI ZeroMem(LPVOID lpData, WORD wCount) { LPBYTE lpBuf=(LPBYTE)lpData; while (wCount--) { *lpBuf='\0'; lpBuf++; } } //-------------------------------------------------------------------- // Function: FlushCachedPrinterFiles(void) // // Action: Flush printer driver files that might be cached by the // system. Two caches exist--one maintained by USER, and one // maintained by winspl16.drv (for old drivers) // // Return: Void //-------------------------------------------------------------------- VOID WINAPI FlushCachedPrinterFiles() { HWND hWndMsgSvr; HMODULE hModWinspl16; // Send a message to MSGSVR32 to flush the default printer's cached DC. if (hWndMsgSvr = FindWindow(cszMsgSvr, NULL)) SendMessage(hWndMsgSvr, WM_USER+0x010A, 0, 0L); // If WINSPL16 is in memory, force it to flush its cache if (hModWinspl16 = GetModuleHandle(cszWinspl16)) { WEPPROC fpWep; if (fpWep = (WEPPROC)GetProcAddress(hModWinspl16, "WEP")) { fpWep(0); } } } //------------------------------------------------------------------ // Function: RenameFailed(lpsi,lpFileSpec) // // Action: Handle the case where the rename failed. Give the user a // chance to close existing apps and shut down printers. // // Return: 0 if the file isn't loaded (use default handling) // VCPN_ABORT if file is in use & user cancelled // VCPN_RETRY if file is in use & user wants to retry //------------------------------------------------------------------ LRESULT NEAR PASCAL RenameFailed(LPSI lpsi, LPVCPFILESPEC lpFileSpec) { char szFile[_MAX_PATH_]; if (vsmGetStringName(lpFileSpec->vhstrFileName,szFile,sizeof(szFile)) && GetModuleHandle(szFile)) { char Message[_MAX_PATH_]; // File is in use by the system--give the user the chance to shut // down existing applications, then continue. if ( LoadString(g_hInst, IDS_ERR_FILE_IN_USE, Message, _MAX_PATH_) IS 0) { DBG_MSG(DBG_LEV_INFO, ("RenameFailed : Could not load string, file in use")); lstrcpy(Message, cszFileInUse); } if (IDCANCEL IS MessageBox(NULL, Message, szFile, MB_ICONEXCLAMATION|MB_RETRYCANCEL|MB_DEFBUTTON2)) { return VCPN_ABORT; } else { // Flush any cached printers & retry FlushCachedPrinterFiles(); return VCPN_RETRY; } } return 0; } //------------------------------------------------------------------ // Function: MyVcpCallbackProc(lpvObj,uMsg,wParam,lParam,lparamRef) // // Action: This simply passes through to vcpUICallbackProc, with one // exception: If a file is in use in the system, we warn the // user and give them a chance to close existing apps. // // Return: Whatever RenameFailed or vcpUICallbackProc return. //------------------------------------------------------------------ LRESULT CALLBACK MyVcpCallbackProc(LPVOID lpvObj, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSI lpsi) { LRESULT lResult = 0; if ((VCPM_FILERENAME + VCPM_ERRORDELTA) IS uMsg) lResult = RenameFailed(lpsi,(LPVCPFILESPEC)lpvObj); if (! lResult) { lResult = vcpUICallbackProc(lpvObj,uMsg,wParam,lParam, (LPARAM)lpsi->lpVcpInfo); } return lResult; } //------------------------------------------------------------------- // Function: OpenQueue(lpsi, lpVcpInfo, lpbOpened) // // Action: Initialize lpVcpInfo and open the queue. *lpbOpened reflects // whether or not we actually opened the queue. // // Return: TRUE if successful, FALSE if not. //------------------------------------------------------------------- BOOL NEAR PASCAL OpenQueue(LPSI lpsi, LPVCPUIINFO lpVcpInfo, BOOL FAR *lpbOpened) { BOOL bSuccess = FALSE; // Initialize the structure ZeroMem(lpVcpInfo, sizeof(VCPUIINFO)); lpVcpInfo->flags = VCPUI_CREATEPROGRESS; lpVcpInfo->hwndParent = NULL; lpsi->lpVcpInfo = (LPBYTE) lpVcpInfo; // Open the queue if (RET_OK IS VcpOpen((VIFPROC)MyVcpCallbackProc, (LPARAM)lpsi)) { bSuccess = TRUE; *lpbOpened = TRUE; } else { // Couldn't open the queue, so clear lpVcpInfo lpsi->lpVcpInfo = NULL; *lpbOpened = FALSE; } return bSuccess; } //------------------------------------------------------------------- // Function: GenInstallCallback(lpGenInfo,lpsi) // // Action: This gets called for each file to be queued. Add it to // the list identified by lpsi->lpFiles, then queue it // to be copied to the system directory // // Return: GENN_SKIP if it's a copy (we queue it ourselves), // GENN_OK otherwise. //------------------------------------------------------------------- LRESULT WINAPI GenInstallCallback(LPGENCALLBACKINFO lpGenInfo, LPSI lpsi) { int wLength; int wMaxLength; int wChunk; if (GENO_COPYFILE != lpGenInfo->wOperation) return GENN_OK; // Save the dependent file in lpsi->lpFiles. wFilesAllocated and // wFilesUsed are used to keep track of memory usage. wLength = lstrlen(lpGenInfo->pszDstFileName); // Pad the length if it's going to LDID_COLOR if (LDID_COLOR IS lpGenInfo->ldidDst) wMaxLength = wLength + MAX_COLOR_PATH; else wMaxLength = wLength; wChunk = max(256,wMaxLength); // This is where we allocate lpFiles the first time if (! lpsi->lpFiles) { if (lpsi->lpFiles = (unsigned char *)HP_GLOBAL_ALLOC_DLL(wChunk)) { lpsi->wFilesAllocated = wChunk; } else { return GENN_SKIP; } } // double NULL terminated if ((lpsi->wFilesUsed + wMaxLength + 2) > lpsi->wFilesAllocated) { LPSTR lpNew; lpNew = (unsigned char *)HP_GLOBAL_REALLOC_DLL(lpsi->lpFiles, lpsi->wFilesAllocated + wChunk, GMEM_ZEROINIT); if (lpNew) { lpsi->wFilesAllocated += wChunk; lpsi->lpFiles = (unsigned char *) lpNew; } else { return GENN_SKIP; } } // Add this file to the list && ensure that it's doubly-NULL // terminated. If it's going to LDID_COLOR, prepend "COLOR\" // to the string if (LDID_COLOR IS lpGenInfo->ldidDst) { char ColorPath[MAX_COLOR_PATH]; if ( LoadString(g_hInst, IDS_COLOR_PATH, ColorPath, MAX_COLOR_PATH) IS 0) { strcpy(ColorPath, "COLOR\\"); } strcpy((LPSTR)(lpsi->lpFiles + lpsi->wFilesUsed), ColorPath); lpsi->wFilesUsed += strlen(ColorPath); } strcpy((LPSTR)(lpsi->lpFiles + lpsi->wFilesUsed), lpGenInfo->pszDstFileName); lpsi->wFilesUsed += (wLength + 1); lpsi->lpFiles[lpsi->wFilesUsed] = '\0'; return GENN_SKIP; } //------------------------------------------------------------------- // Function: QueueNewInf(lpsi, lpdn) // // Action: Call GenInstallEx to queue up the files we need to copy. // // Return: TRUE if we should continue, FALSE if not. //------------------------------------------------------------------- BOOL WINAPI QueueNewInf(LPSI lpsi, LPDRIVER_NODE lpdn) { if (lpdn) { return (RET_OK == GenInstallEx((HINF)lpsi->hModelInf, lpdn->lpszSectionName, GENINSTALL_DO_FILES, NULL, (GENCALLBACKPROC)GenInstallCallback, (LPARAM)lpsi)); } return FALSE; } //------------------------------------------------------------------- // Function: CloseQueue(lpsi, bSuccessSoFar, bOpened) // // Action: Close the VCP queue and report any errors to the user. // If bSuccessSoFar is FALSE, abandon the queue & return FALSE // // Return: TRUE if the copy was successful, FALSE if not. //------------------------------------------------------------------- BOOL NEAR PASCAL CloseQueue(LPSI lpsi, BOOL bSuccessSoFar, BOOL bOpened) { BOOL bSuccess = FALSE; if (! bOpened) bSuccess = bSuccessSoFar; else { if (! bSuccessSoFar) VcpClose(VCPFL_ABANDON, NULL); else if (lpsi->bDontQueueFiles) { VcpClose(VCPFL_ABANDON, NULL); bSuccess=TRUE; } // The queue is now closed, so clear lpsi->lpVcpInfo if (lpsi->lpVcpInfo) lpsi->lpVcpInfo = NULL; } return bSuccess; } //----------------------------------------------------------------------- // Function: WrapVcpCopy(lpsi,lpfnQueueFunction,lpdn) // // Action: Wrap lpfnQueueFunction inside calls to open & close the // queue. If lpsi->bDontCopyFiles is TRUE, we'll close the // queue without copying anything. // // Return: TRUE if everything went smoothly, FALSE if not. //----------------------------------------------------------------------- BOOL WINAPI WrapVcpCopy(LPSI lpsi, LPQUEUEPROC lpfnQueueFunction, LPDRIVER_NODE lpdn) { VCPUIINFO VcpInfo; BOOL bSuccess=FALSE; BOOL bOpened=FALSE; if (OpenQueue(lpsi, &VcpInfo, &bOpened)) { BOOL bQueuedOK; bQueuedOK = lpfnQueueFunction(lpsi, lpdn); bSuccess = CloseQueue(lpsi, bQueuedOK, bOpened); } return bSuccess; } //-------------------------------------------------------------------- // Function: PrintLPSI(lpsi) // // Action: Print out the contents of the LPSI // // Side effect: None // // Return: VOID // //-------------------------------------------------------------------- VOID PrintLPSI(LPSI lpsi) { DBG_MSG(DBG_LEV_INFO, ("LPSI : dwDriverVersion : %#lX", (DWORD)lpsi->dwDriverVersion)); DBG_MSG(DBG_LEV_INFO, ("LPSI : dwUniqueID : %d" , lpsi->dwUniqueID)); DBG_MSG(DBG_LEV_INFO, ("LPSI : bNetPrinter : %d" , lpsi->bNetPrinter)); DBG_MSG(DBG_LEV_INFO, ("LPSI : wFilesUsed : %d" , lpsi->wFilesUsed)); DBG_MSG(DBG_LEV_INFO, ("LPSI : wFilesAllocated : %d" , lpsi->wFilesAllocated)); DBG_MSG(DBG_LEV_INFO, ("LPSI : wRetryTimeout : %d" , lpsi->wRetryTimeout)); DBG_MSG(DBG_LEV_INFO, ("LPSI : wDNSTimeout : %d" , lpsi->wDNSTimeout)); DBG_MSG(DBG_LEV_INFO, ("LPSI : bDontQueueFiles : %d" , lpsi->bDontQueueFiles)); DBG_MSG(DBG_LEV_INFO, ("LPSI : bNoTestPage : %d" , lpsi->bNoTestPage)); DBG_MSG(DBG_LEV_INFO, ("LPSI : hModelInf : %0X" , lpsi->hModelInf)); DBG_MSG(DBG_LEV_INFO, ("LPSI : lpPrinterInfo2 : %d" , lpsi->lpPrinterInfo2)); DBG_MSG(DBG_LEV_INFO, ("LPSI : lpDriverInfo3 : %d" , lpsi->lpDriverInfo3)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szFriendly : %s" , lpsi->szFriendly)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szModel : %s" , lpsi->szModel)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szDefaultDataType : %s" , lpsi->szDefaultDataType)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szBinName : %s" , lpsi->BinName)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szShareName : %s" , lpsi->ShareName)); DBG_MSG(DBG_LEV_INFO, ("LPSI : INFfileName : %s" , lpsi->INFfileName)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szPort : %s" , lpsi->szPort)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szDriverFile : %s" , lpsi->szDriverFile)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szDataFile : %s" , lpsi->szDataFile)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szConfigFile : %s" , lpsi->szConfigFile)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szHelpFile : %s" , lpsi->szHelpFile)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szPrintProcessor : %s" , lpsi->szPrintProcessor)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szVendorSetup : %s" , lpsi->szVendorSetup)); DBG_MSG(DBG_LEV_INFO, ("LPSI : szVendorInstaller : %s" , lpsi->szVendorInstaller)); } //----------------------------------------------------------------------- // Function: FindSelectedDriver(lpsi, lpdn) // // Action: Try to find the install section associated with the specified // model. If the currently selected driver matches the model, we // get all the required info from it. // // Note: Upon entry // lpdn->lpszSectionName // has the name of the correct section in the INF file. // // Return: TRUE is successful, FALSE if not. //----------------------------------------------------------------------- BOOL WINAPI FindSelectedDriver( LPSI lpsi, LPDRIVER_NODE lpdn) { HINFLINE hInfDummy; HINF myHINF; WORD wTest; BOOL bDataSection=FALSE; BOOL bQueuedOK; char szData[_MAX_PATH_]; char szTimeout[10]; char lpSection[_MAX_PATH_]; // Extract all of our information from the INF file. // Open the INF file. if (OK != IpOpen(lpsi->INFfileName, &myHINF)) { return FALSE; } lstrcpyn(lpSection, lpdn->lpszSectionName, _MAX_PATH_); if (OK != IpFindFirstLine(myHINF, lpSection, NULL, &hInfDummy)) { IpClose(myHINF); return FALSE; } lpsi->hModelInf = (int) myHINF; // Build the dependent file list now. lpsi->bDontQueueFiles=TRUE; bQueuedOK = WrapVcpCopy(lpsi,QueueNewInf,lpdn); lpsi->bDontQueueFiles = FALSE; if (!bQueuedOK) { IpClose(myHINF); lpsi->hModelInf = 0; return FALSE; } if (!lpsi->wFilesUsed) { IpClose(myHINF); lpsi->hModelInf = 0; return FALSE; } // Check for a data section. If none is specified, then the // data section is the section associated with this device. // The DataSection key can only appear in the installer section // (for obvious reasons). bDataSection=GetInfOption(myHINF,lpSection,FALSE,FALSE,NULL, cszDataSection,szData,sizeof(szData)); // Don't change szData below this line! (It may contain the // data section name) // Get the driver name (default is the primary section name) if (!GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszDriverFile,lpsi->szDriverFile,sizeof(lpsi->szDriverFile))) { lstrcpyn(lpsi->szDriverFile,lpSection,sizeof(lpsi->szDriverFile)); } // Get the data file name (default is the primary section name) if (!GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszDataFile,lpsi->szDataFile,sizeof(lpsi->szDataFile))) { lstrcpyn(lpsi->szDataFile,lpSection,sizeof(lpsi->szDataFile)); } // Get the config file name (default is the driver name) if (!GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszConfigFile,lpsi->szConfigFile,sizeof(lpsi->szConfigFile))) { lstrcpyn(lpsi->szConfigFile,lpsi->szDriverFile, sizeof(lpsi->szConfigFile)); } // Get the help file (default is none) GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszHelpFile,lpsi->szHelpFile,sizeof(lpsi->szHelpFile)); // Get the Print Processor (default comes from resources) if (!GetInfOption(myHINF,lpSection,bDataSection,TRUE,szData, cszPrintProcessor,lpsi->szPrintProcessor, sizeof(lpsi->szPrintProcessor))) { if (LoadString(g_hInst,IDS_DEFAULT_PRINTPROCESSOR, lpsi->szPrintProcessor,sizeof(lpsi->szPrintProcessor)) IS 0) { DBG_MSG(DBG_LEV_INFO, ("FindSelectedDriver : Could not load string, default print processor")); lstrcpy(lpsi->szPrintProcessor, cszDefaultPrintProcessor); } } // Get the Default Data Type (default comes from resources) if (!GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszDefaultDataType,lpsi->szDefaultDataType, sizeof(lpsi->szDefaultDataType))) { if ( LoadString(g_hInst,IDS_DEFAULT_DATATYPE, lpsi->szDefaultDataType,sizeof(lpsi->szDefaultDataType)) IS 0) { DBG_MSG(DBG_LEV_INFO, ("FindSelectedDriver : Could not load string, default data type")); lstrcpy(lpsi->szDefaultDataType, cszMSDefaultDataType); } } // Get the Vendor Setup (default is none) GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszVendorSetup,lpsi->szVendorSetup,sizeof(lpsi->szVendorSetup)); // Get the Vendor Installer (default is none) GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszVendorInstaller,lpsi->szVendorInstaller, sizeof(lpsi->szVendorInstaller)); // Get the device timeouts (ClearPrinterInfo defaults to 15 & 45) if (GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszRetryTimeout,szTimeout,sizeof(szTimeout))) { if (wTest=myatoi(szTimeout)) lpsi->wRetryTimeout=wTest; } if (GetInfOption(myHINF,lpSection,bDataSection,FALSE,szData, cszNotSelectedTimeout,szTimeout,sizeof(szTimeout))) { if (wTest=myatoi(szTimeout)) lpsi->wDNSTimeout=wTest; } // Decide whether or not we should use the test page. Test page is // skipped if the INF specifically requests it, if we have a // vendor-supplied DLL, or if the port is in conflict. if ( (lpsi->szVendorSetup[0]) || (lpsi->szVendorInstaller[0]) || GetInfOption(myHINF, lpSection, bDataSection, FALSE, szData, cszNoTestPage, szTimeout, sizeof(szTimeout))) { lpsi->bNoTestPage=TRUE; } IpClose(myHINF); lpsi->hModelInf = 0; return TRUE; } //-------------------------------------------------------------------- // Function: CreateDriverNode() // // Action: Create a driver node and initialize it.. // // Side effect: Allocates memory that must be freed by caller.. // // Return: RET_OK on success. // //-------------------------------------------------------------------- RETERR WINAPI CreateDriverNode( LPLPDRIVER_NODE lplpdn, UINT Rank, UINT InfType, unsigned InfDate, LPCSTR lpszDevDescription, LPCSTR lpszDrvDescription, LPCSTR lpszProviderName, LPCSTR lpszMfgName, LPCSTR lpszInfFileName, LPCSTR lpszSectionName, DWORD dwPrivateData) { int DrvDescLen = 0; int DevDescLen = 0; int SectionLen = 0; LPSTR lpszTemp; // Compute a allocate space for the variable part of the DRIVER node // DrvDescLen = lstrlen(lpszDrvDescription); DevDescLen = lstrlen(lpszDevDescription); SectionLen = lstrlen(lpszSectionName); *lplpdn = (LPDRIVER_NODE) HP_GLOBAL_ALLOC_DLL(sizeof(DRIVER_NODE) + DrvDescLen + DevDescLen + SectionLen + (2 * MAX_DEVICE_ID_LEN) + _MAX_PATH_ + NSTRINGS); if (*lplpdn == NULL) { return(ERR_DI_LOW_MEM); } else { (*lplpdn)->Rank = Rank; (*lplpdn)->InfType = InfType; (*lplpdn)->InfDate = InfDate; // For compatibility copy the DevDescription into lpszDescription lpszTemp = (LPSTR)((DWORD)(*lplpdn) + sizeof(DRIVER_NODE)); lstrcpy(lpszTemp, lpszDevDescription); (*lplpdn)->lpszDescription = lpszTemp; // New. Copy the Drv description into the lpszDrvDescription lpszTemp = (LPSTR)((DWORD)(lpszTemp) + (DWORD)(DevDescLen + 1)); lstrcpy(lpszTemp, lpszDevDescription); (*lplpdn)->lpszDrvDescription = lpszTemp; lpszTemp = (LPSTR)((DWORD)(lpszTemp) + (DWORD)(DrvDescLen + 1)); lstrcpy(lpszTemp, lpszSectionName); (*lplpdn)->lpszSectionName = lpszTemp; // Init HardwareID and CompatIDs buffers to empty strings lpszTemp = (LPSTR)((DWORD)(lpszTemp) + (DWORD)(SectionLen + 1)); *lpszTemp = '\0'; (*lplpdn)->lpszHardwareID = lpszTemp; lpszTemp = (LPSTR)((DWORD)(lpszTemp) + (DWORD)(MAX_DEVICE_ID_LEN + 1)); *lpszTemp = '\0'; (*lplpdn)->lpszCompatIDs = lpszTemp; (*lplpdn)->atInfFileName = GlobalAddAtom(lpszInfFileName); if (lpszMfgName != NULL) { (*lplpdn)->atMfgName = GlobalAddAtom(lpszMfgName); } if (lpszProviderName != NULL) { (*lplpdn)->atProviderName = GlobalAddAtom(lpszProviderName); } return(RET_OK); } } //-------------------------------------------------------------------- // // Function: HaveAllFiles(lpsi) // // Action: Do we have all printer driver dependent files in this directory? // // Return: TRUE if all found, FALSE if not // //-------------------------------------------------------------------- BOOL WINAPI HaveAllFiles(LPSI lpsi, LPSTR cszPath) { int result; LPSTR lpThisFile; struct stat statBuf; char fileSpec[_MAX_PATH_]; BOOL fileNotFound = FALSE; // Verify that all the dependent files are in the directory // pointed to by cszPath. // for (lpThisFile = (char *)lpsi->lpFiles; *lpThisFile; lpThisFile += (lstrlen(lpThisFile) + 1)) { // Get data associated with file lstrcpy(fileSpec, cszPath); lstrcat(fileSpec, cszBackslash); lstrcat(fileSpec, lpThisFile); result = stat( fileSpec, (struct stat *)&statBuf); // Check if statistics are valid: if ( result ISNT 0 ) { DBG_MSG(DBG_LEV_INFO, ("HaveAllFiles : File not found <%s>", fileSpec)); fileNotFound = TRUE; break; } } return !fileNotFound; } //-------------------------------------------------------------------- // // Function: CopyNeededFiles(lpsi, cszPath) // // Action: Copy all printer driver files for this printer from the // source directory to the requied printer driver directory. // // Return: RET_OK on success. // RET_FILE_COPY_ERROR is there is a file copy error // //-------------------------------------------------------------------- DWORD WINAPI CopyNeededFiles(LPSI lpsi, LPSTR cszPath) { DWORD dwResult = RET_OK; LONG lResult; LPSTR lpThisFile; OFSTRUCT ofStrSrc; OFSTRUCT ofStrDest; HFILE hfSrcFile, hfDstFile; char fileSource[_MAX_PATH_]; char fileDest[_MAX_PATH_]; char destDir[_MAX_PATH_]; DBG_MSG(DBG_LEV_INFO, ("CopyNeededFiles : About to flush printer files")); lstrcpy(destDir, lpsi->szDriverDir); if (lstrcmpi(destDir, cszPath) IS 0) { // all required files are in the destination directory // return RET_OK; } // Flush any cached files the system may be holding // FlushCachedPrinterFiles(); LZStart(); for (lpThisFile = (char *)lpsi->lpFiles; *lpThisFile; lpThisFile += (lstrlen(lpThisFile) + 1)) { lstrcpy(fileSource, cszNull); lstrcat(fileSource, cszPath); lstrcat(fileSource, cszBackslash); lstrcat(fileSource, lpThisFile); lstrcpy(fileDest, cszNull); lstrcat(fileDest, destDir); lstrcat(fileDest, cszBackslash); lstrcat(fileDest, lpThisFile); lResult = -1; if (hfSrcFile = LZOpenFile(fileSource, &ofStrSrc, OF_READ)) { if (hfDstFile = LZOpenFile(fileDest, &ofStrDest, OF_CREATE)) { #if 0 lResult = CopyLZFile(hfSrcFile, hfDstFile); #else // Hack. If spooler has a file locked, then this call // would fail resulting in the class-installer being called // to copy the files. But for some reason, the class-installer // prompts a path-dialog wanting to know where the files // are. Several attempts at fixing up the device-info // struct with path-information failed to remedy this // situation. Therefore, for now, we will prevent this // CopyLZFile() from returning error to keep away from // the class-installer until this problem can be figured // out. // // See the caller of this routine to see how the class- // installer is called. // CopyLZFile(hfSrcFile, hfDstFile); lResult = 0; #endif LZClose(hfDstFile); } else { DBG_MSG(DBG_LEV_INFO, ("CopyNeededFiles : Could not create dst-file <%s>", fileDest)); } LZClose(hfSrcFile); } else { DBG_MSG(DBG_LEV_INFO, ("CopyNeededFiles : Could not create src-file <%s>", fileSource)); } if (lResult < 0) { dwResult = RET_FILE_COPY_ERROR; break; } } LZDone(); return dwResult; } //-------------------------------------------------------------------- // Function: ParseINF16(LPSI) // // Action: Parse the INF file and store required info in LPSI. // // Return: RET_OK on success. // RET_SECT_NOT_FOUND if no install section for this model // RET_DRIVER_NODE_ERROR if memory error // RET_INVALID_INFFILE other problem with INF file // //-------------------------------------------------------------------- RETERR FAR PASCAL ParseINF16(LPSI lpsi) { RETERR ret = RET_OK; LPDRIVER_NODE lpdn = NULL; char szManufacturer[_MAX_PATH_]; char szSection[_MAX_PATH_]; char cszPath[_MAX_PATH_]; // Get the manufacturer // lstrcpyn(szManufacturer,lpsi->szModel,sizeof(szManufacturer)); lstrtok(szManufacturer,cszSpace); DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : Search inf<%s> mfg<%s> model<%s>", lpsi->INFfileName, szManufacturer, lpsi->szModel)); // Get the correct section name if (!FindCorrectSection(lpsi->INFfileName, szManufacturer, lpsi->szModel, szSection)) { if (lstrcmpi(szManufacturer, "HP") IS 0) { lstrcpy(szManufacturer, "Hewlett-Packard"); if (!FindCorrectSection(lpsi->INFfileName, szManufacturer, lpsi->szModel, szSection)) { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : FindCorrectSection Failed")); return RET_SECT_NOT_FOUND; } else { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : FindCorrectSection Succeeded")); } } else { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : FindCorrectSection Failed")); return RET_SECT_NOT_FOUND; } } else { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : FindCorrectSection Succeeded")); } // Create a driver node // if (RET_OK != CreateDriverNode(&lpdn, 0, INFTYPE_TEXT, NULL, lpsi->szModel, cszNull, cszNull, szManufacturer, lpsi->INFfileName, szSection, 0)) { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : CreateDriverNode Failed")); return RET_DRIVER_NODE_ERROR; } else { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : CreateDriverNode Succeeded")); } // Find the selected driver and dependent files in the INF. Store in lpsi. // if (! FindSelectedDriver(lpsi, lpdn)) { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : FindSelectedDriver Failed")); if (lpdn->atInfFileName ISNT 0) GlobalDeleteAtom(lpdn->atInfFileName); if (lpdn->atMfgName ISNT 0) GlobalDeleteAtom(lpdn->atMfgName); if (lpdn->atProviderName ISNT 0) GlobalDeleteAtom(lpdn->atProviderName); HP_GLOBAL_FREE(lpdn); return RET_INVALID_INFFILE; } else { DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : FindSelectedDriver Succeeded")); } // If there is not a driver already installed for this printer, // Copy the driver files to the driver directory. if (lpsi->wCommand IS CMD_INSTALL_DRIVER) { if ( getcwd(cszPath, _MAX_PATH_) IS NULL) lstrcpy(cszPath, "."); if ((HaveAllFiles(lpsi, cszPath) IS TRUE) AND (CopyNeededFiles(lpsi, cszPath) IS RET_OK) ) { // We have all the needed files in the directory pointed to by cszPath. // They have been copied to the printer driver directory. ret = RET_OK; DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : All files copied to final directory")); } else { #define HKEY_LOCAL_MACHINE (( HKEY ) 0x80000002 ) DEVICE_INFO *lpdi; ret = DiCreateDeviceInfo(&lpdi, lpsi->szModel, 0, HKEY_LOCAL_MACHINE, NULL, "Printer", NULL); // Install the driver files. This will only copy files that // need to be copied. // if (ret IS OK) { LPDRIVER_NODE oldDN = NULL; oldDN = lpdi->lpSelectedDriver; lpdi->lpSelectedDriver = lpdn; ret = DiCallClassInstaller(DIF_INSTALLDEVICEFILES, lpdi); lpdi->lpSelectedDriver = oldDN; oldDN = NULL; DiDestroyDeviceInfoList(lpdi); lpdi = NULL; } switch (ret) { case OK: case ERR_DI_NOFILECOPY: ret = RET_OK; break; case ERR_DI_USER_CANCEL: ret = RET_USER_CANCEL; break; case ERR_DI_LOW_MEM: ret = RET_ALLOC_ERR; break; case ERR_DI_BAD_INF: ret = RET_INVALID_INFFILE; break; case ERR_DI_INVALID_DEVICE_ID: case ERR_DI_INVALID_COMP_DEVICE_LIST: case ERR_DI_REG_API: // Error returned by Reg API. case ERR_DI_BAD_DEV_INFO: // Device Info struct invalid case ERR_DI_INVALID_CLASS_INSTALLER: // Registry entry / DLL invalid case ERR_DI_DO_DEFAULT: // Take default action case ERR_DI_BAD_CLASS_INFO: // Class Info Struct invalid case ERR_DI_BAD_MOVEDEV_PARAMS: // Bad Move Device Params struct case ERR_DI_NO_INF: // No INF found on OEM disk case ERR_DI_BAD_PROPCHANGE_PARAMS: // Bad property change param struct case ERR_DI_BAD_SELECTDEVICE_PARAMS: // Bad Select Device Parameters case ERR_DI_BAD_REMOVEDEVICE_PARAMS: // Bad Remove Device Parameters case ERR_DI_BAD_ENABLECLASS_PARAMS: // Bad Enable Class Parameters case ERR_DI_FAIL_QUERY: // Fail the Enable Class query case ERR_DI_API_ERROR: // DI API called incorrectly case ERR_DI_BAD_PATH: // An OEM path was specified incorrectly default: ret = RET_BROWSE_ERROR; break; } DBG_MSG(DBG_LEV_INFO, ("ParseINF16 : DiCallClassInstaller %s", (ret IS OK ? "succeded" : "failed"))); } } // if wCommand IS CMD_INSTALL_DRIVER // We don't need the driver node anymore // Clean up and delete // if (lpdn->atInfFileName ISNT 0) GlobalDeleteAtom(lpdn->atInfFileName); if (lpdn->atMfgName ISNT 0) GlobalDeleteAtom(lpdn->atMfgName); if (lpdn->atProviderName ISNT 0) GlobalDeleteAtom(lpdn->atProviderName); HP_GLOBAL_FREE(lpdn); return ret; } /*****************************************************************************\ * LibMain * * Entry-point initialization. * \*****************************************************************************/ #if 0 int CALLBACK LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine) { g_hInst = NULL; g_hInst = (HINSTANCE) hModule; return 1; } #else BOOL FAR PASCAL LibMain( HANDLE hInst, int nAttach, LPVOID pContext) { if (g_hInst == NULL) { g_hInst = (HINSTANCE)hInst; if (InitStrings()) return thk_ThunkConnect16(cszDll16, cszDll32, hInst, 1); } return FALSE; } #endif /*****************************************************************************\ * Windows Exit Proceedure (WEP) * * \*****************************************************************************/ int CALLBACK WEP(int exportType) { FreeStrings(); return 1; }