Source code of Windows XP (NT5)
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
13 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");
}