//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1998. // // File: F R I E N D L Y . C P P // // Contents: Creates indexes for device installs and sets friendly // name descriptions based on the indexes. // // Notes: // // Author: billbe 6 Nov 1998 // //--------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "adapter.h" #include "classinst.h" #include "ncmsz.h" #include "ncreg.h" #include "ncsetup.h" #include "util.h" const WCHAR c_szRegValueInstanceIndex[] = L"InstanceIndex"; const DWORD c_cchIndexValueNameLen = 6; const ULONG c_cMaxDescriptions = 10001; // SetupDi only allows 0-9999 const WCHAR c_szRegKeyDescriptions[] = L"Descriptions"; //+-------------------------------------------------------------------------- // // Function: HrCiAddNextAvailableIndex // // Purpose: Adds the next available index to a multi-sz of indexes. // // Arguments: // pmszIndexesIn [in] MultiSz of current indexes. // pulIndex [inout] The index added. // ppmszIndexesOut[out] New multiSz with the added index. // // Returns: HRESULT. S_OK is successful, a converted Win32 error otherwise // // Author: billbe 30 Oct 1998 // // Notes: // HRESULT HrCiAddNextAvailableIndex(PWSTR pmszIndexesIn, ULONG* pIndex, PWSTR* ppmszIndexesOut) { Assert(pmszIndexesIn); Assert(ppmszIndexesOut); HRESULT hr = S_OK; WCHAR szIndex[c_cchIndexValueNameLen]; // clear out param. *ppmszIndexesOut = NULL; // We are adding a new index. Find the first available // index. // ULONG Index; ULONG NextIndex; PWSTR pszStopString; PWSTR pszCurrentIndex = pmszIndexesIn; DWORD PositionInMultiSz = 0; for (NextIndex = 1; NextIndex < c_cMaxDescriptions; ++NextIndex) { Index = wcstoul(pszCurrentIndex, &pszStopString, c_nBase10); if (Index != NextIndex) { // We found an available index. Now we insert it. // swprintf(szIndex, L"%u", NextIndex); BOOL fChanged; hr = HrAddSzToMultiSz(szIndex, pmszIndexesIn, STRING_FLAG_ENSURE_AT_INDEX, PositionInMultiSz, ppmszIndexesOut, &fChanged); AssertSz(fChanged, "We were adding a new index. Something had to change!"); break; } ++PositionInMultiSz; // Try the next index. pszCurrentIndex += wcslen(pszCurrentIndex) + 1; } // If we succeeded, set the output param. if (S_OK == hr) { *pIndex = NextIndex; } TraceHr (ttidError, FAL, hr, FALSE, "HrCiAddNextAvailableIndex"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiCreateAndWaitForIndexListMutex // // Purpose: Creates Updates the description map by adding or removing // entries for pszDescription. // // Arguments: // pszName [in] The name for this mutex. // phMutex [out] The created mutex. // // Returns: HRESULT. S_OK is successful, a converted Win32 error otherwise // // Author: billbe 30 Oct 1998 // // Notes: // HRESULT HrCiCreateAndWaitForIndexListMutex(HANDLE* phMutex) { Assert(phMutex); const WCHAR c_szMutexName[] = L"Global\\{84b06608-8026-11d2-b1f2-00c04fd912b2}"; HRESULT hr = S_OK; // Create the mutex. hr = HrCreateMutexWithWorldAccess(c_szMutexName, FALSE, NULL, phMutex); if (S_OK == hr) { // Wait until the mutex is free or cMaxWaitMilliseconds seconds // have passed. // while (1) { const DWORD cMaxWaitMilliseconds = 30000; // 30 seconds DWORD dwWait = MsgWaitForMultipleObjects (1, phMutex, FALSE, cMaxWaitMilliseconds, QS_ALLINPUT); if ((WAIT_OBJECT_0 + 1) == dwWait) { // We have messages to pump. // MSG msg; while (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) { DispatchMessage (&msg); } } else { // Wait is satisfied, or we had a timeout, or an error. // if (WAIT_TIMEOUT == dwWait) { hr = HRESULT_FROM_WIN32 (ERROR_TIMEOUT); } else if (0xFFFFFFFF == dwWait) { hr = HrFromLastWin32Error (); } break; } } } TraceHr (ttidError, FAL, hr, FALSE, "HrCiCreateAndWaitForIndexListMutex"); return hr; } //+-------------------------------------------------------------------------- // // Function: HrCiUpdateDescriptionIndexList // // Purpose: Updates the description map by adding or removing // entries for pszDescription. // // Arguments: // pguidClass [in] The device's class guid // pszDescription [in] Description of the adapter // eOp [in] The operation to perform. DM_ADD to add // an index, DM_DELETE to delete an index. // pulIndex [inout] The index added if eOp was DM_ADD. // The index to delete if eOp was DM_DELETE. // // Returns: HRESULT. S_OK is successful, a converted Win32 error otherwise // // Author: billbe 30 Oct 1998 // // Notes: // HRESULT HrCiUpdateDescriptionIndexList ( IN NETCLASS Class, IN PCWSTR pszDescription, IN DM_OP eOp, IN OUT ULONG* pIndex) { Assert(pszDescription); Assert(pIndex); Assert(FIsEnumerated(Class)); // We don't want to update a decription's index list at the same time // as another process, so create a mutex and wait until it is available. // HANDLE hMutex = NULL; HRESULT hr = HrCiCreateAndWaitForIndexListMutex(&hMutex); if (S_OK == hr) { // Build the path to the description key // e.g. ...\Network\\c_szRegKeyDescriptions // WCHAR szPath[_MAX_PATH]; PCWSTR pszNetworkSubtreePath; pszNetworkSubtreePath = MAP_NETCLASS_TO_NETWORK_SUBTREE[Class]; AssertSz (pszNetworkSubtreePath, "This class does not use the network subtree."); wcscpy (szPath, pszNetworkSubtreePath); wcscat (szPath, L"\\"); wcscat (szPath, c_szRegKeyDescriptions); // Open/Create the description key // HKEY hkeyDescription; hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, szPath, 0, KEY_READ_WRITE_DELETE, NULL, &hkeyDescription, NULL); if (S_OK == hr) { // Get the description index list if it exists. // PWSTR pmszIndexesOld; hr = HrRegQueryMultiSzWithAlloc( hkeyDescription, pszDescription, &pmszIndexesOld); // If we have the list... if (S_OK == hr) { // Perform the requested operation on the list. // PWSTR pmszBufferToSet = NULL; PWSTR pmszIndexesNew = NULL; if (DM_ADD == eOp) { // We need to add a new index. hr = HrCiAddNextAvailableIndex(pmszIndexesOld, pIndex, &pmszIndexesNew); pmszBufferToSet = pmszIndexesNew; } else if (DM_DELETE == eOp) { // Delete the index from the list. // WCHAR szDelete[c_cchIndexValueNameLen]; BOOL fRemoved; swprintf(szDelete, L"%u", *pIndex); RemoveSzFromMultiSz(szDelete, pmszIndexesOld, STRING_FLAG_REMOVE_SINGLE, &fRemoved); // If something was removed, check to see if the // index list is empty. If it is, delete the // registry value. // if (fRemoved) { ULONG cchIndexes = CchOfMultiSzSafe(pmszIndexesOld); if (!cchIndexes) { // Index list is empty, delete the value. HrRegDeleteValue(hkeyDescription, pszDescription); } else { // Something was removed and there are still // index entries so we have a buffer to set in the // registry. pmszBufferToSet = pmszIndexesOld; } } } // If we succeeded and have a new list to set... // if ((S_OK == hr) && pmszBufferToSet) { // Set the map back in the registry. hr = HrRegSetMultiSz(hkeyDescription, pszDescription, pmszBufferToSet); } MemFree(pmszIndexesNew); MemFree(pmszIndexesOld); } else if ((HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) && (DM_ADD == eOp)) { // There was no entry for this description so we need to // create one. // hr = HrRegAddStringToMultiSz(L"1", hkeyDescription, NULL, pszDescription, STRING_FLAG_ENSURE_AT_FRONT, 0); if (S_OK == hr) { *pIndex = 1; } } RegCloseKey(hkeyDescription); } ReleaseMutex(hMutex); CloseHandle(hMutex); } TraceHr (ttidError, FAL, hr, FALSE, "HrCiUpdateDescriptionIndexList"); return hr; } //+-------------------------------------------------------------------------- // // Function: CiSetFriendlyNameIfNeeded // // Purpose: Sets an instance index for the adapter. If this adapter's // description already exists (i.e. another similar adapter // is installed), then a friendly name for this adapter will be // set using the current description appened with the instance // index. // // Arguments: // cii [in] See classinst.h // // Returns: nothing // // Author: billbe 30 Oct 1998 // // Notes: If previous adapter descriptions were Foo, Foo, Foo // They will have friendly names Foo, Foo #2, Foo #3 // VOID CiSetFriendlyNameIfNeeded(IN const COMPONENT_INSTALL_INFO& cii) { Assert(IsValidHandle(cii.hdi)); Assert(cii.pdeid); Assert(FIsEnumerated(cii.Class)); Assert(cii.pszDescription); // Open the device parameters key. // HKEY hkeyDevice; HRESULT hr; hr = HrSetupDiCreateDevRegKey(cii.hdi, cii.pdeid, DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL, &hkeyDevice); if (S_OK == hr) { // Does this device already have an index? // DWORD Index; hr = HrRegQueryDword(hkeyDevice, c_szRegValueInstanceIndex, &Index); // This device doesn't have an index, so we need to give it one. // if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // Update the description map and get the new index. hr = HrCiUpdateDescriptionIndexList(cii.Class, cii.pszDescription, DM_ADD, &Index); if (S_OK == hr) { // Store the index there so we can retrieve it when // the device is uninstalled and delete the index from // out table of indexes in use. (void) HrRegSetDword(hkeyDevice, c_szRegValueInstanceIndex, Index); } } // The first index doesn't get a new name. // i.e. the following same named devices: // // foo, foo, foo // // become // // foo, foo #2, foo #3 // if ((S_OK == hr) && (1 != Index) && !FIsFilterDevice(cii.hdi, cii.pdeid)) { // Now build the new name of this device using the index // number. // // Note: It doesn't matter if we failed to open the driver key // above; we can still continue. It only means that this index // cannot be reused if the device is deleted. // WCHAR szIndex[c_cchIndexValueNameLen]; swprintf(szIndex, L"%u", Index); WCHAR szNewName[LINE_LEN + 1] = {0}; wcsncpy(szNewName, cii.pszDescription, LINE_LEN - c_cchIndexValueNameLen); wcscat(szNewName, L" #"); wcscat(szNewName, szIndex); // Set the new name as the friendly name of the device hr = HrSetupDiSetDeviceRegistryProperty(cii.hdi, cii.pdeid, SPDRP_FRIENDLYNAME, reinterpret_cast(szNewName), CbOfSzAndTerm(szNewName)); } RegCloseKey(hkeyDevice); } TraceHr (ttidError, FAL, hr, FALSE, "FCiSetFriendlyNameIfNeeded"); }