//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996. // // File: P R O V I D E R . C P P // // Contents: Net component installer functions for Net providers. // // Notes: // // Author: billbe 22 Mar 1997 // //--------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "ncreg.h" #include "ncsetup.h" #include "ncsvc.h" #include "provider.h" #include "winspool.h" #include "ncmisc.h" // constants // extern const WCHAR c_szDevice[]; extern const WCHAR c_szProviderOrder[]; extern const WCHAR c_szRegKeyCtlNPOrder[]; extern const WCHAR c_szRegKeyServices[]; const WCHAR c_chComma = L','; const WCHAR c_szDeviceName[] = L"DeviceName"; const WCHAR c_szDisplayName[] = L"DisplayName"; const WCHAR c_szInfKeyPrintProviderDll[] = L"PrintProviderDll"; const WCHAR c_szInfSubKeyPrintProvider[] = L"PrintProvider"; const WCHAR c_szNetworkProvider[] = L"NetworkProvider"; const WCHAR c_szPrintProviderName[] = L"PrintProviderName"; const WCHAR c_szRegKeyPrintProviders[] = L"System\\CurrentControlSet\\Control\\Print\\Providers"; const WCHAR c_szRegKeyShortName[] = L"System\\CurrentControlSet\\Control\\NetworkProvider\\ShortName"; const WCHAR c_szRegValueName[] = L"Name"; const WCHAR c_szRegValueOrder[] = L"Order"; const WCHAR c_szShortName[] = L"ShortName"; // Functions // HRESULT HrCiCreateShortNameValueIfNeeded(HINF hinf, HKEY hkeyNetworkProvider, const tstring& strSection, tstring* pstrShortName); HRESULT HrCiSetDeviceName(HINF hinf, HKEY hkeyNetworkProvider, const tstring& strSection, const tstring& strServiceName); HRESULT HrCiWritePrintProviderInfoIfNeeded(HINF hinfFile, const tstring& strSection, HKEY hkeyInstance, DWORD dwPrintPosition); HRESULT HrCiAddPrintProvider(const tstring& strName, const tstring& strDllName, const tstring& strDisplayName, DWORD dwPrintPosition); HRESULT HrCiDeletePrintProviderIfNeeded(HKEY hkeyInstance, DWORD* pdwProviderPosition); //+-------------------------------------------------------------------------- // // Function: HrCiAddNetProviderInfo // // Purpose: Adds the current component to the list of network // providers and also adds it as a print provider if // necessary. // // Arguments: // hinf [in] Handle to component's inf file // strSection [in] Main inf section // hkeyInstance [in] Component's instance key // fPreviouslyInstalled [in] TRUE if this component is being // reinstalled, FALSE otherwise // // Returns: HRESULT. S_OK if successful, an error code otherwise // // Author: billbe 22 Mar 1997 // updated 7 Oct 1997 // // Notes: // HRESULT HrCiAddNetProviderInfo(HINF hinf, PCWSTR pszSection, HKEY hkeyInstance, BOOL fPreviouslyInstalled) { Assert(IsValidHandle(hinf)); Assert(pszSection); Assert(hkeyInstance); //tstring strServiceName; DWORD dwNetworkPosition = 0; // default position is the front. DWORD dwPrintPosition = 0; // default position is the front. if (fPreviouslyInstalled) { // Because the inf may contain modifications to the print provider. // e.g. Display name change, dll name change, etc. We delete it // then readd. We would like to just update the information // but the print provider api doesn't support it yet. Until // then, we need to delete and readd to pick up changes. // (void) HrCiDeleteNetProviderInfo(hkeyInstance, &dwNetworkPosition, &dwPrintPosition); TraceTag(ttidClassInst, "Upgrading provider info. Net Prov Pos %d " "Print Prov Pos %d", dwNetworkPosition, dwPrintPosition); } // Get the service name for this component WCHAR szServiceName[MAX_SERVICE_NAME_LEN]; DWORD cbServiceName = MAX_SERVICE_NAME_LEN * sizeof(WCHAR); HKEY hkeyNdi; HRESULT hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi); if (S_OK == hr) { hr = HrRegQuerySzBuffer ( hkeyNdi, L"Service", szServiceName, &cbServiceName); RegCloseKey (hkeyNdi); } if (S_OK == hr) { // If this is Webclient we need to make sure it is after // lanmanworkstation in the ordering. This should be temporary // until mpr.dll is updated to return the union of provider // information. Right now a server can source smb shares and // webclient shares but only one set can be retrieved via the mpr. // Since smb shares are more common, lanmanworkstation needs to be // before webclient. When mpr.dll changes, both sets will be returned // and ordering shouldn't matter (expect for performance). // if (0 == lstrcmpiW(szServiceName, L"WebClient")) { HKEY hkeyNP; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyCtlNPOrder, KEY_READ, &hkeyNP); if (S_OK == hr) { PWSTR Order; hr = HrRegQuerySzWithAlloc(hkeyNP, c_szProviderOrder, &Order); if (S_OK == hr) { DWORD dwPosition; if (FFindStringInCommaSeparatedList(L"LanmanWorkstation", Order, NC_IGNORE, &dwPosition)) { dwNetworkPosition = dwPosition + 1; } delete [] Order; } RegCloseKey(hkeyNP); } } TraceTag(ttidClassInst, "Adding %S to the network provider " "order at position %d\n", szServiceName, dwNetworkPosition); // Add it to the list of network providers hr = HrRegAddStringToSz(szServiceName, HKEY_LOCAL_MACHINE, c_szRegKeyCtlNPOrder, c_szProviderOrder, c_chComma, STRING_FLAG_ENSURE_AT_INDEX, dwNetworkPosition); if (S_OK == hr) { tstring strNetworkProvider = c_szRegKeyServices; strNetworkProvider.append(L"\\"); strNetworkProvider.append(szServiceName); strNetworkProvider.append(L"\\"); strNetworkProvider.append(c_szNetworkProvider); // Open the NetworkProvider key under the component's // service key // HKEY hkey; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, strNetworkProvider.c_str(), KEY_SET_VALUE | KEY_READ, &hkey); if (S_OK == hr) { // Check if shortname is needed. // by looking for it in the option //
.NetworkProvider section // tstring strNetworkSection(pszSection); strNetworkSection += L'.'; strNetworkSection += c_szNetworkProvider; tstring strShortName; HRESULT hr = HrCiCreateShortNameValueIfNeeded(hinf, hkey, strNetworkSection, &strShortName); if (S_OK == hr) { // If shortname was created then we need to // also store it under the instance // key so we can remove it when the component // is removed (void) HrRegSetString(hkeyInstance, c_szShortName, strShortName); } // Set the device name in the NetworkProvider key // under the componet's service key // if (SUCCEEDED(hr)) { hr = HrCiSetDeviceName(hinf, hkey, strNetworkSection, szServiceName); } RegCloseKey(hkey); } } } // Write out any print provider information if the inf file specifies it // if (S_OK == hr) { hr = HrCiWritePrintProviderInfoIfNeeded(hinf, pszSection, hkeyInstance, dwPrintPosition); } TraceHr (ttidError, FAL, hr, FALSE, "HrCiAddNetProviderInfo"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiDeleteNetProviderInfo // // Purpose: Deletes the current component from the list of network // providers and also deletes it as a print provider if // necessary. // // Arguments: // hkeyInstance [in] The handle to the component's isntance key. // pdwNetworkPosition [out] Optional. The positon pf this component in // the network provider order before removal. // pdwPrintPosition [out] Optional. The positon of this component in // the print provider order before removal. // // Returns: HRESULT. S_OK if successful, an error code otherwise // // Author: billbe 22 Mar 1997 // updated 7 Oct 1997 // // Notes: // HRESULT HrCiDeleteNetProviderInfo(HKEY hkeyInstance, DWORD* pdwNetworkPosition, DWORD* pdwPrintPosition) { Assert(hkeyInstance); // Initialize out param. if (pdwNetworkPosition) { *pdwNetworkPosition = 0; } // Initialize out param. if (pdwPrintPosition) { *pdwPrintPosition = 0; } WCHAR szServiceName[MAX_SERVICE_NAME_LEN]; DWORD cbServiceName = MAX_SERVICE_NAME_LEN * sizeof(WCHAR); // Get the service name for this component. HKEY hkeyNdi; HRESULT hr = HrRegOpenKeyEx (hkeyInstance, L"Ndi", KEY_READ, &hkeyNdi); if (S_OK == hr) { hr = HrRegQuerySzBuffer ( hkeyNdi, L"Service", szServiceName, &cbServiceName); RegCloseKey(hkeyNdi); } if (S_OK == hr) { // Open the network provider key. // HKEY hkeyNetProvider; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyCtlNPOrder, KEY_READ_WRITE, &hkeyNetProvider); if (S_OK == hr) { PWSTR pszOrder = NULL; PWSTR pszNewOrder; DWORD dwNetPos; // Get the current list of providers. // hr = HrRegQuerySzWithAlloc(hkeyNetProvider, c_szProviderOrder, &pszOrder); // If we managed to get the list and the provider we are // removing is in the list... // if ((S_OK == hr) && FFindStringInCommaSeparatedList( szServiceName, pszOrder, NC_IGNORE, &dwNetPos)) { // Remove the provider from the list. hr = HrRemoveStringFromDelimitedSz(szServiceName, pszOrder, c_chComma, STRING_FLAG_REMOVE_ALL, &pszNewOrder); if (S_OK == hr) { // Set the new provider list back in the registry. (void) HrRegSetSz(hkeyNetProvider, c_szProviderOrder, pszNewOrder); MemFree (pszNewOrder); } // If the out param was specified, set the position. // if (pdwNetworkPosition) { *pdwNetworkPosition = dwNetPos; } } MemFree(pszOrder); RegCloseKey(hkeyNetProvider); } if (S_OK == hr) { // If short name was used, we need to remove it // tstring strShortName; hr = HrRegQueryString(hkeyInstance, c_szShortName, &strShortName); if (S_OK == hr) { // ShortName was used so remove it // HKEY hkey; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyShortName, KEY_SET_VALUE, &hkey); if (S_OK == hr) { hr = HrRegDeleteValue(hkey, strShortName.c_str()); // delete from our instance key as well // Note: we do this because if this component is being // reinstalled, the new inf might not have shortname so // we don't want the old value lying around (void) HrRegDeleteValue(hkeyInstance, c_szShortName); RegCloseKey(hkey); } } // If the value wasn't there (in the driver key or the ShortName key, // then there is nothing to delete and everything is okay if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { hr = S_OK; } } } // Delete this component as a print provider if necessary // if (S_OK == hr) { hr = HrCiDeletePrintProviderIfNeeded(hkeyInstance, pdwPrintPosition); } TraceHr (ttidError, FAL, hr, FALSE, "HrCiDeleteNetProviderInfo"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiCreateShortNameValueIfNeeded // // Purpose: Creates the short name value for the component under // the c_szRegKeyShortName registry key if short name is // present in the inf. The short name value is set to the // display name as found in the NetworkProvider key under // the component's service key // // Arguments: // hinf [in] Handle to the component's inf // hkeyNetworkProvider [in] The hkey to the NetworkProvider // key under the component's service // key // strSection [in] The section name where ShortName // would be located // pstrShortName [out] The short name found in the inf // // Returns: HRESULT. S_OK if shortname found, S_FALSE if no shortname was // found, or error code otherwise. // // Author: billbe 7 Oct 1997 // // Notes: // HRESULT HrCiCreateShortNameValueIfNeeded(HINF hinf, HKEY hkeyNetworkProvider, const tstring& strSection, tstring* pstrShortName) { Assert(IsValidHandle(hinf)); Assert(hkeyNetworkProvider); Assert(!strSection.empty()); Assert(pstrShortName); INFCONTEXT ctx; // Look for optional shortname HRESULT hr = HrSetupFindFirstLine(hinf, strSection.c_str(), c_szShortName, &ctx); if (SUCCEEDED(hr)) { // Get the shortname value hr = HrSetupGetStringField(ctx, 1, pstrShortName); if (SUCCEEDED(hr)) { HKEY hkey; // Create the ShortName key hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyShortName, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hkey, NULL); if (SUCCEEDED(hr)) { // Get the provider name to set the short name value // tstring strProviderName; hr = HrRegQueryString(hkeyNetworkProvider, c_szRegValueName, &strProviderName); if (SUCCEEDED(hr)) { // create the component's short name value under // the ShortName key and set it to the component's // display name hr = HrRegSetString(hkey, pstrShortName->c_str(), strProviderName); } RegCloseKey(hkey); } } } // The line and section were optional so if it didn't exists return S_FALSE if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_BAD_SECTION_NAME_LINE == hr)) { hr = S_FALSE; } // On failure, initialize the out param if (FAILED(hr)) { pstrShortName->erase(); } TraceHr (ttidError, FAL, hr, S_FALSE == hr, "HrCiCreateShortNameValueIfNeeded"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiSetDeviceName // // Purpose: Creates the device name value for the component under // the NetworkProvider key located in the component's // service key. The device name by default is // \Device\ unless the inf // specifies a new device name. // // Arguments: // hinf [in] Handle to the component's inf // hkeyNetworkProvider [in] The hkey to the NetworkProvider // key under the component's service // key // strSection [in] The section name where ShortName // would be located // strServiceName [in] The component's service name // // Returns: HRESULT. S_OK if successful, or error code otherwise. // // Author: billbe 7 Oct 1997 // // Notes: // HRESULT HrCiSetDeviceName(HINF hinf, HKEY hkeyNetworkProvider, const tstring& strSection, const tstring& strServiceName) { Assert(IsValidHandle(hinf)); Assert(hkeyNetworkProvider); INFCONTEXT ctx; tstring strDeviceName = c_szDevice; // Look for optional DeviceName HRESULT hr = HrSetupFindFirstLine(hinf, strSection.c_str(), c_szDeviceName, &ctx); if (SUCCEEDED(hr)) { tstring strName; // Get the DeviceName value hr = HrSetupGetStringField(ctx, 1, &strName); if (SUCCEEDED(hr)) { // append it to the current value strDeviceName.append(strName); } } // If the device name line was not found in the inf (or the // section name wasn't found), use the service name // if ((SPAPI_E_LINE_NOT_FOUND == hr) || (SPAPI_E_BAD_SECTION_NAME_LINE == hr)) { strDeviceName.append(strServiceName); hr = S_OK; } if (SUCCEEDED(hr)) { // Now set the device name value in the service's networkprovider key hr = HrRegSetString(hkeyNetworkProvider, c_szDeviceName, strDeviceName); } TraceHr (ttidError, FAL, hr, FALSE, "HrCiSetDeviceName"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiGetPrintProviderInfoFromInf // // Purpose: This function gets the display name and dll name from // the print provider section strSection. // // Arguments: // hinf [in] handle to inf file. See SetupApi for more info // strSection [in] The print provider section name // pstrName [out] The print provider name found in the inf // pstrDll [out] The dll name found in the inf // pstrDisplayName [out] The localized display name found in the inf // // Returns: HRESULT. S_OK if successful, error code otherwise // // Author: billbe 24 Oct 1997 // // Notes: HRESULT HrCiGetPrintProviderInfoFromInf(HINF hinf, tstring strSection, tstring* pstrName, tstring* pstrDll, tstring* pstrDisplayName) { Assert(!strSection.empty()); Assert(pstrName); Assert(pstrDll); Assert(pstrDisplayName); INFCONTEXT ctx; // find the line containing non-localized ProviderName HRESULT hr = HrSetupFindFirstLine(hinf, strSection.c_str(), c_szPrintProviderName, &ctx); if (S_OK == hr) { // Get the ProviderName hr = HrSetupGetStringField(ctx, 1, pstrName); if (S_OK == hr) { // Now find and get the PrintProviderDll value // hr = HrSetupFindFirstLine(hinf, strSection.c_str(), c_szInfKeyPrintProviderDll, &ctx); if (S_OK == hr) { hr = HrSetupGetStringField(ctx, 1, pstrDll); if (S_OK == hr) { // find the line containing DisplayName hr = HrSetupFindFirstLine(hinf, strSection.c_str(), c_szDisplayName, &ctx); if (S_OK == hr) { // Get the DisplayName hr = HrSetupGetStringField(ctx, 1, pstrDisplayName); } } } } } TraceHr (ttidError, FAL, hr, FALSE, "HrCiGetPrintProviderInfoFromInf"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiWritePrintProviderInfoIfNeeded // // Purpose: This function updates necessary registry entries for // NETCLIENT class components that are print providers. // // Arguments: // hinf [in] handle to inf file. See SetupApi for more info. // strSection [in] The main section name. // hkeyInstance [in] The hkey to the component's instance key. // dwPrintPosition [in] The position to place the print provider when // it is added to the list. // // Returns: HRESULT. S_OK if successful, error code otherwise // // Author: billbe 22 Mar 1997 // updated 7 Oct 1997 // // Notes: HRESULT HrCiWritePrintProviderInfoIfNeeded(HINF hinf, const tstring& strSection, HKEY hkeyInstance, DWORD dwPrintPosition) { Assert(IsValidHandle(hinf)); Assert(!strSection.empty()); Assert(hkeyInstance); HRESULT hr = S_OK; INFCONTEXT ctx; tstring strDisplayName; tstring strName; tstring strPrintProviderDll; tstring strPrintSection(strSection); strPrintSection.append(L"."); strPrintSection.append(c_szInfSubKeyPrintProvider); // First we check for the PrintProvider inf section hr = HrSetupFindFirstLine(hinf, strPrintSection.c_str(), NULL, &ctx); if (S_OK == hr) { // Get the print provider information from the inf hr = HrCiGetPrintProviderInfoFromInf(hinf, strPrintSection, &strName, &strPrintProviderDll, &strDisplayName); if (S_OK == hr) { // Add the component as a print provider hr = HrCiAddPrintProvider(strName, strPrintProviderDll, strDisplayName, dwPrintPosition); // Now write the Provider name under our instance key // so we can remove this provider when asked if (S_OK == hr) { (void) HrRegSetString(hkeyInstance, c_szPrintProviderName, strName); } } } else { // The section is optional so this is not an error if (SPAPI_E_LINE_NOT_FOUND == hr) { hr = S_OK; } } TraceHr (ttidError, FAL, hr, FALSE, "HrCiWritePrintProviderInfoIfNeeded"); return hr; } //+-------------------------------------------------------------------------- // // Function: MoveProviderToIndex // // Purpose: This function moves the pszProviderName to the position // specified. // // Arguments: // pszProviderName [in] Name of the print provider (used in call to // AddPrintProvidor. // dwPrintPosition [in] The index to place this provider in the // provider order. // // Returns: nothing // // Author: billbe 6 Oct 1998 // // Notes: // VOID MoveProviderToIndex ( IN PCWSTR pszProviderName, IN DWORD dwPrintPosition) { PROVIDOR_INFO_2 p2info; // Open the print provider key // HKEY hkey; HRESULT hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyPrintProviders, KEY_READ, &hkey); if (S_OK == hr) { // Retrieve the current order // PWSTR pmszOrder; hr = HrRegQueryMultiSzWithAlloc(hkey, c_szRegValueOrder, &pmszOrder); if (S_OK == hr) { PWSTR pmszNewOrder; BOOL fChanged; // Move the provider to the front // hr = HrAddSzToMultiSz(pszProviderName, pmszOrder, STRING_FLAG_ENSURE_AT_INDEX, dwPrintPosition, &pmszNewOrder, &fChanged); if ((S_OK == hr) && fChanged) { // Notify Spooler that we want to change the order // p2info.pOrder = pmszNewOrder; if (!AddPrintProvidor(NULL, 2, (LPBYTE)&p2info)) { hr = HrFromLastWin32Error(); // If we removed duplicates, the last call to // AddPrintProvidor may have failed with // ERROR_INVALID_PARAMETER. Trying again will correct // the problem. // if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) == hr) { AddPrintProvidor(NULL, 2, reinterpret_cast(&p2info)); } TraceHr (ttidError, FAL, hr, FALSE, "AddPrintProvider(class 2) returned an error"); } MemFree(pmszNewOrder); } MemFree(pmszOrder); } TraceHr (ttidError, FAL, hr, FALSE, "MoveProviderToIndex"); RegCloseKey(hkey); } } //+-------------------------------------------------------------------------- // // Function: HrCiAddPrintProvider // // Purpose: This function calls the AddPrintProvidor [sic] function // to add the current component as a provider. // // Arguments: // strName [in] Name of the print provider (used in call to // AddPrintProvidor. // strDllName [in] Dll name of the print provider. // strDisplayName [in] Localized Display Name. // dwPrintPosition [in] The position to place this provider when it // is added to the list. // // Returns: HRESULT. S_OK if successful, error code otherwise. // // Author: billbe 22 Mar 1997 // updated 7 Oct 1997 // // Notes: See AddPrintProvidor Win32 fcn for more info HRESULT HrCiAddPrintProvider( const tstring& strName, const tstring& strDllName, const tstring& strDisplayName, DWORD dwPrintPosition) { Assert(!strName.empty()); Assert(!strDllName.empty()); PROVIDOR_INFO_1 pi1; HRESULT hr=S_OK; // Fill the structure with the relevant info // pi1.pEnvironment = NULL; pi1.pDLLName = (PWSTR)strDllName.c_str(); pi1.pName = (PWSTR)strName.c_str(); hr = HrEnableAndStartSpooler(); if (S_OK == hr) { if (!AddPrintProvidor(NULL, 1, reinterpret_cast(&pi1))) { // convert the error hr = HrFromLastWin32Error(); } } if (S_OK == hr) { // AddPrintProvidor adds the print provider to the end of list. // 99% of the time, the goal is to have the provider be somewhere // else. We will attempt to move it to the position given to us. This // is either the beginning of the list or the previous position of // this provider (i.e. if we are reinstalling) If it fails we can // still go on. (void) MoveProviderToIndex(pi1.pName, dwPrintPosition); tstring strPrintProvider = c_szRegKeyPrintProviders; strPrintProvider.append(L"\\"); strPrintProvider.append(strName); HKEY hkey; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, strPrintProvider.c_str(), KEY_SET_VALUE, &hkey); if (S_OK == hr) { // Write DisplayName in the new key created by the // AddPrintProvidor [sic] call. // Not sure who the consumer of this value is but // the NT4 code did this hr = HrRegSetString(hkey, c_szDisplayName, strDisplayName); RegCloseKey(hkey); } } TraceHr (ttidError, FAL, hr, FALSE, "HrCiAddPrintProvider"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiDeletePrintProviderIfNeeded // // Purpose: This function calls the DeletePrintProvidor [sic] function // if this component was a print provider // // Arguments: // hkeyInstance [in] The hkey for the component's instance key. // pdwProviderPosition [out] Optional. The position of the print // provider in the order list before it was // deleted. // // Returns: HRESULT. S_OK if successful, error code otherwise // // Author: billbe 22 Mar 1997 // updated 7 Oct 1997 // // Notes: See DeletePrintProvidor Win32 fcn for more info // HRESULT HrCiDeletePrintProviderIfNeeded(HKEY hkeyInstance, DWORD* pdwProviderPosition) { // Check if this component is a print provider // tstring strName; HRESULT hr = HrRegQueryString(hkeyInstance, c_szPrintProviderName, &strName); if (SUCCEEDED(hr)) { // If the out param was specified, we may need to get the current position of this print provider // in the list of providers if (pdwProviderPosition) { *pdwProviderPosition = 0; // Open the print key // HKEY hkeyPrint; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegKeyPrintProviders, KEY_READ, &hkeyPrint); if (SUCCEEDED(hr)) { // Get the current order of providers // PWSTR pmszOrder; hr = HrRegQueryMultiSzWithAlloc(hkeyPrint, c_szRegValueOrder, &pmszOrder); if (S_OK == hr) { // Get this provider's current position (void) FGetSzPositionInMultiSzSafe( strName.c_str(), pmszOrder, pdwProviderPosition, NULL, NULL); MemFree(pmszOrder); } RegCloseKey(hkeyPrint); } } // The component was a print provider so we need to delete it as such // DeletePrintProvidor(NULL, NULL, (PWSTR)strName.c_str()); // delete from our instance key as well // Note: we do this because if this component is being // reinstalled, the new inf might not have a providername so // we don't want the old value lying around (void) HrRegDeleteValue(hkeyInstance, c_szPrintProviderName); } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // This component was not a print provider so there // is nothing to remove hr = S_OK; } TraceHr (ttidError, FAL, hr, FALSE, "HrCiDeletePrintProviderIfNeeded"); return hr; }