You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
442 lines
14 KiB
442 lines
14 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// 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\<net/infrared guid>\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<const BYTE*>(szNewName),
|
|
CbOfSzAndTerm(szNewName));
|
|
|
|
}
|
|
|
|
RegCloseKey(hkeyDevice);
|
|
}
|
|
|
|
TraceHr (ttidError, FAL, hr, FALSE, "FCiSetFriendlyNameIfNeeded");
|
|
}
|
|
|
|
|