windows-nt/Source/XPSP1/NT/net/config/common/ncbase/ncsetup.cpp

4496 lines
121 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: N C S E T U P . C P P
//
// Contents: HRESULT wrappers for the Setup Api.
//
// Notes:
//
// Author: shaunco 16 Apr 1997
//
//----------------------------------------------------------------------------
#include <pch.h>
#pragma hdrstop
#include "ncsetup.h"
#include "ncbase.h"
#include "ncmem.h"
#include "ncstring.h"
#include "ncmisc.h"
#include <swenum.h>
extern const WCHAR c_szNo[];
extern const WCHAR c_szYes[];
// dwFieldIndex parameter for the first field. Fields indexes are 1 based
// in Setup Api.
//
const DWORD c_dwFirstField = 1;
//+---------------------------------------------------------------------------
//
// Function: HrSetupCommitFileQueue
//
// Purpose: Initializes the context used by the default queue callback
// routine included with the Setup API in the same manner
// as SetupInitDefaultQueueCallback, except that an
// additional window is provided to the callback function
// to accept progress messages.
//
// Arguments:
// hwndOwner [in] See SetupApi for information
// hfq [in]
// pfc [in]
// pvCtx [in]
//
// Returns: S_OK or a Win32 error code.
//
// Author: billbe 23 July 1997
//
// Notes:
//
HRESULT HrSetupCommitFileQueue(HWND hwndOwner, HSPFILEQ hfq,
PSP_FILE_CALLBACK pfc, PVOID pvCtx)
{
Assert(hfq);
Assert(INVALID_HANDLE_VALUE != hfq);
Assert(pfc);
Assert(pvCtx);
HRESULT hr = S_OK;
// Try to commit the queue
if (!SetupCommitFileQueue(hwndOwner, hfq, pfc, pvCtx))
{
hr = HrFromLastWin32Error();
}
TraceError ("HrSetupCommitFileQueue", (HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupInitDefaultQueueCallbackEx
//
// Purpose: Initializes the context used by the default queue callback
// routine included with the Setup API in the same manner
// as SetupInitDefaultQueueCallback, except that an
// additional window is provided to the callback function
// to accept progress messages.
//
// Arguments:
// hwndOwner [in] See SetupApi for information
// hwndAlternate [in]
// uMsg [in]
// dwReserved1 [in]
// dwReserved2 [in]
// ppvCtx [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: billbe 23 July 1997
//
// Notes:
//
HRESULT HrSetupInitDefaultQueueCallbackEx(HWND hwndOwner, HWND hwndAlternate,
UINT uMsg, DWORD dwReserved1,
PVOID pvReserved2, PVOID* ppvCtx)
{
Assert(ppvCtx);
// Try to init default queue callback.
//
HRESULT hr;
PVOID pvCtx = SetupInitDefaultQueueCallbackEx(hwndOwner, hwndAlternate,
uMsg, dwReserved1, pvReserved2);
if (pvCtx)
{
hr = S_OK;
*ppvCtx = pvCtx;
}
else
{
hr = HrFromLastWin32Error ();
*ppvCtx = NULL;
}
TraceError ("HrSetupInitDefaultQueueCallbackEx", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupOpenFileQueue
//
// Purpose: Creates a setup file queue.
//
// Arguments:
// phfq [out] See SetupApi for information
//
// Returns: S_OK or a Win32 error code.
//
// Author: billbe 23 July 1997
//
// Notes:
//
HRESULT HrSetupOpenFileQueue(HSPFILEQ* phfq)
{
Assert(phfq);
// Try to open the file queue.
//
HRESULT hr;
HSPFILEQ hfq = SetupOpenFileQueue();
if (INVALID_HANDLE_VALUE != hfq)
{
hr = S_OK;
*phfq = hfq;
}
else
{
hr = HrFromLastWin32Error ();
*phfq = NULL;
}
TraceError ("HrSetupOpenFileQueue", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupOpenInfFile
//
// Purpose: Open an INF file.
//
// Arguments:
// pszFileName [in] See the Setup API documentation.
// pszInfClass [in]
// dwInfStyle [in]
// punErrorLine [out]
// phinf [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 17 Apr 1997
//
// Notes:
//
HRESULT
HrSetupOpenInfFile (
PCWSTR pszFileName,
PCWSTR pszInfClass,
DWORD dwInfStyle,
UINT* punErrorLine,
HINF* phinf)
{
HRESULT hr;
HINF hinf;
Assert (pszFileName);
Assert (phinf);
// Try to open the file.
//
hinf = SetupOpenInfFile (pszFileName, pszInfClass,
dwInfStyle, punErrorLine);
if (INVALID_HANDLE_VALUE != hinf)
{
hr = S_OK;
*phinf = hinf;
}
else
{
hr = HrFromLastWin32Error ();
*phinf = NULL;
if (punErrorLine)
{
*punErrorLine = 0;
}
}
TraceHr (ttidError, FAL, hr, FALSE,
"HrSetupOpenInfFile (%S)", pszFileName);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupFindFirstLine
//
// Purpose: Find the first line in an INF file with a matching section
// and key.
//
// Arguments:
// hinf [in] See the Setup API documentation.
// pszSection [in]
// pszKey [in]
// pctx [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT
HrSetupFindFirstLine (
IN HINF hinf,
IN PCWSTR pszSection,
IN PCWSTR pszKey,
OUT INFCONTEXT* pctx)
{
Assert (hinf);
Assert (pszSection);
Assert (pctx);
HRESULT hr;
if (SetupFindFirstLine (hinf, pszSection, pszKey, pctx))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error ();
}
TraceErrorOptional ("HrSetupFindFirstLine", hr,
(SPAPI_E_LINE_NOT_FOUND == hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupFindNextLine
//
// Purpose: Find the next line in an INF file relative to ctxIn.
//
// Arguments:
// ctxIn [in] See the Setup API documentation.
// pctxOut [out]
//
// Returns: S_OK if successful, S_FALSE if there are no more lines, or a
// Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT HrSetupFindNextLine (const INFCONTEXT& ctxIn, INFCONTEXT* pctxOut)
{
Assert (pctxOut);
HRESULT hr;
if (SetupFindNextLine (const_cast<PINFCONTEXT>(&ctxIn), pctxOut))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error ();
if (SPAPI_E_LINE_NOT_FOUND == hr)
{
// Translate ERROR_LINE_NOT_FOUND into S_FALSE
hr = S_FALSE;
}
}
TraceError ("HrSetupFindNextLine", (hr == S_FALSE) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupFindNextMatchLine
//
// Purpose: Find the next line in an INF file relative to ctxIn and
// matching an optional key.
//
// Arguments:
// ctxIn [in] See the Setup API documentation.
// pszKey [in]
// pctxOut [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT
HrSetupFindNextMatchLine (
IN const INFCONTEXT& ctxIn,
IN PCWSTR pszKey,
OUT INFCONTEXT* pctxOut)
{
Assert (pctxOut);
HRESULT hr;
if (SetupFindNextMatchLine ((PINFCONTEXT)&ctxIn, pszKey, pctxOut))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error();
if (SPAPI_E_LINE_NOT_FOUND == hr)
{
// Translate ERROR_LINE_NOT_FOUND into S_FALSE
hr = S_FALSE;
}
}
TraceError ("HrSetupFindNextMatchLine", (hr == S_FALSE) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetLineByIndex
//
// Purpose: Locates a line in an INF file by its index value in the
// specified section.
//
// Arguments:
// hinf [in] See the Setup API documentation.
// pszSection [in]
// dwIndex [in]
// pctx [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetLineByIndex (
IN HINF hinf,
IN PCWSTR pszSection,
IN DWORD dwIndex,
OUT INFCONTEXT* pctx)
{
Assert (pszSection);
Assert (pctx);
HRESULT hr;
if (SetupGetLineByIndex (hinf, pszSection, dwIndex, pctx))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error ();
}
TraceError ("HrSetupGetLineByIndex", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetLineCount
//
// Purpose: Get the number of lines in the specified section on an
// INF file.
//
// Arguments:
// hinf [in] See the Setup API documentation.
// pszSection [in]
// pulCount [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetLineCount (
IN HINF hinf,
IN PCWSTR pszSection,
OUT ULONG* pulCount)
{
Assert (pszSection);
Assert (pulCount);
HRESULT hr;
LONG lCount = SetupGetLineCount (hinf, pszSection);
if (-1 != lCount)
{
*pulCount = lCount;
hr = S_OK;
}
else
{
*pulCount = 0;
hr = HrFromLastWin32Error ();
}
TraceError ("HrSetupGetLineCount", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetBinaryField
//
// Purpose: Gets a binary value from an INF field.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// pbBuf [out]
// cbBuf [in]
// pbRequired [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetBinaryField (
IN const INFCONTEXT& ctx,
IN DWORD dwFieldIndex,
OUT BYTE* pbBuf,
IN DWORD cbBuf,
OUT DWORD* pbRequired)
{
HRESULT hr;
if (SetupGetBinaryField ((PINFCONTEXT)&ctx, dwFieldIndex, pbBuf,
cbBuf, pbRequired))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error ();
if (pbBuf)
{
*pbBuf = 0;
}
if (pbRequired)
{
*pbRequired = 0;
}
}
TraceError ("HrSetupGetBinaryField", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetIntField
//
// Purpose: Gets an integer value from an INF field.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// pnValue [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetIntField (
IN const INFCONTEXT& ctx,
IN DWORD dwFieldIndex,
OUT INT* pnValue)
{
Assert (pnValue);
HRESULT hr;
if (SetupGetIntField (const_cast<PINFCONTEXT>(&ctx),
dwFieldIndex, pnValue))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error ();
*pnValue = 0;
}
TraceError ("HrSetupGetIntField", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetMultiSzField
//
// Purpose: Gets a multi-sz value from an INF field.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// pszBuf [out]
// cchBuf [in]
// pcchRequired [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetMultiSzField (
const INFCONTEXT& ctx,
DWORD dwFieldIndex,
PWSTR pszBuf,
DWORD cchBuf,
DWORD* pcchRequired)
{
HRESULT hr;
if (SetupGetMultiSzField (const_cast<PINFCONTEXT>(&ctx),
dwFieldIndex, pszBuf, cchBuf, pcchRequired))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error ();
if (pszBuf)
{
*pszBuf = 0;
}
if (pcchRequired)
{
*pcchRequired = 0;
}
}
TraceError ("HrSetupGetMultiSzField", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetMultiSzFieldWithAlloc
//
// Purpose: Gets a multi-sz value from an INF field. Allocates space for
// it automatically.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// ppszBuf [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes: Free the returned multi-sz with MemFree.
//
HRESULT HrSetupGetMultiSzFieldWithAlloc (
const INFCONTEXT& ctx,
DWORD dwFieldIndex,
PWSTR* ppszBuf)
{
Assert (ppszBuf);
// Initialize the output parameter.
*ppszBuf = NULL;
// First, get the size required.
//
HRESULT hr;
DWORD cchRequired;
hr = HrSetupGetMultiSzField (ctx, dwFieldIndex, NULL, 0, &cchRequired);
if (S_OK == hr)
{
// Allocate the buffer.
//
PWSTR pszBuf = (PWSTR)MemAlloc(cchRequired * sizeof(WCHAR));
if (pszBuf)
{
// Now fill the buffer.
//
hr = HrSetupGetMultiSzField (ctx, dwFieldIndex, pszBuf,
cchRequired, NULL);
if (S_OK == hr)
{
*ppszBuf = pszBuf;
}
else
{
MemFree (pszBuf);
}
}
}
TraceError ("HrSetupGetMultiSzFieldWithAlloc", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetStringField
//
// Purpose: Gets a string from an INF field. Returns it as a tstring.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// pstr [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT HrSetupGetStringField (const INFCONTEXT& ctx,
DWORD dwFieldIndex,
tstring* pstr)
{
Assert (pstr);
// First, get the size required.
//
DWORD cchRequired = 0;
HRESULT hr = HrSetupGetStringField (ctx, dwFieldIndex, NULL, 0, &cchRequired);
// 412390: workaround for bug in NT4 SETUPAPI.dll
//
if ((S_OK == hr) && (0 == cchRequired))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
}
if (S_OK == hr)
{
// Allocate a buffer on the stack.
//
PWSTR pszBuf;
pszBuf = (PWSTR)PvAllocOnStack(cchRequired * sizeof(WCHAR));
// Now fill the buffer.
//
hr = HrSetupGetStringField (ctx, dwFieldIndex, pszBuf, cchRequired, NULL);
if (S_OK == hr)
{
*pstr = pszBuf;
}
}
// If we failed for any reason, initialize the output parameter.
//
if (FAILED(hr))
{
pstr->erase ();
}
TraceError ("HrSetupGetStringField", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetStringField
//
// Purpose: Gets a string from an INF field.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// pszBuf [out]
// cchBuf [in]
// pcchRequired [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT HrSetupGetStringField (
IN const INFCONTEXT& ctx,
IN DWORD dwFieldIndex,
OUT PWSTR pszBuf,
IN DWORD cchBuf,
OUT DWORD* pcchRequired)
{
HRESULT hr;
if (SetupGetStringField ((PINFCONTEXT)&ctx, dwFieldIndex, pszBuf,
cchBuf, pcchRequired))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error ();
if (pszBuf)
{
*pszBuf = 0;
}
if (pcchRequired)
{
*pcchRequired = 0;
}
}
TraceError ("HrSetupGetStringField", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupScanFileQueueWithNoCallback
//
// Purpose: Scans a setup file queue, performing an operation on each node
// in its copy list. The operation is specified by a set of
// flags. This function can be called either before or after
// the queue has been committed.
//
// Arguments:
// hfq [in] See SetupApi for information
// dwFlags [in]
// hwnd [in]
// pdwResult [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: billbe 23 July 1997
//
// Notes: This differs from the SetupApi version in that no callback
// can be specified through this wrapper. This is because
// errors from the callback cannot not be reliably mapped
// to an HRESULT. If a user defined callback is needed,
// the original SetupApi function must be used.
//
HRESULT HrSetupScanFileQueueWithNoCallback(HSPFILEQ hfq, DWORD dwFlags,
HWND hwnd, PDWORD pdwResult)
{
Assert(hfq);
Assert(INVALID_HANDLE_VALUE != hfq);
Assert(pdwResult);
HRESULT hr = S_OK;
// Scan the given queue
if (!SetupScanFileQueue(hfq, dwFlags, hwnd, NULL, NULL, pdwResult))
{
hr = HrFromLastWin32Error();
}
TraceError ("HrSetupScanFileQueueWithNoCallback", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetMultiSzFieldMapToDword
//
// Purpose: Gets the values represented as mult-sz in an INF
// and returns the value as a DWORD of bit flags.
// The mapping is specified by the caller through an array of
// pointers to string values and their associated DWORD values.
//
// Example: The value in the INF might be "Ip,Ipx,Nbf".
// This function can map these values to the DWORD
// representation of FLAG_IP | FLAG_IPX | FLAG_NBF.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// aMapSzDword [in] array of elements mapping a string to a DWORD.
// cMapSzDword [in] count of elements in the array.
// pdwValue [out] the returned value.
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes: _wcsicmp is used to make the string comparisons.
//
HRESULT HrSetupGetMultiSzFieldMapToDword (const INFCONTEXT& ctx,
DWORD dwFieldIndex,
const MAP_SZ_DWORD* aMapSzDword,
UINT cMapSzDword,
DWORD* pdwValue)
{
Assert (aMapSzDword);
Assert (cMapSzDword);
Assert (pdwValue);
// Initialize the output parameter.
*pdwValue = 0;
// Get the multi-sz value.
//
HRESULT hr;
PWSTR pszBuf;
hr = HrSetupGetMultiSzFieldWithAlloc (ctx, dwFieldIndex, &pszBuf);
if (S_OK == hr)
{
DWORD dwValue = 0;
// Map each value in the multi-sz to a DWORD and OR it into
// the result.
for (PCWSTR pszValue = pszBuf; *pszValue;
pszValue += lstrlenW (pszValue) + 1)
{
// Search the map for a matching value. When found, update
// dwValue.
for (UINT i = 0; i < cMapSzDword; i++)
{
if (0 == lstrcmpiW (aMapSzDword[i].pszValue, pszValue))
{
dwValue |= aMapSzDword[i].dwValue;
break;
}
}
}
// Assign the output parameter.
*pdwValue = dwValue;
MemFree (pszBuf);
}
TraceError ("HrSetupGetMultiSzFieldMapToDword", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetStringFieldMapToDword
//
// Purpose: Gets a value represented as multiple strings in an INF
// and returns it as a DWORD. The mapping is specified
// by the caller through an array of pointers to string
// values and their associated DWORD values.
//
// Example: Values in the INF might be "Yes" or "No".
// This function can map these values to DWORD representations
// of "1" and "0" respectively.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// aMapSzDword [in] array of elements mapping a string to a DWORD.
// cMapSzDword [in] count of elements in the array.
// pdwValue [out] the returned value.
//
// Returns: S_OK if a match was found. If a match wasn't found,
// HRESULT_FROM_WIN32(ERROR_INVALID_DATA) is returned.
// Other Win32 error codes.
//
// Author: shaunco 16 Apr 1997
//
// Notes: lstrcmpiW is used to make the string comparisons.
//
HRESULT HrSetupGetStringFieldMapToDword (const INFCONTEXT& ctx,
DWORD dwFieldIndex,
const MAP_SZ_DWORD* aMapSzDword,
UINT cMapSzDword,
DWORD* pdwValue)
{
Assert (aMapSzDword);
Assert (cMapSzDword);
Assert (pdwValue);
// Initialize the output parameter.
*pdwValue = 0;
// Get the string value.
//
tstring strValue;
HRESULT hr = HrSetupGetStringField (ctx, dwFieldIndex, &strValue);
if (SUCCEEDED(hr))
{
// Search the map for a matching value. When found, pass
// the DWORD value out.
// If the none of the strings matched, we'll return
// an invalid data error code.
hr = HRESULT_FROM_WIN32 (ERROR_INVALID_DATA);
while (cMapSzDword--)
{
if (0 == lstrcmpiW (aMapSzDword->pszValue, strValue.c_str()))
{
*pdwValue = aMapSzDword->dwValue;
hr = S_OK;
break;
}
aMapSzDword++;
}
}
TraceError ("HrSetupGetStringFieldMapToDword", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetStringFieldAsBool
//
// Purpose: Gets the value of a boolean field represented as the
// strings "Yes" and "No" in an INF file.
//
// Arguments:
// ctx [in] See the Setup API documentation.
// dwFieldIndex [in]
// pfValue [out] the returned value.
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
HRESULT HrSetupGetStringFieldAsBool (const INFCONTEXT& ctx,
DWORD dwFieldIndex,
BOOL* pfValue)
{
Assert (pfValue);
// Initialize the output parameter.
*pfValue = FALSE;
static const MAP_SZ_DWORD aMapYesNo [] =
{
{ c_szYes, TRUE },
{ c_szNo, FALSE },
};
DWORD dwValue;
HRESULT hr = HrSetupGetStringFieldMapToDword (ctx, dwFieldIndex,
aMapYesNo, celems(aMapYesNo),
&dwValue);
if (SUCCEEDED(hr))
{
*pfValue = !!dwValue;
}
TraceError ("HrSetupGetStringFieldAsBool", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetFirstDword
//
// Purpose: Get a DWORD value from a section in the INF file.
//
// Arguments:
// hinf [in] handle to an open INF file.
// pszSection [in] specifies the section that contains the value.
// pszKey [in] specifies the key that contains the value.
// pdwValue [out] the returned value.
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 17 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetFirstDword (
IN HINF hinf,
IN PCWSTR pszSection,
IN PCWSTR pszKey,
OUT DWORD* pdwValue)
{
Assert (pszSection);
Assert (pszKey);
// Initialize the output parameter.
*pdwValue = 0;
INFCONTEXT ctx;
HRESULT hr = HrSetupFindFirstLine (hinf, pszSection, pszKey, &ctx);
if (S_OK == hr)
{
INT nValue;
hr = HrSetupGetIntField (ctx, c_dwFirstField, &nValue);
if (S_OK == hr)
{
*pdwValue = nValue;
}
}
TraceErrorOptional ("HrSetupGetFirstDword", hr,
(SPAPI_E_LINE_NOT_FOUND == hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetFirstString
//
// Purpose: Get a string value from a section in the INF file.
//
// Arguments:
// hinf [in] handle to an open INF file.
// pszSection [in] specifies the section that contains the value.
// pszKey [in] specifies the key that contains the value.
// pdwValue [out] the returned value.
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 17 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetFirstString (
IN HINF hinf,
IN PCWSTR pszSection,
IN PCWSTR pszKey,
OUT tstring* pstr)
{
Assert (pszSection);
Assert (pszKey);
INFCONTEXT ctx;
HRESULT hr = HrSetupFindFirstLine (hinf, pszSection, pszKey, &ctx);
if (S_OK == hr)
{
hr = HrSetupGetStringField (ctx, c_dwFirstField, pstr);
}
// If we failed for any reason, initialize the output parameter.
//
if (FAILED(hr))
{
pstr->erase ();
}
TraceErrorOptional ("HrSetupGetFirstString", hr,
(SPAPI_E_SECTION_NOT_FOUND == hr) ||
(SPAPI_E_LINE_NOT_FOUND == hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetFirstMultiSzFieldWithAlloc
//
// Purpose: Retrieves the first occurrance of the given key in the given
// section of an INF file, allocates memory for it, and returns
// it in the parameter pszOut.
//
// Arguments:
// hinf [in] handle to an open INF file.
// pszSection [in] specifies the section that contains the value.
// pszKey [in] specifies the key that contains the value.
// pszOut [out] Returns multi-sz field.
//
// Returns: S_OK or a Win32 error code.
//
// Author: danielwe 7 May 1997
//
// Notes: Free the resulting string with MemFree.
//
HRESULT
HrSetupGetFirstMultiSzFieldWithAlloc (
IN HINF hinf,
IN PCWSTR pszSection,
IN PCWSTR pszKey,
OUT PWSTR* ppszOut)
{
Assert(pszSection);
Assert(pszKey);
Assert(ppszOut);
// Initialize the output parameter.
*ppszOut = 0;
INFCONTEXT ctx;
HRESULT hr = HrSetupFindFirstLine (hinf, pszSection, pszKey, &ctx);
if (S_OK == hr)
{
hr = HrSetupGetMultiSzFieldWithAlloc(ctx, c_dwFirstField, ppszOut);
}
TraceErrorOptional("HrSetupGetFirstMultiSzFieldWithAlloc", hr,
(SPAPI_E_LINE_NOT_FOUND == hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetFirstMultiSzMapToDword
//
// Purpose: Get a DWORD value from a section in the INF file.
// The value is represented in the INF file as a multi-sz, but
// it is mapped to a DWORD value based on a caller-specified
// mapping. The string values in the map are compared using
// a case insensitive compare.
//
// Use this when the INF value can be one or more of a fixed
// set of values represented as strings.
//
// Example: [MySection] with a map of:
// MyKey = Ip,Nbf { "Ip", 0x01 }
// { "Ipx", 0x02 }
// { "Nbf", 0x04 }
//
// yields *pdwValue returned as 0x01 | 0x04 = 0x05.
//
// Arguments:
// hinf [in] handle to an open INF file.
// pszSection [in] specifies the section that contains the value.
// pszKey [in] specifies the key that contains the value.
// aMapSzDword [in] array of elements mapping a string to a DWORD.
// cMapSzDword [in] count of elements in the array.
// pdwValue [out] the returned value.
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 17 Apr 1997
//
// Notes: HrOpen must have been called before this call.
//
HRESULT
HrSetupGetFirstMultiSzMapToDword (
IN HINF hinf,
IN PCWSTR pszSection,
IN PCWSTR pszKey,
IN const MAP_SZ_DWORD* aMapSzDword,
IN UINT cMapSzDword,
OUT DWORD* pdwValue)
{
Assert (pszSection);
Assert (pszKey);
// Initialize the output parameter.
*pdwValue = 0;
INFCONTEXT ctx;
HRESULT hr = HrSetupFindFirstLine (hinf, pszSection, pszKey, &ctx);
if (S_OK == hr)
{
hr = HrSetupGetMultiSzFieldMapToDword (ctx, c_dwFirstField,
aMapSzDword, cMapSzDword,
pdwValue);
}
TraceErrorOptional ("HrSetupGetFirstMultiSzMapToDword", hr,
(SPAPI_E_LINE_NOT_FOUND == hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: HrSetupGetFirstStringMapToDword
//
// Purpose: Get a DWORD value from a section in the INF file.
// The value is represented in the INF file as a string, but
// it is mapped to a DWORD value based on a caller-specified
// mapping. The string values in the map are compared using
// a case insensitive compare.
//
// Use this when the INF value can be one of a fixed set of
// values represented as strings.
//
// Example: [MySection] with a map of:
// MyKey = ThisComputer { "Network", 1 }
// { "ThisComputer", 2 }
//
// yields *pdwValue returned as 2.
//
// Arguments:
// hinf [in] handle to an open INF file.
// pszSection [in] specifies the section that contains the value.
// pszKey [in] specifies the key that contains the value.
// aMapSzDword [in] array of elements mapping a string to a DWORD.
// cMapSzDword [in] count of elements in the array.
// pdwValue [out] the returned value.
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 17 Apr 1997
//
// Notes: HrOpen must have been called before this call.
//
HRESULT
HrSetupGetFirstStringMapToDword (
IN HINF hinf,
IN PCWSTR pszSection,
IN PCWSTR pszKey,
IN const MAP_SZ_DWORD* aMapSzDword,
IN UINT cMapSzDword,
OUT DWORD* pdwValue)
{
Assert (pszSection);
Assert (pszKey);
// Initialize the output parameter.
*pdwValue = 0;
INFCONTEXT ctx;
HRESULT hr = HrSetupFindFirstLine (hinf, pszSection, pszKey, &ctx);
if (S_OK == hr)
{
hr = HrSetupGetStringFieldMapToDword (ctx, c_dwFirstField,
aMapSzDword, cMapSzDword,
pdwValue);
}
TraceErrorOptional ("HrSetupGetFirstStringMapToDword", hr,
(SPAPI_E_LINE_NOT_FOUND == hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetFirstStringAsBool
//
// Purpose: Get a boolean value from a section in the INF file.
// The boolean value is represented in the INF file as
// "Yes" or "No" (case insensitive) but the value is returned
// as a BOOL type.
//
// Example: [MySection]
// MyKey = yes
//
// yields *pfValue returned as TRUE.
//
// Arguments:
// hinf [in] handle to an open INF file.
// pszSection [in] specifies the section that contains the value.
// pszKey [in] specifies the key that contains the value.
// pdwValue [out] the returned value.
//
// Returns: S_OK or a Win32 error code.
//
// Author: shaunco 17 Apr 1997
//
// Notes:
//
HRESULT
HrSetupGetFirstStringAsBool (
IN HINF hinf,
IN PCWSTR pszSection,
IN PCWSTR pszKey,
OUT BOOL* pfValue)
{
Assert (hinf);
Assert (pszSection);
Assert (pszKey);
Assert (pfValue);
// Initialize the output parameter.
*pfValue = FALSE;
INFCONTEXT ctx;
HRESULT hr = HrSetupFindFirstLine (hinf, pszSection, pszKey, &ctx);
if (S_OK == hr)
{
hr = HrSetupGetStringFieldAsBool (ctx, c_dwFirstField, pfValue);
}
TraceErrorOptional ("HrSetupGetFirstStringAsBool", hr,
(SPAPI_E_LINE_NOT_FOUND == hr));
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupGetInfInformation
//
// Purpose: Returns the SP_INF_INFORMATION structure for the specified
// INF file to a caller-supplied buffer.
//
// Arguments:
// pvInfSpec [in] See SetupApi documentation for more info
// dwSearchControl [in]
// ppinfInfo [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: BillBe 18 Jan 1998
//
// Notes:
//
HRESULT
HrSetupGetInfInformation (
IN LPCVOID pvInfSpec,
IN DWORD dwSearchControl,
OUT PSP_INF_INFORMATION* ppinfInfo)
{
DWORD dwSize;
BOOL fSuccess;
*ppinfInfo = NULL;
if (fSuccess = SetupGetInfInformation (pvInfSpec, dwSearchControl,
NULL, 0, &dwSize))
{
*ppinfInfo = (PSP_INF_INFORMATION)MemAlloc (dwSize);
fSuccess = SetupGetInfInformation (pvInfSpec, dwSearchControl,
*ppinfInfo, dwSize, 0);
}
HRESULT hr = S_OK;
if (!fSuccess)
{
hr = HrFromLastWin32Error();
MemFree (*ppinfInfo);
*ppinfInfo = NULL;
}
TraceError("HrSetupGetInfInformation", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupIsValidNt5Inf
//
// Purpose: Determines if an inf file is a valid NT5 inf by examining
// its signature.
//
// Arguments:
// hinf [in] Handle to the inf file
//
// Returns: S_OK if valid, SPAPI_E_WRONG_INF_STYLE if invalid,
// or a Win32 error code.
//
// Author: BillBe 18 Jan 1998
//
// Notes: $WINDOWS 95$ is invalid and $CHICAGO$ is
// only valid if it has the required Compatible inf key in
// the version info.
//
HRESULT
HrSetupIsValidNt5Inf (
IN HINF hinf)
{
static const WCHAR c_szSignature[] = INFSTR_KEY_SIGNATURE;
static const WCHAR c_szCompatible[] = L"Compatible";
static const WCHAR c_szChicagoSig[] = L"$Chicago$";
static const WCHAR c_szWinntSig[] = L"$Windows NT$";
static const WCHAR c_szCompatibleValue[] = L"1";
PSP_INF_INFORMATION pinfInfo;
// Get the inf's version info
HRESULT hr = HrSetupGetInfInformation (hinf, INFINFO_INF_SPEC_IS_HINF,
&pinfInfo);
if (S_OK == hr)
{
PWSTR pszSignature;
// Get the signature info
hr = HrSetupQueryInfVersionInformation (pinfInfo, 0,
c_szSignature, &pszSignature);
if (S_OK == hr)
{
// if the inf signature is not windows nt...
if (0 != lstrcmpiW (pszSignature, c_szWinntSig))
{
// if it isn't Chicago, then we don't support it
if (0 != lstrcmpiW (pszSignature, c_szChicagoSig))
{
hr = SPAPI_E_WRONG_INF_STYLE;
}
else
{
// The signature is Chicago so now we check if
// the compatible line exists.
//
PWSTR pszCompatible;
hr = HrSetupQueryInfVersionInformation (pinfInfo, 0,
c_szCompatible, &pszCompatible);
if (S_OK == hr)
{
// We found the compatible line, now make sure
// it is set to c_szCompatibleValue.
//
if (0 != lstrcmpiW (pszCompatible, c_szCompatibleValue))
{
hr = SPAPI_E_WRONG_INF_STYLE;
}
MemFree (pszCompatible);
}
else if (HRESULT_FROM_WIN32(ERROR_INVALID_DATA) == hr)
{
// The Compatible key didn't exist so this is
// considered a windows 95 net inf
hr = SPAPI_E_WRONG_INF_STYLE;
}
}
}
MemFree (pszSignature);
}
MemFree (pinfInfo);
}
TraceError("HrSetupIsValidNt5Inf",
(SPAPI_E_WRONG_INF_STYLE == hr) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupQueryInfVersionInformation
//
// Purpose: Returns INF file version information from an
// SP_INF_INFORMATION structure to a caller-supplied buffer.
//
//
//
// Arguments:
// pinfInfo [in] See SetupApi documentation for more info
// uiIndex [in]
// szKey [in]
// ppszInfo [out]
//
// Returns: S_OK or a Win32 error code.
//
// Author: BillBe 18 Jan 1998
//
// Notes:
//
HRESULT
HrSetupQueryInfVersionInformation (
IN PSP_INF_INFORMATION pinfInfo,
IN UINT uiIndex,
IN PCWSTR pszKey,
OUT PWSTR* ppszInfo)
{
Assert(pinfInfo);
*ppszInfo = NULL;
DWORD dwSize;
BOOL fSuccess = SetupQueryInfVersionInformation (pinfInfo, uiIndex,
pszKey, NULL, 0, &dwSize);
if (fSuccess)
{
*ppszInfo = (PWSTR)MemAlloc (dwSize * sizeof (WCHAR));
fSuccess = SetupQueryInfVersionInformation (pinfInfo, uiIndex, pszKey,
*ppszInfo, dwSize, NULL);
}
HRESULT hr = S_OK;
if (!fSuccess)
{
MemFree (*ppszInfo);
*ppszInfo = NULL;
hr = HrFromLastWin32Error();
}
TraceError("HrSetupQueryInfVersionInformation", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CSetupInfFile::Close
//
// Purpose: Close the INF file. It must have previously opened with
// a call to HrOpen().
//
// Arguments:
// (none)
//
// Returns: nothing
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
void CSetupInfFile::Close ()
{
AssertSz (m_hinf, "You shouldn't be closing a file that is already closed.");
::SetupCloseInfFile (m_hinf);
m_hinf = NULL;
}
//+---------------------------------------------------------------------------
//
// Member: CSetupInfFile::EnsureClosed
//
// Purpose: Ensure the INF file represented by this object is closed.
//
// Arguments:
// (none)
//
// Returns: nothing
//
// Author: shaunco 16 Apr 1997
//
// Notes:
//
void CSetupInfFile::EnsureClosed()
{
if (m_hinf)
{
Close ();
}
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiCallClassInstaller
//
// Purpose: calls the appropriate class installer with the specified
// installation request (DI_FUNCTION).
//
// Arguments:
// dif [in] See SetupApi for more info
// hdi [in] See SetupApi for more info
// pdeid [in] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 25 June 1997
//
// Notes: SPAPI_E_DI_DO_DEFAULT is mapped to S_OK
//
HRESULT
HrSetupDiCallClassInstaller(
IN DI_FUNCTION dif,
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid)
{
Assert(INVALID_HANDLE_VALUE != hdi);
Assert(hdi);
HRESULT hr = S_OK;
// Call the class installer and convert any errors
if (!SetupDiCallClassInstaller(dif, hdi, pdeid))
{
hr = HrFromLastWin32Error();
if (SPAPI_E_DI_DO_DEFAULT == hr)
{
hr = S_OK;
}
}
TraceError("HrSetupDiCallClassInstaller",
(HRESULT_FROM_WIN32(ERROR_CANCELLED) == hr) ? S_OK : hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupCopyOEMInf
//
// Purpose: HRESULT wrapper for SetupCopyOEMInf that returns the
// new file path and name as tstrings
//
// Arguments:
// szSourceName [in] See SetupApi for more info
// szSourceMediaLocation [in]
// dwSourceMediaType [in]
// dwCopyStyle [in]
// pstrDestFilename [out]
// pstrDestFilenameComponent [out]
//
// Returns: HRESULT. S_OK if successful, or Win32 converted error code
//
// Author: billbe 15 May 1997
//
// Notes: See SetupCopyOEMInf in SetupApi for more info
//
HRESULT
HrSetupCopyOemInf(
IN const tstring& strSourceName,
IN const tstring& strSourceMediaLocation, OPTIONAL
IN DWORD dwSourceMediaType,
IN DWORD dwCopyStyle,
OUT tstring* pstrDestFilename, OPTIONAL
OUT tstring* pstrDestFilenameComponent OPTIONAL)
{
Assert(!strSourceName.empty());
BOOL fWin32Success = TRUE;
DWORD cchRequiredSize;
// Copy the file and get the size for the new filename in case it is
// needed
if (fWin32Success = SetupCopyOEMInf(strSourceName.c_str(),
strSourceMediaLocation.c_str(), dwSourceMediaType, dwCopyStyle,
NULL, NULL, &cchRequiredSize, NULL))
{
// If any of the out parameters are specified, we need to get the
// information
if (pstrDestFilename || pstrDestFilenameComponent)
{
PWSTR pszDestPath = NULL;
PWSTR pszDestFilename = NULL;
// now we allocate space to get the destination file path.
// We allocate on the stack for automatic clean-up
// Note: dwRequiredSize includes the terminating NULL
//
pszDestPath = (PWSTR)_alloca(cchRequiredSize * sizeof(WCHAR));
// Get the new file path and filename
if (fWin32Success = SetupCopyOEMInf(strSourceName.c_str(),
strSourceMediaLocation.c_str(), dwSourceMediaType,
dwCopyStyle, pszDestPath, cchRequiredSize, NULL,
&pszDestFilename))
{
// if the file path is needed, assign it
if (pstrDestFilename)
{
*pstrDestFilename = pszDestPath;
}
// If the user wants just the filename, assign it to the
// string
if (pstrDestFilenameComponent)
{
*pstrDestFilenameComponent = pszDestFilename;
}
}
else
{
// initialize out params on failure
//
if (pstrDestFilename)
{
pstrDestFilename->erase();
}
if (pstrDestFilenameComponent)
{
pstrDestFilenameComponent->erase();
}
}
}
}
HRESULT hr = S_OK;
if (!fWin32Success)
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupCopyOEMInf", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupCopyOEMInf
//
// Purpose: HRESULT wrapper for SetupCopyOEMInf that returns the
// new file path and name as tstrings
//
// Arguments:
// pszSourceName [in] See SetupApi for more info
// pszSourceMediaLocation [in]
// dwSourceMediaType [in]
// dwCopyStyle [in]
// pszDestFilename [out] // must be at least _MAX_PATH chars.
// ppszDestFilenameComponent [out]
//
// Returns: HRESULT. S_OK if successful, or Win32 converted error code
//
// Author: billbe 15 May 1997
//
// Notes: See SetupCopyOEMInf in SetupApi for more info
//
HRESULT
HrSetupCopyOemInfBuffer(
IN PCWSTR pszSourceName,
IN PCWSTR pszSourceMediaLocation, OPTIONAL
IN DWORD SourceMediaType,
IN DWORD CopyStyle,
OUT PWSTR pszDestFilename,
IN DWORD cchDestFilename,
OUT PWSTR* ppszDestFilenameComponent OPTIONAL)
{
Assert(pszSourceName);
Assert(pszDestFilename);
BOOL fWin32Success = TRUE;
if (!(fWin32Success = SetupCopyOEMInf(pszSourceName,
pszSourceMediaLocation, SourceMediaType,
CopyStyle, pszDestFilename, cchDestFilename, NULL,
ppszDestFilenameComponent)))
{
// initialize out params on failure
//
*pszDestFilename = 0;
if (*ppszDestFilenameComponent)
{
*ppszDestFilenameComponent = NULL;
}
}
HRESULT hr = S_OK;
if (!fWin32Success)
{
hr = HrFromLastWin32Error();
}
TraceHr (ttidError, FAL, hr, FALSE, "HrSetupCopyOEMInf");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiBuildDriverInfoList
//
// Purpose: builds a list of drivers associated with a specified device
// instance or with the device information set's global
// class driver list.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in, out]
// dwDriverType [in]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiBuildDriverInfoList(IN HDEVINFO hdi, IN OUT PSP_DEVINFO_DATA pdeid,
IN DWORD dwDriverType)
{
Assert(IsValidHandle(hdi));
HRESULT hr = S_OK;
// Build the list
if (!SetupDiBuildDriverInfoList(hdi, pdeid, dwDriverType))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiBuildDriverInfoList", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiCreateDeviceInfo
//
// Purpose: creates a new device information element and adds it as a
// new member to the specified device information set.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pszDeviceName [in] See SetupApi for more info
// guidClass [in] See SetupApi for more info
// pszDesc [in] See SetupApi for more info
// hwndParent [in] See SetupApi for more info
// dwFlags [in] See SetupApi for more info
// pdeid [out] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes: pdeid is initialized and its cbSize field set by this fcn
//
HRESULT
HrSetupDiCreateDeviceInfo(
IN HDEVINFO hdi,
IN PCWSTR pszDeviceName,
IN const GUID& guidClass,
IN PCWSTR pszDesc, OPTIONAL
IN HWND hwndParent, OPTIONAL
IN DWORD dwFlags,
OUT PSP_DEVINFO_DATA pdeid OPTIONAL)
{
Assert(IsValidHandle(hdi));
Assert(pszDeviceName);
if (pdeid)
{
ZeroMemory(pdeid, sizeof(SP_DEVINFO_DATA));
pdeid->cbSize = sizeof(SP_DEVINFO_DATA);
}
HRESULT hr = S_OK;
// Create the device info node
if (!SetupDiCreateDeviceInfo (hdi, pszDeviceName, &guidClass, pszDesc,
hwndParent, dwFlags, pdeid))
{
hr = HrFromLastWin32Error();
}
TraceError ("HrSetupDiCreateDeviceInfo", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiEnumDeviceInfo
//
// Purpose: Enumerates the members of the specified device information
// set.
//
// Arguments:
// hdi [in] See SetupApi for more info
// dwIndex [in] See SetupApi for more info
// pdeid [in] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 13 June 1997
//
// Notes:
//
HRESULT
HrSetupDiEnumDeviceInfo(
IN HDEVINFO hdi,
IN DWORD dwIndex,
OUT PSP_DEVINFO_DATA pdeid)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
HRESULT hr;
ZeroMemory(pdeid, sizeof(SP_DEVINFO_DATA));
pdeid->cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiEnumDeviceInfo (hdi, dwIndex, pdeid))
{
hr = S_OK;
}
else
{
hr = HrFromLastWin32Error();
}
TraceErrorOptional("HrSetupDiEnumDeviceInfo", hr,
HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiEnumDriverInfo
//
// Purpose: Enumerates the members of a driver information list.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// dwDriverType [in]
// dwIndex [in]
// pdrid [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiEnumDriverInfo(
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN DWORD dwDriverType,
IN DWORD dwIndex,
OUT PSP_DRVINFO_DATA pdrid)
{
Assert(IsValidHandle(hdi));
Assert(pdrid);
HRESULT hr = S_OK;
// initialize the out param
ZeroMemory(pdrid, sizeof(SP_DRVINFO_DATA));
pdrid->cbSize = sizeof(SP_DRVINFO_DATA);
// call the enum fcn
if (!SetupDiEnumDriverInfo(hdi, pdeid, dwDriverType, dwIndex, pdrid))
{
hr = HrFromLastWin32Error();
}
TraceErrorOptional("HrSetupDiEnumDriverInfo", hr,
HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSelectBestCompatDrv
//
// Purpose: Finds and selects the best driver for the current device.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in][out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiSelectBestCompatDrv(
IN HDEVINFO hdi,
IN OUT PSP_DEVINFO_DATA pdeid)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
HRESULT hr = S_OK;
// call the SelectBestCompatDrv fcn
if (!SetupDiSelectBestCompatDrv(hdi, pdeid))
{
hr = HrFromLastWin32Error();
}
TraceErrorOptional("HrSetupDiSelectBestCompatDrv", hr,
HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetDeviceInfoListClass
//
// Purpose: Retrieves the class GUID associated with a device
// information set if it has an associated class.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pguid [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiGetDeviceInfoListClass (
IN HDEVINFO hdi,
OUT GUID* pguid)
{
Assert(IsValidHandle(hdi));
Assert(pguid);
HRESULT hr = S_OK;
// Get the guid for the HDEVINFO
if (!SetupDiGetDeviceInfoListClass (hdi, pguid))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetDeviceInfoListClass", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetClassDevs
//
// Purpose: Returns a device information set that contains all installed
// devices of a specified class.
//
// Arguments:
// pguidClass [in] See SetupApi for more info
// pszEnumerator [in] See SetupApi for more info
// hwndParent [in] See SetupApi for more info
// dwFlags [in] See SetupApi for more info
// phdi [out] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 13 June 1997
//
// Notes:
//
HRESULT
HrSetupDiGetClassDevs (
IN const GUID* pguidClass, OPTIONAL
IN PCWSTR pszEnumerator, OPTIONAL
IN HWND hwndParent, OPTIONAL
IN DWORD dwFlags,
OUT HDEVINFO* phdi)
{
Assert(phdi);
HRESULT hr;
HDEVINFO hdi = SetupDiGetClassDevsW (pguidClass, pszEnumerator,
hwndParent, dwFlags);
if (INVALID_HANDLE_VALUE != hdi)
{
hr = S_OK;
*phdi = hdi;
}
else
{
hr = HrFromLastWin32Error();
*phdi = NULL;
}
TraceError ("HrSetupDiGetClassDevs", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetDeviceInstanceId
//
// Purpose: HRESULT wrapper for SetupDiGetDeviceInstanceId.
//
// Arguments:
// hdi [in] See SetupApi for more info.
// pdeid [in] See SetupApi for more info.
// pszId [out] The device instance Id for the net card.
// cchId [in] The size of pszId in characters.
// pcchRequired [out] Optional. The required buffer size in characters.
//
//
// Returns: HRESULT. S_OK if successful, error code otherwise.
//
// Author: billbe 26 Mar 1997
//
// Notes: See SetupDiGetDeviceInstanceId in Device Installer for more info.
//
HRESULT
HrSetupDiGetDeviceInstanceId(
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
OUT PWSTR pszId,
IN DWORD cchId,
OUT OPTIONAL DWORD* pcchRequired)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
DWORD cchRequiredSize;
BOOL fSuccess = TRUE;
HRESULT hr = S_OK;
// Get the buffer length required for the instance Id.
if (!(fSuccess = SetupDiGetDeviceInstanceIdW(hdi, pdeid, NULL, 0,
&cchRequiredSize)))
{
// If all went well, we should have a buffer error.
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
// Since ERROR_INSUFFICIENT_BUFFER is really a success
// for us, we will reset the success flag.
fSuccess = TRUE;
// Set the out param if it was specified.
if (pcchRequired)
{
*pcchRequired = cchRequiredSize;
}
// If the buffer sent in was large enough, go ahead and use it.
if (cchId >= cchRequiredSize)
{
fSuccess = SetupDiGetDeviceInstanceIdW(hdi, pdeid,
pszId, cchId, NULL);
}
}
}
#ifdef DBG // Just being safe
else
{
// This should never happen since we sent in no buffer
AssertSz(FALSE, "SetupDiGetDeviceInstanceId returned success"
" even though it was given no buffer");
}
#endif // DBG
// We used SetupApi so we need to convert any errors
if (!fSuccess)
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetDeviceInstanceId", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiInstallDevice
//
// Purpose: Wrapper for SetupDiInstallDevice
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiInstallDevice (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
HRESULT hr = S_OK;
// Let SetupApi install the specfied device
if (!SetupDiInstallDevice (hdi, pdeid))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiInstallDevice", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiOpenDevRegKey
//
// Purpose: Return an HKEY to the hardware device's driver instance key
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// dwScope [in]
// dwHwProfile [in]
// dwKeyType [in]
// samDesired [in]
// phkey [out]
//
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: billbe 7 May 1997
//
// Notes:
//
HRESULT
HrSetupDiOpenDevRegKey (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN DWORD dwScope,
IN DWORD dwHwProfile,
IN DWORD dwKeyType,
IN REGSAM samDesired,
OUT HKEY* phkey)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
Assert(phkey);
// Try to open the registry key
//
HRESULT hr;
HKEY hkey = SetupDiOpenDevRegKey(hdi, pdeid, dwScope, dwHwProfile,
dwKeyType, samDesired);
if (INVALID_HANDLE_VALUE != hkey)
{
hr = S_OK;
*phkey = hkey;
}
else
{
hr = HrFromLastWin32Error();
*phkey = NULL;
}
TraceErrorOptional("HrSetupDiOpenDevRegKey", hr,
(SPAPI_E_DEVINFO_NOT_REGISTERED == hr) ||
(SPAPI_E_KEY_DOES_NOT_EXIST == hr));
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSetClassInstallParams
//
// Purpose: sets or clears class install parameters for a device
// information set or a particular device information element.
//
// Arguments:
// hdi [in] See Device Installer API for more info
// pdeid [in]
// pcih [in]
// cbSize [in]
//
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiSetClassInstallParams (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid, OPTIONAL
IN PSP_CLASSINSTALL_HEADER pcih, OPTIONAL
IN DWORD cbSize)
{
Assert(IsValidHandle(hdi));
HRESULT hr = S_OK;
// Set or clear the params
if (!SetupDiSetClassInstallParams(hdi, pdeid, pcih, cbSize))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiSetClassInstallParams", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetFixedSizeClassInstallParams
//
// Purpose: Gets a fixed size of an info list's ot device's class install
// parameters for a device.
//
// Arguments:
// hdi [in] See Device Installer for more info
// pdeid [in]
// pcih [in]
// cbSize [in]
//
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiGetFixedSizeClassInstallParams (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN PSP_CLASSINSTALL_HEADER pcih,
IN INT cbSize)
{
Assert(IsValidHandle(hdi));
Assert(pcih);
HRESULT hr = S_OK;
ZeroMemory(pcih, cbSize);
pcih->cbSize = sizeof(SP_CLASSINSTALL_HEADER);
// Device Installer Api uses an all purpose GetClassInstallParams
// function. Several structures contain an SP_CLASSINSTALL_HEADER
// as their first member.
if (!SetupDiGetClassInstallParams(hdi, pdeid, pcih, cbSize, NULL))
{
hr = HrFromLastWin32Error();
}
TraceErrorOptional("HrSetupDiGetFixedSizeClassInstallParams", hr,
SPAPI_E_NO_CLASSINSTALL_PARAMS == hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetSelectedDriver
//
// Purpose: Retrieves the member of a driver list that has been selected
// as the controlling driver.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// pdrid [out]
//
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiGetSelectedDriver (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
OUT PSP_DRVINFO_DATA pdrid)
{
Assert(IsValidHandle(hdi));
Assert(pdrid);
// initialize and set the cbSize field
ZeroMemory(pdrid, sizeof(*pdrid));
pdrid->cbSize = sizeof(*pdrid);
HRESULT hr = S_OK;
// Set pdrid as the selected driver
if (!SetupDiGetSelectedDriver(hdi, pdeid, pdrid))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetSelectedDriver",
(SPAPI_E_NO_DRIVER_SELECTED == hr) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupDiGetDriverInfoDetail
//
// Purpose: Gets details on the driver referenced by the given parameters.
//
// Arguments:
// hdi []
// pdeid [] See SetupAPI for more info
// pdrid []
// ppdridd []
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: danielwe 5 May 1998
//
// Notes:
//
HRESULT
HrSetupDiGetDriverInfoDetail (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN PSP_DRVINFO_DATA pdrid,
OUT PSP_DRVINFO_DETAIL_DATA* ppdridd)
{
HRESULT hr = S_OK;
BOOL fSuccess = TRUE;
DWORD dwRequiredSize = 0;
Assert(IsValidHandle(hdi));
Assert(pdrid);
Assert(ppdridd);
Assert(pdrid);
*ppdridd = NULL;
// Get the size needed for the driver detail
if (!(fSuccess = SetupDiGetDriverInfoDetailW (hdi, pdeid, pdrid, NULL,
0, &dwRequiredSize)))
{
// We should have received an insufficient buffer error since we
// sent no buffer
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
// Since this is ERROR_INSUFFICIENT_BUFFER is really a
// success for us, we will reset the success flag.
fSuccess = TRUE;
// Now we allocate our buffer for the driver detail data
// The size of the buffer is variable but it is a
// PSP_DEVINFO_DETAIL_DATA.
*ppdridd = (PSP_DRVINFO_DETAIL_DATA)MemAlloc (dwRequiredSize);
if (*ppdridd)
{
//initialize the variable
ZeroMemory(*ppdridd, dwRequiredSize);
(*ppdridd)->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
// Get detailed info
fSuccess = SetupDiGetDriverInfoDetailW (hdi, pdeid, pdrid,
*ppdridd, dwRequiredSize, NULL);
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
else
{
// This should NEVER happen
AssertSz(FALSE, "HrSetupDiGetDriverInfoDetail succeeded with no "
"buffer!");
}
// We have been using Device Installer Api so convert any errors
if (!fSuccess)
{
hr = HrFromLastWin32Error();
}
// clean up on failure
if (FAILED(hr))
{
MemFree (*ppdridd);
*ppdridd = NULL;
}
TraceError("HrSetupDiGetDriverInfoDetail", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSetSelectedDriver
//
// Purpose: Sets the specified member of a driver list as the
// currently-selected driver. It can also be used to reset
// the driver list so that there is no currently-selected
// driver.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// pdrid [in, out]
//
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiSetSelectedDriver (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN OUT PSP_DRVINFO_DATA pdrid)
{
Assert(IsValidHandle(hdi));
Assert(pdrid);
HRESULT hr = S_OK;
// Set pdrid as the selected driver
if (!SetupDiSetSelectedDriver(hdi, pdeid, pdrid))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiSetSelectedDriver", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiCreateDevRegKey
//
// Purpose: Creates and returns an HKEY to the hardware device's driver
// instance key
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// dwScope [in]
// dwHwProfile [in]
// dwKeyType [in]
// hinf [in] OPTIONAL
// pszInfSectionName [in] OPTIONAL
// phkey [out]
//
//
// Returns: HRESULT. S_OK if successful, Win32 error code otherwise
//
// Author: billbe 4 June 1997
//
// Notes:
//
HRESULT
HrSetupDiCreateDevRegKey (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN DWORD dwScope,
IN DWORD dwHwProfile,
IN DWORD dwKeyType,
IN HINF hinf,
PCWSTR pszInfSectionName,
OUT HKEY* phkey)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
Assert(phkey);
// Try to create the registry key and process the inf section, if
// specified
//
HRESULT hr;
HKEY hkey = SetupDiCreateDevRegKeyW(hdi, pdeid, dwScope, dwHwProfile,
dwKeyType, hinf, pszInfSectionName);
if (INVALID_HANDLE_VALUE != hkey)
{
hr = S_OK;
*phkey = hkey;
}
else
{
hr = HrFromLastWin32Error();
*phkey = NULL;
}
TraceError("HrSetupDiCreateDevRegKey", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetActualSectionToInstall
//
// Purpose: The sections in an inf file may have OS and platform suffixes
// appended to them. This function searches for a section that
// has pszSectionName as its base and has a certain suffix.
// For example on an x86 NT machine, given a section name of
// INSTALL, the search would start with INSTALL.NTx86, if that
// is not found, then INSTALL.NT is searched for.
// If that is not found INSTALL is returned.
//
// Arguments:
// hinf [in] SetupApi inf file handle
// pszSectionName [in] the section name to base the search on
// pstrActualSectionName [out] The actual section name with extension
// pstrExtension [out] OPTIONAL. The extension part of the
// pstrActualSectionName.
// This includes "."
//
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 27 Mar 1997
//
// Notes: See SetupDiGetActualSectionToInstall in SetupApi documention
// for more info
//
HRESULT
HrSetupDiGetActualSectionToInstall(
IN HINF hinf,
IN PCWSTR pszSectionName,
OUT tstring* pstrActualSectionName,
OUT tstring* pstrExtension OPTIONAL)
{
Assert(IsValidHandle(hinf));
Assert(pszSectionName);
Assert(pstrActualSectionName);
// strSectionName might need to be decorated with OS
// and Platform specific suffixes. The next call will return the actual
// decorated section name or our current section name if the decorated
// one does not exist.
//
BOOL fSuccess = TRUE;
DWORD cchRequiredSize;
// Get the buffer length required
if (fSuccess = SetupDiGetActualSectionToInstallW(hinf,
pszSectionName, NULL, 0, &cchRequiredSize, NULL))
{
// now we allocate space to get the actual section name
// we allocate on the stack for automatic clean-up
// Note: dwRequiredSize includes the terminating NULL
//
PWSTR pszActualSection = NULL;
pszActualSection = (PWSTR)_alloca(cchRequiredSize * sizeof(WCHAR));
PWSTR pszExtension = NULL;
// Now fill the temporary and assign it to the OUT parameter
if (fSuccess = SetupDiGetActualSectionToInstallW(hinf,
pszSectionName, pszActualSection, cchRequiredSize,
NULL, &pszExtension))
{
*pstrActualSectionName = pszActualSection;
// If the user wants the extension assign it to the string
// or assign the empty string if no extension was found
if (pstrExtension)
{
*pstrExtension = (pszExtension ? pszExtension : c_szEmpty);
}
}
else
{
// initialize out params on failure
pstrActualSectionName->erase();
if (pstrExtension)
{
pstrExtension->erase();
}
}
}
// We used SetupApi so errors have to be converted
HRESULT hr = S_OK;
if (!fSuccess)
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetActualSectionToInstall", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetActualSectionToInstallWithAlloc
//
// Purpose: The sections in an inf file may have OS and platform suffixes
// appended to them. This function searches for a section that
// has pszSectionName as its base and has a certain suffix.
// For example on an x86 NT machine, given a section name of
// INSTALL, the search would start with INSTALL.NTx86, if that
// is not found, then INSTALL.NT is searched for.
// If that is not found INSTALL is returned.
//
// Arguments:
// hinf [in] SetupApi inf file handle.
// pszSection [in] the section name to base the search on.
// ppszActualSection [out] The actual section name with extension.
// If the actual section is the same as
// pszSectionName, *ppszActualSectionName
// will be NULL.
// ppszExtension [out] OPTIONAL. The extension part of the
// *ppszActualSectionName. This includes "."
//
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 27 Mar 1997
//
// Notes: See SetupDiGetActualSectionToInstall in SetupApi documention
// for more info
//
HRESULT
HrSetupDiGetActualSectionToInstallWithAlloc(
IN HINF hinf,
IN PWSTR pszSection,
OUT PWSTR* ppszActualSection,
OUT PWSTR* ppszExtension OPTIONAL)
{
Assert(IsValidHandle(hinf));
Assert(pszSection);
Assert(ppszActualSection);
// pszSectionName might need to be decorated with OS
// and Platform specific suffixes. The next call will return the actual
// decorated section name or our current section name if the decorated
// one does not exist.
//
HRESULT hr = S_OK;
BOOL fSuccess = TRUE;
DWORD cchRequiredSize;
*ppszActualSection = NULL;
if (ppszExtension)
{
*ppszExtension = NULL;
}
// Get the buffer length required
if (fSuccess = SetupDiGetActualSectionToInstallW(hinf,
pszSection, NULL, 0, &cchRequiredSize, NULL))
{
// We are assuming the section is not changing. If cchRequired is
// larger than the current section name buffer than we will allocate
// and fill the out param.
//
// If the section name is teh same, then we will not allocate. But
// if ppszExtension is specified then we need to send in the original
// section name buffer since ppszExtension will point to a location
// within it.
//
PWSTR pszBuffer = pszSection;
if ((wcslen(pszSection) + 1) < cchRequiredSize)
{
hr = E_OUTOFMEMORY;
*ppszActualSection = new WCHAR[cchRequiredSize * sizeof(WCHAR)];
pszBuffer = *ppszActualSection;
}
// if the section name is different (we allocated) or the
// extension out param was specified, then we need to call the fcn.
if (pszBuffer && ((pszBuffer != pszSection) || ppszExtension))
{
// Now fill the temporary and assign it to the OUT parameter
if (!(fSuccess = SetupDiGetActualSectionToInstallW(hinf,
pszSection, pszBuffer, cchRequiredSize,
NULL, ppszExtension)))
{
// initialize out params on failure
delete [] *ppszActualSection;
*ppszActualSection = NULL;
if (ppszExtension)
{
*ppszExtension = NULL;
}
}
}
}
// We used SetupApi so errors have to be converted
if (SUCCEEDED(hr) && !fSuccess)
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetActualSectionToInstallWithAlloc", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetActualSectionToInstallWithBuffer
//
// Purpose: The sections in an inf file may have OS and platform suffixes
// appended to them. This function searches for a section that
// has pszSectionName as its base and has a certain suffix.
// For example on an x86 NT machine, given a section name of
// INSTALL, the search would start with INSTALL.NTx86, if that
// is not found, then INSTALL.NT is searched for.
// If that is not found INSTALL is returned.
//
// Arguments:
// hinf [in] SetupApi inf file handle.
// pszSection [in] The section name to base the search on.
// pszActualSection [out] The actual section name with extension
// Buffer must be LINE_LEN characters.
// cchActualSection [in] Size of pszActualSection in characters.
// pcchRequired [out] OPTIONAL. Reuqired size of buffer in
// characters.
// ppszExtension [out] OPTIONAL. The extension part of the
// pszActualSection. This includes "."
//
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 27 Mar 1997
//
// Notes: See SetupDiGetActualSectionToInstall in SetupApi documention
// for more info
//
HRESULT
HrSetupDiGetActualSectionToInstallWithBuffer(
IN HINF hinf,
IN PCWSTR pszSection,
OUT PWSTR pszActualSection,
IN DWORD cchActualSection,
OUT DWORD* pcchRequired,
OUT PWSTR* ppszExtension OPTIONAL)
{
Assert(IsValidHandle(hinf));
Assert(pszSection);
Assert(pszActualSection);
// pszSectionName might need to be decorated with OS
// and Platform specific suffixes. The next call will return the actual
// decorated section name or our current section name if the decorated
// one does not exist.
//
BOOL fSuccess = TRUE;
DWORD cchRequiredSize;
*pszActualSection = 0;
if (ppszExtension)
{
*ppszExtension = NULL;
}
// Get the buffer length required
if (fSuccess = SetupDiGetActualSectionToInstallW(hinf,
pszSection, NULL, 0, &cchRequiredSize, NULL))
{
if (pcchRequired)
{
*pcchRequired = cchRequiredSize;
}
// If the buffer sent in is large enough, get the section name.
if (cchActualSection >= cchRequiredSize)
{
if (!(fSuccess = SetupDiGetActualSectionToInstallW(hinf,
pszSection, pszActualSection, cchActualSection,
NULL, ppszExtension)))
{
// cleanup on failure.
*pszActualSection = 0;
}
}
}
// We used SetupApi so errors have to be converted
HRESULT hr = S_OK;
if (!fSuccess)
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetActualSectionToInstallWithBuffer", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetDeviceInstallParams
//
// Purpose: Returns the device install params header of a
// device info set/data. Set SetupDiGetDeviceInstallParams
// in the SetupApi for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in] See SetupApi for more info
// pdeip [out] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 May 1997
//
// Notes: This function will clear the variable pdeip and set its
// cbSize field.
//
HRESULT
HrSetupDiGetDeviceInstallParams (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid, OPTIONAL
OUT PSP_DEVINSTALL_PARAMS pdeip)
{
Assert(IsValidHandle(hdi));
Assert(pdeip);
HRESULT hr = S_OK;
// initialize out parameter and set its cbSize field
//
ZeroMemory(pdeip, sizeof(SP_DEVINSTALL_PARAMS));
pdeip->cbSize = sizeof(SP_DEVINSTALL_PARAMS);
// get the header
if (!SetupDiGetDeviceInstallParams(hdi, pdeid, pdeip))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetDeviceInstallParams", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetDriverInstallParams
//
// Purpose: Retrieves install parameters for the specified driver.
// See SetupApi for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// pdrid [in]
// pdrip [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes: This function will clear the variable pdrip and set its
// cbSize field.
//
HRESULT
HrSetupDiGetDriverInstallParams (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid, OPTIONAL
IN PSP_DRVINFO_DATA pdrid,
OUT PSP_DRVINSTALL_PARAMS pdrip)
{
Assert(IsValidHandle(hdi));
Assert(pdrid);
Assert(pdrip);
HRESULT hr = S_OK;
// initialize out parameter and set its cbSize field
//
ZeroMemory(pdrip, sizeof(SP_DRVINSTALL_PARAMS));
pdrip->cbSize = sizeof(SP_DRVINSTALL_PARAMS);
// get the header
if (!SetupDiGetDriverInstallParams(hdi, pdeid, pdrid, pdrip))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetDriverInstallParams", hr);
return hr;
}
VOID
SetupDiSetConfigFlags (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN DWORD dwFlags,
IN SD_FLAGS_BINARY_OP eOp)
{
DWORD dwConfigFlags = 0;
// Get the current config flags
(VOID) HrSetupDiGetDeviceRegistryProperty(hdi, pdeid,
SPDRP_CONFIGFLAGS, NULL, (BYTE*)&dwConfigFlags,
sizeof(dwConfigFlags), NULL);
// Perform the requested operation
switch (eOp)
{
case SDFBO_AND:
dwConfigFlags &= dwFlags;
break;
case SDFBO_OR:
dwConfigFlags |= dwFlags;
break;
case SDFBO_XOR:
dwConfigFlags ^= dwFlags;
break;
default:
AssertSz(FALSE, "Invalid binary op in HrSetupDiSetConfigFlags");
}
(VOID) HrSetupDiSetDeviceRegistryProperty(hdi, pdeid, SPDRP_CONFIGFLAGS,
(BYTE*)&dwConfigFlags, sizeof(dwConfigFlags));
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSetDeviceInstallParams
//
// Purpose: Sets the device install params header of a
// device info set/data. Set SetupDiSetDeviceInstallParams
// in the SetupApi for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in] See SetupApi for more info
// pdeip [in] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 May 1997
//
// Notes:
//
HRESULT
HrSetupDiSetDeviceInstallParams (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid, OPTIONAL
IN PSP_DEVINSTALL_PARAMS pdeip)
{
Assert(IsValidHandle(hdi));
Assert(pdeip);
Assert(pdeip->cbSize == sizeof(SP_DEVINSTALL_PARAMS));
HRESULT hr = S_OK;
// set the header
if (!SetupDiSetDeviceInstallParams(hdi, pdeid, pdeip))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiSetDeviceInstallParams", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSetDriverInstallParams
//
// Purpose: Establishes install parameters for the specified driver.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// pdrid [in]
// pdrip [in]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiSetDriverInstallParams (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid, OPTIONAL
IN PSP_DRVINFO_DATA pdrid,
IN PSP_DRVINSTALL_PARAMS pdrip)
{
Assert(IsValidHandle(hdi));
Assert(pdrid);
Assert(pdrip);
Assert(pdrip->cbSize == sizeof(SP_DRVINSTALL_PARAMS));
HRESULT hr = S_OK;
// set the header
if (!SetupDiSetDriverInstallParams(hdi, pdeid, pdrid, pdrip))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiSetDriverInstallParams", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSetDeipFlags
//
// Purpose: This sets given flags in a dev info data
//
// Arguments:
// hdi [in] See Device Installer Api for more info
// pdeid [in] See Device Installer Api for more info
// dwFlags [in] Flags to set
// eFlagType [in] Which flags field to set with dwFlags
// eClobber [in] Whether to add to existing flags or relace them
//
// Returns: HRESULT. S_OK if successful,
// a Win32 converted error otherwise
//
//
// Author: billbe 3 Feb 1998
//
// Notes:
//
HRESULT
HrSetupDiSetDeipFlags (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN DWORD dwFlags, SD_DEID_FLAG_TYPE eFlagType,
IN SD_FLAGS_BINARY_OP eOp)
{
Assert(IsValidHandle(hdi));
SP_DEVINSTALL_PARAMS deip;
// Get the install params
HRESULT hr = HrSetupDiGetDeviceInstallParams (hdi, pdeid, &deip);
if (S_OK == hr)
{
DWORD* pFlags;
// Set our pointer to the right flag type
switch (eFlagType)
{
case SDDFT_FLAGS:
pFlags = &deip.Flags;
break;
case SDDFT_FLAGSEX:
pFlags = &deip.FlagsEx;
break;
default:
AssertSz(FALSE, "Invalid Flag type in HrSetupDiSetDeipFlags");
break;
}
// Perform the requested operation
switch (eOp)
{
case SDFBO_AND:
*pFlags &= dwFlags;
break;
case SDFBO_OR:
*pFlags |= dwFlags;
break;
case SDFBO_XOR:
*pFlags ^= dwFlags;
break;
default:
AssertSz(FALSE, "Invalid binary op in HrSetupDiSetDeipFlags");
}
// update the params
hr = HrSetupDiSetDeviceInstallParams (hdi, pdeid, &deip);
}
TraceError ("HrSetupDiSetDeipFlags", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiRemoveDevice
//
// Purpose: Calls SetupApi to remove a device. See
// SetupDiRemoveDevice for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 27 May 1997
//
// Notes: This is used for enumerated Net class components
//
HRESULT
HrSetupDiRemoveDevice(
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
HRESULT hr = S_OK;
if (!SetupDiRemoveDevice(hdi,pdeid))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiRemoveDevice", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiOpenDeviceInfo
//
// Purpose: Retrieves information about an existing device instance and
// adds it to the specified device information set
//
// Arguments:
// hdi [in] See SetupApi for more info
// pszPnpInstanceId [in] See SetupApi for more info
// hwndParent [in] See SetupApi for more info
// dwOpenFlags [in] See SetupApi for more info
// pdeid [out] See SetupApi for more info OPTIONAL
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 27 May 1997
//
// Notes: This is used for enumerated Net class components
//
HRESULT
HrSetupDiOpenDeviceInfo(
IN const HDEVINFO hdi,
IN PCWSTR pszPnpInstanceId,
IN HWND hwndParent,
IN DWORD dwOpenFlags,
OUT PSP_DEVINFO_DATA pdeid OPTIONAL)
{
Assert(IsValidHandle(hdi));
Assert(pszPnpInstanceId);
// If the out param was specified, clear it and set its cbSize field
//
if (pdeid)
{
ZeroMemory(pdeid, sizeof(*pdeid));
pdeid->cbSize = sizeof(*pdeid);
}
HRESULT hr = S_OK;
if (!SetupDiOpenDeviceInfo(hdi, pszPnpInstanceId, hwndParent, dwOpenFlags,
pdeid))
{
hr = HrFromLastWin32Error();
}
TraceHr (ttidError, FAL, hr, SPAPI_E_NO_SUCH_DEVINST == hr,
"HrSetupDiOpenDeviceInfo");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiCreateDeviceInfoList
//
// Purpose: Creates an empty device information set.
//
// Arguments:
// pguidClass [in] See SetupApi for more info
// hwndParent [in] See SetupApi for more info
// phdi [out] See SetupApi for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 27 May 1997
//
// Notes:
//
HRESULT
HrSetupDiCreateDeviceInfoList (
IN const GUID* pguidClass,
IN HWND hwndParent,
OUT HDEVINFO* phdi)
{
Assert(phdi);
HRESULT hr;
// Try to create the info set
//
HDEVINFO hdi = SetupDiCreateDeviceInfoList (pguidClass, hwndParent);
if (INVALID_HANDLE_VALUE != hdi)
{
hr = S_OK;
*phdi = hdi;
}
else
{
hr = HrFromLastWin32Error();
*phdi = NULL;
}
TraceError("HrSetupDiCreateDeviceInfoList", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetDeviceRegistryPropertyWithAlloc
//
// Purpose: Returns the requested property of a device
// See SetupApi for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// dwProperty [in]
// pdwRegType [out]
// ppbBuffer [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 1 June 1997
//
// Notes:
//
HRESULT
HrSetupDiGetDeviceRegistryPropertyWithAlloc(
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN DWORD dwProperty,
OUT DWORD* pdwRegType, OPTIONAL
OUT BYTE** ppbBuffer)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
Assert(ppbBuffer);
*ppbBuffer = NULL;
DWORD cbReqSize;
HRESULT hr = S_OK;
// Get the size needed for the buffer
BOOL fWin32Success = SetupDiGetDeviceRegistryPropertyW(hdi, pdeid,
dwProperty, NULL, NULL, 0, &cbReqSize);
// We expect failure since we want the buffer size and sent in no buffer
if (!fWin32Success)
{
if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
{
// Not really an error
fWin32Success = TRUE;
}
if (fWin32Success)
{
*ppbBuffer = (BYTE*) MemAlloc (cbReqSize);
if (*ppbBuffer)
{
// Now get the actual information
fWin32Success = SetupDiGetDeviceRegistryPropertyW(hdi, pdeid,
dwProperty, pdwRegType, *ppbBuffer, cbReqSize, NULL);
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
// All failures are converted to HRESULTS
if (SUCCEEDED(hr) && !fWin32Success)
{
MemFree (*ppbBuffer);
*ppbBuffer = NULL;
hr = HrFromLastWin32Error();
}
TraceHr (ttidError, FAL, hr ,
(HRESULT_FROM_WIN32(ERROR_INVALID_DATA) == hr) ||
(SPAPI_E_NO_SUCH_DEVINST == hr),
"HrSetupDiGetDeviceRegistryPropertyWithAlloc");
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetDeviceRegistryProperty
//
// Purpose: Returns the requested property of a device
// See SetupApi for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// dwProperty [in]
// pdwRegType [out]
// ppbBuffer [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 1 June 1997
//
// Notes:
//
HRESULT
HrSetupDiGetDeviceRegistryProperty(
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN DWORD dwProperty,
OUT DWORD* pdwRegType, OPTIONAL
OUT BYTE* pbBuffer,
IN DWORD cbBufferSize,
OUT DWORD* pcbRequiredSize OPTIONAL)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
// Get the size needed for the buffer
BOOL fWin32Success = SetupDiGetDeviceRegistryPropertyW(hdi, pdeid, dwProperty,
pdwRegType, pbBuffer, cbBufferSize, pcbRequiredSize);
HRESULT hr = S_OK;
// All failures are converted to HRESULTS
if (!fWin32Success)
{
if (pbBuffer)
{
*pbBuffer = 0;
}
hr = HrFromLastWin32Error();
}
TraceHr (ttidError, FAL, hr ,
(HRESULT_FROM_WIN32(ERROR_INVALID_DATA) == hr) ||
(SPAPI_E_NO_SUCH_DEVINST == hr),
"HrSetupDiGetDeviceRegistryProperty");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupDiGetDeviceName
//
// Purpose: Helper function to get the name of the device specified in
// hdi and pdeid. Trys the friendly name first and if not there
// falls back to driver name which must be there.
//
// Arguments:
// hdi [in]
// pdeid [in] See SetupApi for more info
// ppszName [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: danielwe 11 Feb 1998
//
// Notes:
//
HRESULT
HrSetupDiGetDeviceName (
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
OUT PWSTR* ppszName)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
Assert(ppszName);
DWORD dwType;
HRESULT hr = S_OK;
hr = HrSetupDiGetDeviceRegistryPropertyWithAlloc(
hdi, pdeid, SPDRP_FRIENDLYNAME, &dwType, (BYTE**)ppszName);
if (FAILED(hr))
{
// Try again with the device desc which MUST be there.
hr = HrSetupDiGetDeviceRegistryPropertyWithAlloc(
hdi, pdeid, SPDRP_DEVICEDESC, &dwType, (BYTE**)ppszName);
}
AssertSz(FImplies(SUCCEEDED(hr), (dwType == REG_SZ)), "Not a string?!");
TraceError("HrSetupDiGetDeviceName", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrSetupDiSetDeviceName
//
// Purpose: Helper function to set the name of the device specified in
// hdi and pdeid.
//
// Arguments:
// hdi [in]
// pdeid [in] See SetupApi for more info
// ppbBuffer [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: sumitc 23 apr 1998
//
// Notes:
//
HRESULT
HrSetupDiSetDeviceName(
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid,
IN PCWSTR pszDeviceName)
{
Assert(IsValidHandle(hdi));
Assert(pszDeviceName);
HRESULT hr = S_OK;
hr = HrSetupDiSetDeviceRegistryProperty(hdi,
pdeid,
SPDRP_FRIENDLYNAME,
(const BYTE*)pszDeviceName,
sizeof(WCHAR) * (wcslen(pszDeviceName) + 1));
TraceError("HrSetupDiSetDeviceName", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSetDeviceRegistryProperty
//
// Purpose: Sets the specified Plug and Play device registry property.
// See SetupApi for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in]
// dwProperty [in]
// pbBuffer [in]
// cbSize [in]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 June 1997
//
// Notes:
//
HRESULT
HrSetupDiSetDeviceRegistryProperty(IN HDEVINFO hdi,
IN OUT PSP_DEVINFO_DATA pdeid,
IN DWORD dwProperty,
IN const BYTE* pbBuffer,
IN DWORD cbSize)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
Assert(pbBuffer);
HRESULT hr = S_OK;
// Set the property
if (!SetupDiSetDeviceRegistryProperty(hdi, pdeid, dwProperty, pbBuffer,
cbSize))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiSetDeviceRegistryProperty", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiSendPropertyChangeNotification
//
// Purpose: This sends a DIF_PROPERTCHANGE notification to the
// class installer
//
// Arguments:
// hdi [in] See Device Isntaller Api
// pdeid [in]
// dwStateChange [in]
// dwScope [in]
// dwProfileId [in]
//
// Returns: HRESULT. S_OK if no error, a Win32 error converted
// code otherwise
//
// Author: billbe 4 Nov 1997
//
// Notes:
//
HRESULT
HrSetupDiSendPropertyChangeNotification(HDEVINFO hdi, PSP_DEVINFO_DATA pdeid,
DWORD dwStateChange, DWORD dwScope,
DWORD dwProfileId)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
// First we create the property change structure and fill out its fields
//
SP_PROPCHANGE_PARAMS pcp;
ZeroMemory(&pcp, sizeof(pcp));
pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
pcp.StateChange = dwStateChange;
pcp.Scope = dwScope;
pcp.HwProfile = dwProfileId;
// Now we set the structure as the device info data's
// class install params
HRESULT hr = HrSetupDiSetClassInstallParams(hdi, pdeid,
reinterpret_cast<SP_CLASSINSTALL_HEADER*>(&pcp),
sizeof(pcp));
if (SUCCEEDED(hr))
{
// Now we need to set the "we have a class install params" flag
// in the device install params
//
SP_DEVINSTALL_PARAMS deip;
hr = HrSetupDiGetDeviceInstallParams(hdi, pdeid, &deip);
if (SUCCEEDED(hr))
{
deip.Flags |= DI_CLASSINSTALLPARAMS;
hr = HrSetupDiSetDeviceInstallParams(hdi, pdeid, &deip);
if (SUCCEEDED(hr))
{
// Notify the driver that the state has changed
hr = HrSetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hdi,
pdeid);
if (SUCCEEDED(hr))
{
// Set the properties change flag in the device info to
// let anyone who cares know that their ui might need
// updating to reflect any change in the device's status
// We can't let any failures here stop us so we ignore
// return values
//
(void) HrSetupDiGetDeviceInstallParams(hdi, pdeid,
&deip);
deip.Flags |= DI_PROPERTIES_CHANGE;
(void) HrSetupDiSetDeviceInstallParams(hdi, pdeid,
&deip);
}
}
}
}
TraceError("HrSetupDiSendPropertyChangeNotification", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: FSetupDiCheckIfRestartNeeded
//
// Purpose: Checks the hdi and pdeid for the presence of the
// restart flag in the install params structure.
// See Device Installer Api for more info.
//
// Arguments:
// hdi [in] See Device Installer Api
// pdeid [in]
//
// Returns: BOOL. TRUE if a restart is required, FALSE otherwise
//
// Author: billbe 28 Apr 1997
//
// Notes:
//
BOOL
FSetupDiCheckIfRestartNeeded(HDEVINFO hdi, PSP_DEVINFO_DATA pdeid)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
SP_DEVINSTALL_PARAMS deip;
BOOL fRestart = FALSE;
// Get the install params for the device pdeid.
HRESULT hr = HrSetupDiGetDeviceInstallParams(hdi, pdeid, &deip);
if (SUCCEEDED(hr))
{
// Check for the presence of the flag
if ((deip.Flags & DI_NEEDRESTART) || (deip.Flags & DI_NEEDREBOOT))
{
fRestart = TRUE;
}
}
// We don't return any failures from this function since it is just
// a check but we should trace them
TraceError("FSetupDiCheckIfRestartNeeded", hr);
return fRestart;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetClassImageList
//
// Purpose: Builds an image list that contains bitmaps for every
// installed class and returns the list in a data structure
//
// Arguments:
// pcild [out] See Device Installer Api for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 Nov 1997
//
// Notes: The image list will be in the ImageList field of the pcild
// structure
//
HRESULT
HrSetupDiGetClassImageList(PSP_CLASSIMAGELIST_DATA pcild)
{
Assert(pcild);
HRESULT hr = S_OK;
ZeroMemory(pcild, sizeof(*pcild));
pcild->cbSize = sizeof(*pcild);
if (!SetupDiGetClassImageList(pcild))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetClassImageList", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiDestroyClassImageList
//
// Purpose: Destroys a class image list that was built with
// (Hr)SetupDiGetClassImageList
//
// Arguments:
// pcild [in] See Device Installer Api for more info
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 Nov 1997
//
// Notes:
//
HRESULT
HrSetupDiDestroyClassImageList(PSP_CLASSIMAGELIST_DATA pcild)
{
Assert(pcild);
HRESULT hr = S_OK;
if (!SetupDiDestroyClassImageList(pcild))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiDestroyClassImageList", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetClassImageIndex
//
// Purpose: Retrieves the index within the class image list of a
// specified class
//
// Arguments:
// pcild [in] See Device Installer Api for more info
// guidClass [in]
// pnIndex [out]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 26 Nov 1997
//
// Notes:
//
HRESULT
HrSetupDiGetClassImageIndex(PSP_CLASSIMAGELIST_DATA pcild,
const GUID* pguidClass, INT* pnIndex)
{
Assert(pcild);
Assert(pguidClass);
Assert(pnIndex);
HRESULT hr = S_OK;
if (!SetupDiGetClassImageIndex(pcild, pguidClass, pnIndex))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupDiGetClassImageIndex", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupDiGetParentWindow
//
// Purpose: Returns the window handle found in the install params of a
// device info set/data. Set SP_DEVINSTALL_PARAMS in the
// SetupApi for more info.
//
// Arguments:
// hdi [in] See SetupApi for more info
// pdeid [in] See SetupApi for more info
// phwndParent [out] Pointer to the parent window handle
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 12 May 1997
//
// Notes:
//
HRESULT HrSetupDiGetParentWindow (HDEVINFO hdi,
PSP_DEVINFO_DATA pdeid, OPTIONAL
HWND* phwndParent)
{
Assert(IsValidHandle(hdi));
Assert(phwndParent);
// Initialize the output parameter.
*phwndParent = NULL;
// Get the install params of the device
SP_DEVINSTALL_PARAMS deip;
HRESULT hr = HrSetupDiGetDeviceInstallParams(hdi, pdeid, &deip);
if (SUCCEEDED(hr))
{
// Only assign the output if we have a valid window handle
if (IsWindow(deip.hwndParent))
{
*phwndParent = deip.hwndParent;
}
}
TraceError("HrSetupDiGetParentWindow", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupInstallFilesFromInfSection
//
// Purpose: Queues all the files specified in the Copy Files sections
// listed by an Install section for installation.
//
// Arguments:
// hinf [in] See SetupApi for more info
// hinfLayout [in] Optional
// hfq [in]
// pszSection [in]
// pszSourcePath [in] Optional
// ulFlags [in] Optional
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 21 July 1997
//
// Notes:
//
HRESULT
HrSetupInstallFilesFromInfSection (
IN HINF hinf,
IN HINF hinfLayout,
IN HSPFILEQ hfq,
IN PCWSTR pszSection,
IN PCWSTR pszSourcePath,
IN UINT ulFlags)
{
Assert(IsValidHandle(hinf));
Assert(FImplies(hinfLayout, INVALID_HANDLE_VALUE != hinfLayout));
Assert(pszSection);
HRESULT hr = S_OK;
if (!SetupInstallFilesFromInfSection(hinf, hinfLayout, hfq, pszSection,
pszSourcePath, ulFlags))
{
hr = HrFromLastWin32Error();
}
TraceError("HrSetupInstallFilesFromInfSection", hr);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupInstallFromInfSection
//
// Purpose: Carries out all the directives in an INF file Install section.
//
// Arguments:
// hwnd [in] See SetupApi for more info
// hinf [in]
// pszSection [in]
// ulFlags [in]
// hkey [in]
// pszSource [in]
// ulCopyFlags [in]
// pfc [in]
// pvCtx [in]
// hdi [in]
// pdeid [in]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 5 July 1997
//
// Notes:
//
HRESULT
HrSetupInstallFromInfSection (
IN HWND hwnd,
IN HINF hinf,
IN PCWSTR pszSection,
IN UINT ulFlags,
IN HKEY hkey,
IN PCWSTR pszSource,
IN UINT ulCopyFlags,
IN PSP_FILE_CALLBACK pfc,
IN PVOID pvCtx,
IN HDEVINFO hdi,
IN PSP_DEVINFO_DATA pdeid)
{
Assert(IsValidHandle(hinf));
Assert(pszSection);
HRESULT hr = S_OK;
if (!SetupInstallFromInfSection(hwnd, hinf, pszSection, ulFlags, hkey,
pszSource, ulCopyFlags, pfc, pvCtx, hdi, pdeid))
{
hr = HrFromLastWin32Error();
}
TraceHr (ttidError, FAL, hr, FALSE, "HrSetupInstallFromInfSection (%S)",
pszSection);
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: HrSetupInstallServicesFromInfSection
//
// Purpose: Carries out all the service directives in an INF file Install
// section.
//
// Arguments:
// hinf [in] See SetupApi for more info
// pszSection [in]
// dwFlags [in]
//
// Returns: HRESULT. S_OK if successful, error code otherwise
//
// Author: billbe 19 Feb 1998
//
// Notes:
//
HRESULT
HrSetupInstallServicesFromInfSection (
IN HINF hinf,
IN PCWSTR pszSection,
IN DWORD dwFlags)
{
Assert(IsValidHandle(hinf));
Assert(pszSection);
HRESULT hr = S_OK;
if (!SetupInstallServicesFromInfSection(hinf, pszSection, dwFlags))
{
hr = HrFromLastWin32Error();
}
TraceHr (ttidError, FAL, hr, (SPAPI_E_SECTION_NOT_FOUND == hr),
"HrSetupInstallServicesFromInfSection (%S)", pszSection);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOpenSoftwareDeviceEnumerator
//
// Purpose: Opens the swenum device driver used to install software-
// enumerated device drivers.
//
// Arguments:
// dwFlagsAndAttributes [in] See CreateFile.
// phFile [out] The returned handle to the swenum device.
//
// Returns: S_OK or an error code.
//
// Author: shaunco 30 Mar 1998
//
// Notes:
//
HRESULT
HrOpenSoftwareDeviceEnumerator (
DWORD dwFlagsAndAttributes,
HANDLE* phFile)
{
Assert (phFile);
// Initialize the output parameter.
//
*phFile = INVALID_HANDLE_VALUE;
// Get the devices in software device enumerator class. There should
// only be one. (Or rather, we're only interested in the first one.)
//
HDEVINFO hdi;
HRESULT hr = HrSetupDiGetClassDevs (&BUSID_SoftwareDeviceEnumerator,
NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE,
&hdi);
if (S_OK == hr)
{
// Enumerate the first device in this class. This will
// initialize did.
//
SP_DEVICE_INTERFACE_DATA did;
ZeroMemory (&did, sizeof(did));
did.cbSize = sizeof(did);
if (SetupDiEnumDeviceInterfaces (hdi, NULL,
const_cast<LPGUID>(&BUSID_SoftwareDeviceEnumerator),
0, &did))
{
// Now get the details so we can open the device.
//
const ULONG cbDetail = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) +
(MAX_PATH * sizeof(WCHAR));
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
hr = HrMalloc (cbDetail, (PVOID*)&pDetail);
if (S_OK == hr)
{
pDetail->cbSize = sizeof(*pDetail);
if (SetupDiGetDeviceInterfaceDetail (hdi, &did,
pDetail, cbDetail, NULL, NULL))
{
// Now open the device (swenum).
//
HANDLE hFile = CreateFile (pDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
dwFlagsAndAttributes, NULL);
if (hFile && (INVALID_HANDLE_VALUE != hFile))
{
*phFile = hFile;
}
else
{
hr = HrFromLastWin32Error ();
}
}
else
{
hr = HrFromLastWin32Error ();
}
MemFree (pDetail);
}
}
else
{
hr = HrFromLastWin32Error ();
}
SetupDiDestroyDeviceInfoList (hdi);
}
TraceHr (ttidError, FAL, hr, FALSE, "HrOpenSoftwareDeviceEnumerator");
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrFindDeviceOnInterface
//
// Purpose: Searches for a specific device on a given interface.
// It does this by using setup api to return all of the
// devices in the class given by pguidInterfaceId. It then
// gets device path for each of these device interfaces and
// looks for pguidDeviceId and pszReferenceString as substrings.
//
// Arguments:
// pguidDeviceId [in] The device id to find.
// pguidInterfaceId [in] The interface on which to look.
// pszReferenceString [in] Optional. Further match on this ref string.
// dwFlagsAndAttributes [in] See CreateFile. This is how the device is
// opened if it is found.
// phFile [out] The returned device handle.
//
// Returns: S_OK if found and opened, S_FALSE if not found, or an error.
//
// Author: shaunco 30 Mar 1998
//
// Notes:
//
HRESULT
HrFindDeviceOnInterface (
IN const GUID* pguidDeviceId,
IN const GUID* pguidInterfaceId,
IN PCWSTR pszReferenceString,
IN DWORD dwFlagsAndAttributes,
OUT HANDLE* phFile)
{
Assert (pguidDeviceId);
Assert (pguidInterfaceId);
Assert (phFile);
// Initialize the output parameter.
//
*phFile = INVALID_HANDLE_VALUE;
WCHAR szDeviceId [c_cchGuidWithTerm];
INT cch = StringFromGUID2 (*pguidDeviceId, szDeviceId,
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
CharLower (szDeviceId);
// Get the devices in this class.
//
HDEVINFO hdi;
HRESULT hr = HrSetupDiGetClassDevs (pguidInterfaceId, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE, &hdi);
if (S_OK == hr)
{
BOOL fFound = FALSE;
// abBuffer is a buffer used to get device interface detail for each
// device interface enumerated below.
//
const ULONG cbDetail = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) +
(MAX_PATH * sizeof(WCHAR));
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
hr = HrMalloc (cbDetail, (PVOID*)&pDetail);
if (S_OK == hr)
{
// Enumerate the device interfaces looking for the one specified.
//
SP_DEVICE_INTERFACE_DATA did;
ZeroMemory (&did, sizeof(did));
for (DWORD i = 0;
did.cbSize = sizeof(did),
SetupDiEnumDeviceInterfaces (hdi, NULL,
const_cast<LPGUID>(pguidInterfaceId), i, &did);
i++)
{
// Now get the details so we can compare the device path.
//
pDetail->cbSize = sizeof(*pDetail);
if (SetupDiGetDeviceInterfaceDetailW (hdi, &did,
pDetail, cbDetail, NULL, NULL))
{
CharLower (pDetail->DevicePath);
// Look for a substring containing szDeviceId. Also
// look for a substring containing pszReferenceString if
// it is specified.
//
if (wcsstr (pDetail->DevicePath, szDeviceId) &&
(!pszReferenceString || !*pszReferenceString ||
wcsstr (pDetail->DevicePath, pszReferenceString)))
{
// We found it, so open the device and return it.
//
HANDLE hFile = CreateFile (pDetail->DevicePath,
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
dwFlagsAndAttributes, NULL);
if (hFile && (INVALID_HANDLE_VALUE != hFile))
{
TraceTag (ttidNetcfgBase, "Found device id '%S'",
szDeviceId);
TraceTag (ttidNetcfgBase, "Opening device '%S'",
pDetail->DevicePath);
*phFile = hFile;
fFound = TRUE;
}
else
{
hr = HrFromLastWin32Error ();
}
// Now that we've found it, break out of the loop.
//
break;
}
}
else
{
hr = HrFromLastWin32Error ();
}
}
MemFree (pDetail);
}
SetupDiDestroyDeviceInfoList (hdi);
if (SUCCEEDED(hr) && !fFound)
{
hr = S_FALSE;
}
}
TraceHr(ttidError, FAL, hr, S_FALSE == hr,
"HrFindDeviceOnInterface (device=%S)", szDeviceId);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrInstallSoftwareDeviceOnInterface
//
// Purpose: Install a software-enumerated device on the given interface.
//
// Arguments:
// pguidDeviceId [in] The device id to install.
// pguidInterfaceId [in] The interface to install it on.
// pszReferenceString [in] The reference string.
// fForceInstall [in] Usually specify FALSE. Specify TRUE to
// force installation of the device using
// pguidClass and pszHardwareId.
// Typically this is used during GUI mode setup
// where swenum won't be able to fully install
// the device.
//
// Returns: S_OK or an error code.
//
// Author: shaunco 30 Mar 1998
//
// Notes:
//
HRESULT
HrInstallSoftwareDeviceOnInterface (
const GUID* pguidDeviceId,
const GUID* pguidInterfaceId,
PCWSTR pszReferenceString,
BOOL fForceInstall,
PCWSTR pszInfFilename,
HWND hwndParent)
{
Assert (pguidDeviceId);
Assert (pguidInterfaceId);
Assert (pszReferenceString && *pszReferenceString);
// Open the software device enumerator.
//
HANDLE hSwenum;
HRESULT hr = HrOpenSoftwareDeviceEnumerator (
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
&hSwenum);
if (S_OK == hr)
{
Assert (INVALID_HANDLE_VALUE != hSwenum);
// Allocate and build the buffer used as the IOCTL parameter.
//
const ULONG cbBuf = (ULONG)FIELD_OFFSET (SWENUM_INSTALL_INTERFACE, ReferenceString) +
CbOfSzAndTerm (pszReferenceString);
SWENUM_INSTALL_INTERFACE* pBuf;
hr = HrMalloc (cbBuf, (PVOID*)&pBuf);
if (S_OK == hr)
{
ZeroMemory (pBuf, cbBuf);
pBuf->DeviceId = *pguidDeviceId;
pBuf->InterfaceId = *pguidInterfaceId;
lstrcpyW (pBuf->ReferenceString, pszReferenceString);
// Create an event to be used for the overlapped IO we are about
// to issue.
//
OVERLAPPED ovl;
ZeroMemory (&ovl, sizeof(ovl));
ovl.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (ovl.hEvent)
{
#ifdef ENABLETRACE
WCHAR szDeviceId [c_cchGuidWithTerm];
INT cch = StringFromGUID2 (pBuf->DeviceId, szDeviceId,
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
WCHAR szInterfaceId [c_cchGuidWithTerm];
cch = StringFromGUID2 (pBuf->InterfaceId, szInterfaceId,
c_cchGuidWithTerm);
Assert (c_cchGuidWithTerm == cch);
TraceTag (ttidNetcfgBase, "Installing software enumerated "
"device '%S' on interface '%S'",
szDeviceId, szInterfaceId);
#endif
// Issue the install interface IOCTL.
//
DWORD cbReturned;
BOOL fIoResult = DeviceIoControl (hSwenum,
IOCTL_SWENUM_INSTALL_INTERFACE,
pBuf, cbBuf, NULL, 0,
&cbReturned, &ovl);
if (!fIoResult)
{
hr = HrFromLastWin32Error ();
if (HRESULT_FROM_WIN32 (ERROR_IO_PENDING) == hr)
{
// Wait for the IO to complete if it was returned as
// pending.
//
fIoResult = GetOverlappedResult (hSwenum, &ovl,
&cbReturned, TRUE);
if (!fIoResult)
{
hr = HrFromLastWin32Error ();
}
}
}
CloseHandle (ovl.hEvent);
}
MemFree (pBuf);
}
CloseHandle (hSwenum);
}
// Force the device to be installed by enumerating it.
//
if ((S_OK == hr) && fForceInstall)
{
HANDLE hDevice;
hr = HrFindDeviceOnInterface (
pguidDeviceId,
pguidInterfaceId,
pszReferenceString,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
&hDevice);
if (S_OK == hr)
{
CloseHandle (hDevice);
}
else if (S_FALSE == hr)
{
// We just installed this device, why wasn't it found?
//
hr = E_UNEXPECTED;
}
}
TraceHr (ttidError, FAL, hr, FALSE, "HrInstallSoftwareDeviceOnInterface");
return hr;
}
// ----------------------------------------------------------------------
//
// Function: HrInstallFromInfSectionInFile
//
// Purpose: Open the given INF file and call Setup API to install
// from the specified section.
//
// Arguments:
// hwndParent [in] handle of parent window
// szInfName [in] name of INF
// szSection [in] section name
// hkeyRelative [in] handle of reg-key to use
// fQuietInstall [in] TRUE if we shouldn't show UI and use
// default values, FALSE if we can bother
// the user with questions and UI
//
// Returns: S_OK on success, otherwise an error code
//
// Author: kumarp 23-December-97
//
// Notes:
//
HRESULT HrInstallFromInfSectionInFile (
IN HWND hwndParent,
IN PCWSTR pszInfName,
IN PCWSTR pszSection,
IN HKEY hkeyRelative,
IN BOOL fQuietInstall)
{
AssertValidReadPtr(pszInfName);
AssertValidReadPtr(pszSection);
HRESULT hr;
HINF hinf;
hr = HrSetupOpenInfFile(pszInfName, NULL,
INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL, &hinf);
if (S_OK == hr)
{
hr = HrSetupInstallFromInfSection (hwndParent, hinf, pszSection,
SPINST_REGISTRY, hkeyRelative, NULL, 0, NULL, NULL,
NULL, NULL);
}
TraceError("HrInstallInfSectionInfFile", hr);
return hr;
}
#if defined(REMOTE_BOOT)
//+--------------------------------------------------------------------------
//
// Function: HrIsRemoteBootAdapter
//
// Purpose: This determines whether the adapter is a remote boot adapter
//
// Arguments:
// hdi [in] See Device Installer Api for more info
// pdeid [in] See Device Installer Api for more info
//
// Returns: HRESULT. S_OK if adapter is a remote boot adapter
// S_FALSE if adapter is not a remote boot adapter
// a Win32 converted error otherwise
//
//
// Author: billbe 31 Jan 1998
//
// Notes:
//
HRESULT
HrIsRemoteBootAdapter(HDEVINFO hdi, PSP_DEVINFO_DATA pdeid)
{
Assert(IsValidHandle(hdi));
Assert(pdeid);
DWORD dwConfigFlags;
// Get the current config flags
HRESULT hr = HrSetupDiGetDeviceRegistryProperty(hdi, pdeid,
SPDRP_CONFIGFLAGS, NULL, (BYTE*)&dwConfigFlags,
sizeof(dwConfigFlags), NULL);
if (SUCCEEDED(hr))
{
if (dwConfigFlags & CONFIGFLAG_NETBOOT_CARD)
{
hr = S_OK;
}
else
{
hr = S_FALSE;
}
}
else if (HRESULT_FROM_WIN32(ERROR_INVALID_DATA) == hr)
{
// The device had no config flags, so it isn't a remote boot adapter
hr = S_FALSE;
}
TraceError("HrIsRemoteBootAdapter", (hr == S_FALSE) ? S_OK : hr);
return hr;
}
#endif // defined(REMOTE_BOOT)
VOID
SetupDiDestroyDeviceInfoListSafe(HDEVINFO hdi)
{
if (IsValidHandle(hdi))
{
SetupDiDestroyDeviceInfoList(hdi);
}
}
VOID
SetupCloseInfFileSafe(HINF hinf)
{
if (IsValidHandle(hinf))
{
SetupCloseInfFile(hinf);
}
}