//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: N U C O M P A T . C P P // // Contents: // // // Notes: // // Author: kumarp 04/12/97 17:17:27 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "comp.h" #include "conflict.h" #include "infmap.h" #include "kkstl.h" #include "kkutils.h" #include "ncsetup.h" #include "oemupg.h" #include "ncsvc.h" // ---------------------------------------------------------------------- // String constants const WCHAR sz_DLC[] = L"DLC"; #ifdef _X86_ #define NWC_PRINT_PROVIDER 101 #define MAX_BUF_SIZE 350 const WCHAR c_szNWCWorkstation[] = L"NWCWorkstation"; const WCHAR c_szNWCfgDll[] = L"System32\\nwcfg.dll"; const WCHAR c_szProviders[] = L"System\\CurrentControlSet\\Control\\Print\\Providers"; const WCHAR c_szNWCPrintProviderKey[] = L"System\\CurrentControlSet\\Control\\Print\\Providers\\Netware or Compatible Network"; const WCHAR c_szOrder[] = L"Order"; const WCHAR c_szTmpPrefix[] = L"$net"; const WCHAR c_szNWCSection[] = L"RenameNWCPrintProvider"; const WCHAR c_szUpdateProviderOrder[] = L"UpdateProvidersOrder"; const WCHAR c_szNWCDelReg[] = L"NWCProviderDelReg"; const WCHAR c_szNWCAddReg[] = L"NWCProviderAddReg"; const WCHAR c_szNWCPrintProviderName[] = L"Netware or Compatible Network"; const WCHAR c_szDefaultDisplayName[] = L"DisplayName"; const WCHAR c_szDefaultName[] = L"Name"; const WCHAR c_szDefaultameValue [] = L"nwprovau.dll"; static DWORD g_dwBytesWritten; static WCHAR g_buf[MAX_BUF_SIZE+1]; #endif const WCHAR c_szDefaultTextFile[] = L"winntupg\\unsupmsg.txt"; void GetHelpFile(IN PCWSTR pszPreNT5InfId, OUT tstring* pstrTextHelpFile, OUT tstring* pstrHtmlHelpFile); #ifdef _X86_ VOID FixNWClientPrinProviderName (PCOMPAIBILITYCALLBACK CompatibilityCallback, LPVOID Context); HRESULT DumpProvidersOrder (HANDLE hFile, LPWSTR lpszPrintProviderName); HRESULT DumpNWPrintProviderKey (HANDLE hFile, LPWSTR lpszPrintProviderName); BOOL IsNT4Upgrade (VOID); BOOL IsNetWareClientKeyLocalized (VOID); HRESULT GetNWPrintProviderName (LPWSTR *lppPrintProvider); #endif // ---------------------------------------------------------------------- // // Function: NetUpgradeCompatibilityCheck // // Purpose: This functions is called by winnt32.exe so that we // can scan the system to find any potential upgrade problems // // For each such problem-net-component found, we call // CompatibilityCallback to report it to winnt32 // // Arguments: // CompatibilityCallback [in] pointer to COMPAIBILITYCALLBACK fn // Context [in] pointer to compatibility context // // Returns: // // Author: kumarp 21-May-98 // // Notes: // BOOL WINAPI NetUpgradeCompatibilityCheck( PCOMPAIBILITYCALLBACK CompatibilityCallback, LPVOID Context) { DefineFunctionName("NetUpgradeCompatibilityCheck"); TraceTag(ttidNetUpgrade, "entering ---> %s", __FUNCNAME__); HRESULT hr=S_OK; TPtrList* plNetComponents; TPtrListIter pos; COMPATIBILITY_ENTRY ce; CNetComponent* pnc; DWORD dwError; hr = HrGetConflictsList(&plNetComponents); if (S_OK == hr) { tstring strHtmlHelpFile; tstring strTextHelpFile; for (pos = plNetComponents->begin(); pos != plNetComponents->end(); pos++) { pnc = (CNetComponent*) *pos; GetHelpFile(pnc->m_strPreNT5InfId.c_str(), &strTextHelpFile, &strHtmlHelpFile); // prepare the entry // ZeroMemory(&ce, sizeof(ce)); ce.Description = (PWSTR) pnc->m_strDescription.c_str(); ce.HtmlName = (PWSTR) strHtmlHelpFile.c_str(); ce.TextName = (PWSTR) strTextHelpFile.c_str(); ce.RegKeyName = NULL; ce.RegValName = NULL; ce.RegValDataSize = 0; ce.RegValData = 0; ce.SaveValue = (LPVOID) pnc; ce.Flags = COMPFLAG_USE_HAVEDISK; TraceTag(ttidNetUpgrade, "%s: calling CompatibilityCallback for '%S': %S, %S...", __FUNCNAME__, ce.Description, ce.HtmlName, ce.TextName); dwError = CompatibilityCallback(&ce, Context); TraceTag(ttidNetUpgrade, "...CompatibilityCallback returned 0x%x", dwError); } } else if (FAILED(hr)) { TraceTag(ttidNetUpgrade, "%s: HrGetConflictsList returned err code: 0x%x", __FUNCNAME__, hr); } #ifdef _X86_ // Raid Bug 327760: Change localized Netware Print Provider name to English. FixNWClientPrinProviderName( CompatibilityCallback, Context ); #endif return SUCCEEDED(hr); } // ---------------------------------------------------------------------- // // Function: NetUpgradeHandleCompatibilityHaveDisk // // Purpose: This callback function is called by winnt32.exe // if user clicks HaveDisk button on the compatibility // report page. // // Arguments: // hwndParent [in] handle of parent window // SaveValue [in] pointer to private data // (we store CNetComponent* in this pointer) // // Returns: // // Author: kumarp 21-May-98 // // Notes: // DWORD WINAPI NetUpgradeHandleCompatibilityHaveDisk(HWND hwndParent, LPVOID SaveValue) { DefineFunctionName("NetUpgradeHandleCompatibilityHaveDisk"); HRESULT hr=S_OK; BOOL fStatus = FALSE; DWORD dwStatus=ERROR_SUCCESS; CNetComponent* pnc=NULL; PCWSTR pszComponentDescription; static const WCHAR c_szNull[] = L""; if (SaveValue) { pnc = (CNetComponent*) SaveValue; pszComponentDescription = pnc->m_strDescription.c_str(); } else { pszComponentDescription = c_szNull; } TraceTag(ttidNetUpgrade, "%s: called for %S...", __FUNCNAME__, pszComponentDescription); if (pnc) { tstring strOemDir; hr = HrShowUiAndGetOemFileLocation(hwndParent, pszComponentDescription, &strOemDir); if (S_OK == hr) { hr = HrProcessAndCopyOemFiles(strOemDir.c_str(), TRUE); } } else { hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } TraceErrorOptional(__FUNCNAME__, hr, (S_FALSE == hr)); if (S_FALSE == hr) { // this will ensure that winnt32 will not take this item // off the compatibility list // dwStatus = ERROR_FILE_NOT_FOUND; } else { dwStatus = DwWin32ErrorFromHr(hr); } return dwStatus; } // ---------------------------------------------------------------------- // // Function: GetHelpFile // // Purpose: Get name of help file for an unsupported component // // Arguments: // hinfNetUpg [in] handle of netupg.inf // pszPreNT5InfId [in] pre-NT5 InfId // pstrTextHelpFile [out] name of the text file found // pstrHtmlHelpFile [out] name of the html file found // // Returns: None // // Author: kumarp 22-May-98 // // Notes: // void GetHelpFile(IN PCWSTR pszPreNT5InfId, OUT tstring* pstrTextHelpFile, OUT tstring* pstrHtmlHelpFile) { // Known txt/htm files if (lstrcmpiW(pszPreNT5InfId, sz_DLC) == 0) { *pstrTextHelpFile = L"compdata\\dlcproto.txt"; *pstrHtmlHelpFile = L"compdata\\dlcproto.htm"; return; } // Unknown or OEM files static const WCHAR c_szOemUpgradeHelpFiles[] = L"OemUpgradeHelpFiles"; static const WCHAR c_szDefaultHtmlFile[] = L"winntupg\\unsupmsg.htm"; HRESULT hr=S_OK; INFCONTEXT ic; tstring strText; tstring strHtml; tstring strNT5InfId; BOOL fIsOemComponent=FALSE; CNetMapInfo* pnmi=NULL; *pstrTextHelpFile = c_szDefaultTextFile; *pstrHtmlHelpFile = c_szDefaultHtmlFile; hr = HrMapPreNT5NetComponentInfIDToNT5InfID(pszPreNT5InfId, &strNT5InfId, &fIsOemComponent, NULL, &pnmi); if ((S_FALSE == hr) && !strNT5InfId.empty()) { hr = HrSetupFindFirstLine(pnmi->m_hinfNetMap, c_szOemUpgradeHelpFiles, strNT5InfId.c_str(), &ic); if (S_OK == hr) { hr = HrSetupGetStringField(ic, 1, &strText); if (S_OK == hr) { hr = HrSetupGetStringField(ic, 2, &strHtml); if (S_OK == hr) { *pstrTextHelpFile = pnmi->m_strOemDir; *pstrHtmlHelpFile = pnmi->m_strOemDir; AppendToPath(pstrTextHelpFile, strText.c_str()); AppendToPath(pstrHtmlHelpFile, strHtml.c_str()); } } } } } #ifdef _X86_ // ---------------------------------------------------------------------- // // Function: FixNWClientPrinProviderName // // Purpose: Change the localized Print Provider name to English. // // Arguments: // // Returns: None // // Author: asinha 14-June-01 // // Notes: // VOID FixNWClientPrinProviderName (PCOMPAIBILITYCALLBACK CompatibilityCallback, LPVOID Context) { DefineFunctionName( "FixNWClientPrinProviderName" ); TraceTag(ttidNetUpgrade, "entering ---> %s", __FUNCNAME__); LPWSTR lpszPrintProviderName; WCHAR lpTmpFile[MAX_PATH+1]; WCHAR lpTmpPath[MAX_PATH+1]; HANDLE hFile; DWORD dwChars; COMPATIBILITY_ENTRY ce; BOOL bRet; HRESULT hr=S_OK; // // Is it an upgrade from NT 4.0 and the Netware print provider name localized? // if ( IsNT4Upgrade() && IsNetWareClientKeyLocalized() ) { TraceTag( ttidNetUpgrade, "%s: Netware Print Provider name is localized.", __FUNCNAME__ ); // Get the localized Netware print provider name from nwcfg.dll. hr = GetNWPrintProviderName( &lpszPrintProviderName ); if ( hr == S_OK ) { TraceTag( ttidNetUpgrade, "%s: Netware Print Provider name is: %S", __FUNCNAME__, lpszPrintProviderName ); // Create a .tmp filename where INF directives are written to rename // the print provider name into English. This INF file will be executed // by base setup in GUI mode. // GetTempPathW( MAX_PATH, lpTmpPath ); if ( GetTempFileNameW( lpTmpPath, c_szTmpPrefix, 1, lpTmpFile) ) { hFile = CreateFileW( lpTmpFile, GENERIC_WRITE | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile != INVALID_HANDLE_VALUE ) { // Write the initial entries. dwChars = wsprintfW( g_buf, L"[Version]\r\n" L"Signature=\"$WINDOWS NT$\"\r\n" L"Provider=Microsoft\r\n" L"LayoutFile=layout.inf\r\n\r\n" L"[%s]\r\n" L"AddReg=%s\r\n" L"DelReg=%s\r\n" L"AddReg=%s\r\n", c_szNWCSection, c_szUpdateProviderOrder, c_szNWCDelReg, c_szNWCAddReg ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); // Write the HKLM\System\CCS\Control\Print\Providers\Order values. hr = DumpProvidersOrder( hFile, lpszPrintProviderName ); if ( hr == S_OK ) { // Write addreg/delreg directives to change the Print Provider name hr = DumpNWPrintProviderKey( hFile, lpszPrintProviderName ); if ( hr == S_OK ) { CloseHandle( hFile ); hFile = INVALID_HANDLE_VALUE; // Call the compatibility callback so the %temp%\$ne1.tmp INF file // is executed in GUI mode setup. ZeroMemory( &ce, sizeof(ce) ); ce.Description = (PWSTR)c_szNWCPrintProviderName; ce.TextName = (PWSTR)c_szDefaultTextFile; ce.InfName = (PWSTR)lpTmpFile; ce.InfSection = (PWSTR)c_szNWCSection; ce.Flags = COMPFLAG_HIDE; TraceTag(ttidNetUpgrade, "%s: calling CompatibilityCallback for '%S'...", __FUNCNAME__, ce.Description ); bRet = CompatibilityCallback( &ce, Context ); TraceTag( ttidNetUpgrade, "...CompatibilityCallback returned %#x", bRet ); } } if ( hFile != INVALID_HANDLE_VALUE ) { CloseHandle( hFile ); } } else { TraceTag( ttidNetUpgrade, "%s: Failed to open %S.", __FUNCNAME__, lpTmpFile ); hr = HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED); } } else { hr = HRESULT_FROM_WIN32(GetLastError()); TraceTag( ttidNetUpgrade, "%s: GetTempFileName failed, path=%S, prefix=%S: Error=%#x", __FUNCNAME__, lpTmpPath, c_szTmpPrefix, hr ); } MemFree( lpszPrintProviderName ); } else { TraceTag( ttidNetUpgrade, "%s: GetNWPrintProviderName returned error : %#x", __FUNCNAME__, hr ); } } TraceTag(ttidNetUpgrade, "<---%s: hr = %#x", __FUNCNAME__, hr); return; } // Write addreg to update HKLM\System\CCS\Control\Print\Order value with the Netware Print Provider // in English. HRESULT DumpProvidersOrder (HANDLE hFile, LPWSTR lpszPrintProviderName) { DefineFunctionName( "DumpProvidersOrder" ); TraceTag(ttidNetUpgrade, "entering ---> %s", __FUNCNAME__); HKEY hkeyProviders; DWORD dwValueLen; LPWSTR lpValue; LPWSTR lpTemp; DWORD dwChars; LONG lResult; dwChars = wsprintfW( g_buf, L"\r\n[%s]\r\n", c_szUpdateProviderOrder ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); lResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, c_szProviders, 0, KEY_READ, &hkeyProviders ); if ( lResult == ERROR_SUCCESS ) { // First query how many bytes are needed to read the value. lResult = RegQueryValueExW( hkeyProviders, // handle to key c_szOrder, // value name NULL, // reserved NULL, // type buffer NULL, // data buffer &dwValueLen ); // size of data buffer if ( lResult == ERROR_SUCCESS ) { lpValue = (LPWSTR)MemAlloc( dwValueLen ); if ( lpValue ) { // Read the old value which is a multi_sz. lResult = RegQueryValueExW( hkeyProviders, // handle to key c_szOrder, // value name NULL, // reserved NULL, // type buffer (LPBYTE)lpValue,// data buffer &dwValueLen ); // size of data buffer if ( lResult == ERROR_SUCCESS ) { lpTemp = lpValue; dwChars = wsprintfW( g_buf, L"HKLM,\"%s\",\"%s\",0x00010020", c_szProviders, c_szOrder ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); // Write each print provider name. while( *lpTemp ) { // If we find a localized one then, we write its English name. if ( _wcsicmp( lpTemp, lpszPrintProviderName) != 0 ) { dwChars = wsprintfW( g_buf, L",\"%s\"", lpTemp ); Assert( dwChars <= MAX_BUF_SIZE ); TraceTag( ttidNetUpgrade, "%s: Writing print provider name %S.", __FUNCNAME__, lpTemp ); } else { dwChars = wsprintfW( g_buf, L",\"%s\"", c_szNWCPrintProviderName ); Assert( dwChars <= MAX_BUF_SIZE ); TraceTag( ttidNetUpgrade, "%s: Writing print provider name %S.", __FUNCNAME__, c_szNWCPrintProviderName ); } WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); // Get next print provider name. lpTemp += lstrlenW( lpTemp ) + 1; } dwChars = wsprintfW( g_buf, L"\r\n" ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); } else { TraceTag( ttidNetUpgrade, "%s: RegQueryValueExW failed to open '%S' value, Error: %#x", c_szOrder, HRESULT_FROM_WIN32(lResult) ); } MemFree( lpValue ); } else { lResult = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } } else { TraceTag(ttidNetUpgrade, "RegQueryValueExW failed to open '%S' value, Error: %#x", __FUNCNAME__, c_szOrder, HRESULT_FROM_WIN32(lResult) ); } RegCloseKey( hkeyProviders ); } else { TraceTag(ttidNetUpgrade, "%s: RegOpenKeyExW failed to open '%S' key, Error: %#x", __FUNCNAME__, c_szProviders, HRESULT_FROM_WIN32(lResult) ); } TraceTag(ttidNetUpgrade, "<---%s: hr = %#x", __FUNCNAME__, HRESULT_FROM_WIN32(lResult)); return HRESULT_FROM_WIN32(lResult); } // Write delreg/addreg directives to rename the Netware PrintProvider name into English. HRESULT DumpNWPrintProviderKey (HANDLE hFile, LPWSTR lpszPrintProviderName) { DefineFunctionName( "DumpNWPrintProviderKey" ); TraceTag(ttidNetUpgrade, "entering ---> %s", __FUNCNAME__); HKEY hkeyNWPrinProvider; WCHAR szNWPrintProvider[MAX_PATH+1]; DWORD dwMaxValueNameLen; DWORD dwMaxValueLen; DWORD dwNameLen; DWORD dwValueLen; DWORD dwCount; DWORD i; DWORD dwChars; LPWSTR lpValueName; LPWSTR lpValue; LONG lResult; dwChars = wsprintfW( szNWPrintProvider, L"%s\\%s", c_szProviders, lpszPrintProviderName ); Assert( dwChars <= MAX_BUF_SIZE ); dwChars = wsprintfW( g_buf, L"\r\n[%s]\r\n" L"HKLM,\"%s\"\r\n", c_szNWCDelReg, szNWPrintProvider ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); dwChars = wsprintfW( g_buf, L"\r\n[%s]\r\n", c_szNWCAddReg ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); // Open the localize Netware print provider key. lResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, szNWPrintProvider, 0, KEY_READ, &hkeyNWPrinProvider ); if ( lResult == ERROR_SUCCESS ) { // Find out the space needed for longest name and largest value and how many values. lResult = RegQueryInfoKeyW( hkeyNWPrinProvider, NULL, NULL, NULL, NULL, NULL, NULL, &dwCount, &dwMaxValueNameLen, &dwMaxValueLen, NULL, NULL ); if ( lResult == ERROR_SUCCESS ) { // Add some padding. dwMaxValueLen += 4; dwMaxValueNameLen += 4; lpValueName = (LPWSTR)MemAlloc( dwMaxValueNameLen * sizeof(WCHAR) ); lpValue = (LPWSTR)MemAlloc( dwMaxValueLen ); if ( lpValueName && lpValue ) { // Enumerate each value and write it to the INF file. for (i=0; i < dwCount; ++i) { dwNameLen = dwMaxValueNameLen; dwValueLen = dwMaxValueLen; lResult = RegEnumValueW(hkeyNWPrinProvider, i, lpValueName, &dwNameLen, NULL, NULL, (LPBYTE)lpValue, &dwValueLen ); Assert( lResult == ERROR_SUCCESS ); if ( lResult == ERROR_SUCCESS ) { dwChars = wsprintfW( g_buf, L"HKLM,\"%s\",\"%s\",,\"%s\"\r\n", c_szNWCPrintProviderKey, lpValueName, lpValue ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); TraceTag( ttidNetUpgrade, "%s: Writing value name %S, value %S", __FUNCNAME__, lpValueName, lpValue ); } else { TraceTag( ttidNetUpgrade, "%s: RegEnumValueW(%d) failed. Error: %#x", __FUNCNAME__, i, HRESULT_FROM_WIN32(lResult) ); } } lResult = ERROR_SUCCESS; } else { lResult = ERROR_NOT_ENOUGH_MEMORY; } if ( lpValueName ) { MemFree( lpValueName ); } if ( lpValue ) { MemFree( lpValue ); } } RegCloseKey( hkeyNWPrinProvider ); } else { // For some reason, we couldn't open the localized Netware Print Provider name. So, we // write the default values. // TraceTag(ttidNetUpgrade,"%s: RegOpenKeyExW failed to open '%S' key, Error: %#x", __FUNCNAME__, szNWPrintProvider, HRESULT_FROM_WIN32(lResult) ); dwChars = wsprintfW( g_buf, L"HKLM,\"%s\",\"%s\",,\"%s\"\r\n", c_szNWCPrintProviderKey, c_szDefaultDisplayName, lpszPrintProviderName ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); dwChars = wsprintfW( g_buf, L"HKLM,\"%s\",\"%s\",,\"%s\"\r\n", c_szNWCPrintProviderKey, c_szDefaultName, c_szDefaultameValue ); Assert( dwChars <= MAX_BUF_SIZE ); WriteFile( hFile, g_buf, dwChars * sizeof(WCHAR), &g_dwBytesWritten, NULL ); Assert( g_dwBytesWritten == (dwChars * sizeof(WCHAR)) ); lResult = ERROR_SUCCESS; } TraceTag(ttidNetUpgrade, "<---%s: hr = %#x", __FUNCNAME__, HRESULT_FROM_WIN32(lResult)); return HRESULT_FROM_WIN32(lResult); } BOOL IsNT4Upgrade (VOID) { OSVERSIONINFO osvi; ZeroMemory( &osvi, sizeof(OSVERSIONINFO) ); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if ( GetVersionEx(&osvi) ) { return ( (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && (osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0) ); } return TRUE; } // Determine if Netware print provider name is localized. BOOL IsNetWareClientKeyLocalized (VOID) { CServiceManager sm; CService srv; HKEY hKey; HRESULT hr; LONG lResult = ERROR_SUCCESS; // Is CSNW installed? if ( sm.HrOpenService(&srv, c_szNWCWorkstation) == S_OK ) { srv.Close(); // Open the Netware print provider name key assuming it is in English. lResult = RegOpenKeyExW( HKEY_LOCAL_MACHINE, c_szNWCPrintProviderKey, 0, KEY_READ, &hKey ); if ( lResult == ERROR_SUCCESS ) { RegCloseKey( hKey ); } } // If we successfully opened the key then, it is not localized. return lResult != ERROR_SUCCESS; } // Get the localized Netware Print provider name from nwcfg.dll. HRESULT GetNWPrintProviderName (LPWSTR *lppPrintProvider) { LPWSTR lpszNWCfgDll; int iLen; HMODULE hModule; WCHAR lpszNWCName[100]; DWORD dwLen; HRESULT hr; *lppPrintProvider = NULL; dwLen = GetWindowsDirectoryW( NULL, 0 ); if ( dwLen == 0 ) { return HRESULT_FROM_WIN32(GetLastError()); } lpszNWCfgDll = (LPWSTR)MemAlloc( (dwLen + celems(c_szNWCfgDll) + 2) * sizeof(WCHAR) ); if ( !lpszNWCfgDll ) { return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } if ( GetWindowsDirectoryW(lpszNWCfgDll, dwLen) == 0 ) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { if ( lpszNWCfgDll[dwLen-1] == L'\\' ) { lstrcatW( lpszNWCfgDll, c_szNWCfgDll ); } else { lstrcatW( lpszNWCfgDll, L"\\" ); lstrcatW( lpszNWCfgDll, c_szNWCfgDll ); } hModule = LoadLibraryExW( lpszNWCfgDll, NULL, LOAD_LIBRARY_AS_DATAFILE ); if ( hModule ) { iLen = LoadStringW( hModule, NWC_PRINT_PROVIDER, lpszNWCName, 100 ); if ( iLen > 0 ) { *lppPrintProvider = (LPWSTR)MemAlloc( (iLen + 1) * sizeof(WCHAR) ); lstrcpyW( *lppPrintProvider, lpszNWCName ); hr = S_OK; } else { hr = HRESULT_FROM_WIN32( GetLastError() ); } FreeLibrary( hModule ); } else { hr = HRESULT_FROM_WIN32( GetLastError() ); } } MemFree( lpszNWCfgDll ); return hr; } #endif