668 lines
16 KiB
C++
668 lines
16 KiB
C++
//=======================================================================
|
|
//
|
|
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// File: cdm.cpp
|
|
//
|
|
// Description:
|
|
//
|
|
// Functions exported by CDM
|
|
//
|
|
// CloseCDMContext
|
|
// DetFilesDownloaded
|
|
// DownloadGetUpdatedFiles
|
|
// DownloadIsInternetAvailable
|
|
// DownloadUpdatedFiles
|
|
// FindMatchingDriver
|
|
// LogDriverNotFound
|
|
// OpenCDMContext
|
|
// OpenCDMContextEx
|
|
// QueryDetectionFiles
|
|
//
|
|
//=======================================================================
|
|
#include <objbase.h>
|
|
#include <winbase.h>
|
|
#include <tchar.h>
|
|
#include <logging.h>
|
|
#include <iucommon.h>
|
|
#include <loadengine.h>
|
|
#include <osdet.h>
|
|
#include <iu.h>
|
|
#include <wininet.h>
|
|
#include <wusafefn.h>
|
|
|
|
static BOOL g_fCloseConnection /* FALSE */;
|
|
|
|
static HMODULE g_hEngineModule /* = NULL */;
|
|
static PFN_InternalDetFilesDownloaded g_pfnDetFilesDownloaded /* = NULL */;
|
|
static PFN_InternalDownloadGetUpdatedFiles g_pfnDownloadGetUpdatedFiles /* = NULL */;
|
|
static PFN_InternalDownloadUpdatedFiles g_pfnDownloadUpdatedFiles /* = NULL */;
|
|
static PFN_InternalFindMatchingDriver g_pfnFindMatchingDriver /* = NULL */;
|
|
static PFN_InternalLogDriverNotFound g_pfnLogDriverNotFound /* = NULL */;
|
|
static PFN_InternalQueryDetectionFiles g_pfnQueryDetectionFiles /* = NULL */;
|
|
static PFN_InternalSetGlobalOfflineFlag g_pfnSetGlobalOfflineFlag /* = NULL */;
|
|
static PFN_SetOperationMode g_pfnSetOperationMode /* = NULL */;
|
|
|
|
static HMODULE g_hCtlModule /* = NULL */;
|
|
static long g_lLoadEngineRefCount /* = 0 */;
|
|
static PFN_LoadIUEngine g_pfnCtlLoadIUEngine /* = NULL */;
|
|
static PFN_UnLoadIUEngine g_pfnCtlUnLoadIUEngine /* = NULL */;
|
|
|
|
|
|
static CRITICAL_SECTION g_cs;
|
|
BOOL g_fInitCS;
|
|
|
|
const TCHAR szOpenCDMContextFirst[] = _T("Must OpenCDMContext first!");
|
|
//
|
|
// constant for SetOperationMode() API (BUILD util won't allow building iuctl.idl from cdm dir)
|
|
//
|
|
const LONG UPDATE_COMMAND_CANCEL = 0x00000004;
|
|
|
|
|
|
BOOL APIENTRY DllMain(
|
|
HINSTANCE hInstance,
|
|
DWORD ul_reason_for_call,
|
|
LPVOID /*lpReserved*/
|
|
)
|
|
{
|
|
switch (ul_reason_for_call)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls(hInstance);
|
|
|
|
g_fInitCS = SafeInitializeCriticalSection(&g_cs);
|
|
//
|
|
// Initialize free logging
|
|
//
|
|
InitFreeLogging(_T("CDM"));
|
|
LogMessage("Starting");
|
|
|
|
if (!g_fInitCS)
|
|
{
|
|
LogError(E_FAIL, "InitializeCriticalSection");
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
//
|
|
// Shutdown free logging
|
|
//
|
|
LogMessage("Shutting down");
|
|
TermFreeLogging();
|
|
|
|
if (g_fInitCS)
|
|
{
|
|
DeleteCriticalSection(&g_cs);
|
|
}
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void UnLoadCtlAndEngine(void)
|
|
{
|
|
LOG_Block("UnLoadCtlAndEngine");
|
|
|
|
EnterCriticalSection(&g_cs);
|
|
|
|
if (0 != g_lLoadEngineRefCount)
|
|
{
|
|
g_lLoadEngineRefCount--;
|
|
}
|
|
|
|
if (0 == g_lLoadEngineRefCount)
|
|
{
|
|
if(NULL != g_hEngineModule)
|
|
{
|
|
//
|
|
// Call UnLoadIUEngine
|
|
//
|
|
g_pfnCtlUnLoadIUEngine(g_hEngineModule);
|
|
g_hEngineModule = NULL;
|
|
|
|
g_pfnDetFilesDownloaded = NULL;
|
|
g_pfnDownloadGetUpdatedFiles = NULL;
|
|
g_pfnDownloadUpdatedFiles = NULL;
|
|
g_pfnFindMatchingDriver = NULL;
|
|
g_pfnLogDriverNotFound = NULL;
|
|
g_pfnQueryDetectionFiles = NULL;
|
|
g_pfnSetGlobalOfflineFlag = NULL;
|
|
g_pfnSetOperationMode = NULL;
|
|
}
|
|
|
|
if (NULL != g_hCtlModule)
|
|
{
|
|
//
|
|
// Unload the iuctl.dll
|
|
//
|
|
FreeLibrary(g_hCtlModule);
|
|
g_hCtlModule = NULL;
|
|
g_pfnCtlLoadIUEngine = NULL;
|
|
g_pfnCtlUnLoadIUEngine = NULL;
|
|
}
|
|
|
|
if (g_fCloseConnection)
|
|
{
|
|
//
|
|
// We dialed for the user - now disconnect
|
|
//
|
|
if (!InternetAutodialHangup(0))
|
|
{
|
|
LOG_ErrorMsg(E_FAIL);
|
|
SetLastError(E_FAIL);
|
|
}
|
|
|
|
g_fCloseConnection = FALSE;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_cs);
|
|
}
|
|
|
|
BOOL LoadCtlAndEngine(BOOL fConnectIfNotConnected)
|
|
{
|
|
LOG_Block("LoadCtlAndEngine");
|
|
|
|
BOOL fRet = FALSE;
|
|
HRESULT hr;
|
|
DWORD dwFlags;
|
|
BOOL fConnected = InternetGetConnectedState(&dwFlags, 0);
|
|
LOG_Driver(_T("fConnectIfNotConnected param is %s"), fConnectIfNotConnected ? _T("TRUE") : _T("FALSE"));
|
|
LOG_Driver(_T("fConnected = %s, dwFlags from InternetGetConnectedState = 0x%08x"), fConnected ? _T("TRUE") : _T("FALSE"), dwFlags);
|
|
|
|
EnterCriticalSection(&g_cs); // start touching globals
|
|
|
|
if (fConnectIfNotConnected)
|
|
{
|
|
if (!fConnected)
|
|
{
|
|
if ((INTERNET_CONNECTION_MODEM & dwFlags) && !(INTERNET_CONNECTION_OFFLINE & dwFlags))
|
|
{
|
|
//
|
|
// If we are not already connected to the internet and
|
|
// the system is configured to use a modem attempt a connection.
|
|
//
|
|
DWORD dwErr;
|
|
if (ERROR_SUCCESS == (dwErr = InternetAttemptConnect(0)))
|
|
{
|
|
LOG_Driver(_T("auto-dial succeeded"));
|
|
//
|
|
// The auto-dial worked, we need to disconnect later
|
|
//
|
|
g_fCloseConnection = TRUE;
|
|
fConnected = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Bail with error since we are required to be online
|
|
//
|
|
LOG_Driver(_T("auto-dial failed"));
|
|
LOG_ErrorMsg(dwErr);
|
|
SetLastError(dwErr);
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We can't connect because we aren't configured for a modem or user set IE offline mode
|
|
//
|
|
LOG_ErrorMsg(ERROR_GEN_FAILURE);
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto CleanUp;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now that we are connected (only required if TRUE == fConnectIfNotConnected)
|
|
//
|
|
if (NULL != g_hEngineModule)
|
|
{
|
|
LOG_Driver(_T("IUEngine is already loaded"));
|
|
//
|
|
// Bump the ref count and return TRUE
|
|
//
|
|
g_lLoadEngineRefCount++;
|
|
fRet = TRUE;
|
|
goto CleanUp;
|
|
}
|
|
//
|
|
// This extra lock on wininet.dll is required to prevent a TerminateThread call from
|
|
// WININET!AUTO_PROXY_DLLS::FreeAutoProxyInfo during FreeLibrary of CDM.DLL.
|
|
//
|
|
// We don't ever free the returned handle, but will fail the call if it returns NULL
|
|
//
|
|
if (NULL == LoadLibraryFromSystemDir(_T("wininet.dll")))
|
|
{
|
|
LOG_ErrorMsg(GetLastError());
|
|
goto CleanUp;
|
|
}
|
|
|
|
//
|
|
// Load iuctl.dll and get the [Un]LoadIUEngine function pointers
|
|
//
|
|
if (NULL == (g_hCtlModule = LoadLibraryFromSystemDir(_T("iuctl.dll"))))
|
|
{
|
|
LOG_ErrorMsg(GetLastError());
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (NULL == (g_pfnCtlLoadIUEngine = (PFN_LoadIUEngine) GetProcAddress(g_hCtlModule, "LoadIUEngine")))
|
|
{
|
|
LOG_ErrorMsg(GetLastError());
|
|
goto CleanUp;
|
|
}
|
|
|
|
if (NULL == (g_pfnCtlUnLoadIUEngine = (PFN_UnLoadIUEngine) GetProcAddress(g_hCtlModule, "UnLoadIUEngine")))
|
|
{
|
|
LOG_ErrorMsg(GetLastError());
|
|
goto CleanUp;
|
|
}
|
|
//
|
|
// Now we can call LoadIUEngine()
|
|
//
|
|
if (NULL == (g_hEngineModule = g_pfnCtlLoadIUEngine(TRUE, !fConnected)))
|
|
{
|
|
LOG_ErrorMsg(GetLastError());
|
|
goto CleanUp;
|
|
}
|
|
|
|
g_pfnDetFilesDownloaded = (PFN_InternalDetFilesDownloaded) GetProcAddress(g_hEngineModule, "InternalDetFilesDownloaded");
|
|
g_pfnDownloadGetUpdatedFiles = (PFN_InternalDownloadGetUpdatedFiles) GetProcAddress(g_hEngineModule, "InternalDownloadGetUpdatedFiles");
|
|
g_pfnDownloadUpdatedFiles = (PFN_InternalDownloadUpdatedFiles) GetProcAddress(g_hEngineModule, "InternalDownloadUpdatedFiles");
|
|
g_pfnFindMatchingDriver = (PFN_InternalFindMatchingDriver) GetProcAddress(g_hEngineModule, "InternalFindMatchingDriver");
|
|
g_pfnLogDriverNotFound = (PFN_InternalLogDriverNotFound) GetProcAddress(g_hEngineModule, "InternalLogDriverNotFound");
|
|
g_pfnQueryDetectionFiles = (PFN_InternalQueryDetectionFiles) GetProcAddress(g_hEngineModule, "InternalQueryDetectionFiles");
|
|
g_pfnSetGlobalOfflineFlag = (PFN_InternalSetGlobalOfflineFlag) GetProcAddress(g_hEngineModule, "InternalSetGlobalOfflineFlag");
|
|
g_pfnSetOperationMode = (PFN_SetOperationMode) GetProcAddress(g_hEngineModule, "EngSetOperationMode");
|
|
|
|
if (NULL == g_pfnDetFilesDownloaded ||
|
|
NULL == g_pfnDownloadGetUpdatedFiles ||
|
|
NULL == g_pfnDownloadUpdatedFiles ||
|
|
NULL == g_pfnFindMatchingDriver ||
|
|
NULL == g_pfnLogDriverNotFound ||
|
|
NULL == g_pfnQueryDetectionFiles ||
|
|
NULL == g_pfnSetGlobalOfflineFlag ||
|
|
NULL == g_pfnSetOperationMode )
|
|
{
|
|
LOG_Driver(_T("GetProcAddress on IUEngine failed"));
|
|
LOG_ErrorMsg(ERROR_CALL_NOT_IMPLEMENTED);
|
|
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
|
|
}
|
|
else
|
|
{
|
|
fRet = TRUE;
|
|
g_lLoadEngineRefCount++;
|
|
// Set Global Offline Flag - checked by XML Classes to disable Validation (schemas are on the net)
|
|
g_pfnSetGlobalOfflineFlag(!fConnected);
|
|
}
|
|
// goto CleanUp;
|
|
|
|
CleanUp:
|
|
|
|
if (FALSE == fRet)
|
|
{
|
|
UnLoadCtlAndEngine();
|
|
}
|
|
|
|
LeaveCriticalSection(&g_cs);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//This API closes the internet connection opened with the OpenCDMContext() API.
|
|
//If CDM did not open the internet connection this API simply returns. The CDM
|
|
//context handle must have been the same handle that was returned from
|
|
//the OpenCDMContext() API.
|
|
//
|
|
//This call cannot fail. If the pConnection handle is invalid this function
|
|
//simply ignores it.
|
|
|
|
VOID WINAPI CloseCDMContext (
|
|
IN HANDLE /* hConnection */ // Obsolete handle returned by OpenCDMContext.
|
|
)
|
|
{
|
|
LOG_Block("CloseCDMContext");
|
|
|
|
//
|
|
// This is the only spot we unload engine (but note exceptions in
|
|
// DownloadGetUpdatedFiles).
|
|
//
|
|
// Doesn't use COM
|
|
//
|
|
UnLoadCtlAndEngine();
|
|
}
|
|
|
|
|
|
void WINAPI DetFilesDownloaded(
|
|
IN HANDLE hConnection
|
|
)
|
|
{
|
|
LOG_Block("DetFilesDownloaded");
|
|
|
|
HRESULT hr;
|
|
if (g_pfnDetFilesDownloaded)
|
|
{
|
|
if (SUCCEEDED(hr = CoInitialize(0)))
|
|
{
|
|
g_pfnDetFilesDownloaded(hConnection);
|
|
|
|
CoUninitialize();
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_Error(szOpenCDMContextFirst);
|
|
}
|
|
}
|
|
|
|
//Win 98 entry point
|
|
//This function allows Windows 98 to call the same entry points as NT.
|
|
//The function returns TRUE if the download succeeds and FALSE if it
|
|
//does not.
|
|
|
|
BOOL DownloadGetUpdatedFiles(
|
|
IN PDOWNLOADINFOWIN98 pDownloadInfoWin98, //The win98 download info structure is
|
|
//slightly different that the NT version
|
|
//so this function handles conversion.
|
|
IN OUT LPTSTR lpDownloadPath, //returned Download path to the downloaded
|
|
//cab files.
|
|
IN UINT uSize //size of passed in download path buffer.
|
|
)
|
|
{
|
|
|
|
LOG_Block("DownloadGetUpdatedFiles");
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Special case - we need to load and unloadengine since historically we haven't required an
|
|
// OpenCDMContext[Ex] call before calling this function and CloseCDMContext after.
|
|
//
|
|
HRESULT hr;
|
|
BOOL fRet;
|
|
if (LoadCtlAndEngine(TRUE))
|
|
{
|
|
if (SUCCEEDED(hr = CoInitialize(0)))
|
|
{
|
|
fRet = g_pfnDownloadGetUpdatedFiles(pDownloadInfoWin98, lpDownloadPath, uSize);
|
|
|
|
CoUninitialize();
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
fRet = FALSE;
|
|
}
|
|
|
|
UnLoadCtlAndEngine();
|
|
return fRet;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//This function determines if this client can connect to the internet.
|
|
|
|
BOOL DownloadIsInternetAvailable(void)
|
|
{
|
|
LOG_Block("DownloadIsInternetAvailable");
|
|
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// We don't care about the current online state, just if we have a
|
|
// connection configured (returned in dwFlags).
|
|
//
|
|
DWORD dwFlags;
|
|
(void) InternetGetConnectedState(&dwFlags, 0);
|
|
|
|
if ( ( (INTERNET_CONNECTION_CONFIGURED & dwFlags) ||
|
|
(INTERNET_CONNECTION_LAN & dwFlags) ||
|
|
(INTERNET_CONNECTION_MODEM & dwFlags) ||
|
|
(INTERNET_RAS_INSTALLED & dwFlags) ||
|
|
(INTERNET_CONNECTION_PROXY & dwFlags) )
|
|
|
|
&& !(INTERNET_CONNECTION_OFFLINE & dwFlags)
|
|
)
|
|
{
|
|
LOG_Driver(_T("Returning TRUE: InternetGetConnectedState returned 0x%08x in dwFlags"), dwFlags);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
LOG_Driver(_T("Returning FALSE: InternetGetConnectedState returned 0x%08x in dwFlags"), dwFlags);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//This function downloads the specified CDM package. The hConnection handle must have
|
|
//been returned from the OpenCDMContext() API.
|
|
//
|
|
//This function Returns TRUE if download is successful GetLastError() will return
|
|
//the error code indicating the reason that the call failed.
|
|
|
|
BOOL WINAPI DownloadUpdatedFiles(
|
|
IN HANDLE hConnection, //Connection handle from OpenCDMContext() API.
|
|
IN HWND hwnd, //Window handle for call context
|
|
IN PDOWNLOADINFO pDownloadInfo, //download information structure describing
|
|
//package to be read from server
|
|
OUT LPWSTR lpDownloadPath, //local computer directory location of the
|
|
//downloaded files
|
|
IN UINT uSize, //size of the download path buffer. If this
|
|
//buffer is to small to contain the complete
|
|
//path and file name no file will be downloaded.
|
|
//The PUINT puReguiredSize parameter can be checked
|
|
//to determine the size of buffer necessary to
|
|
//perform the download.
|
|
OUT PUINT puRequiredSize //required lpDownloadPath buffer size. This
|
|
//parameter is filled in with the minimum size
|
|
//that is required to place the complete path
|
|
//file name of the downloaded file. If this
|
|
//parameter is NULL no size is returned.
|
|
)
|
|
{
|
|
LOG_Block("DownloadUpdatedFiles");
|
|
|
|
HRESULT hr;
|
|
BOOL fRet;
|
|
if (g_pfnDownloadUpdatedFiles)
|
|
{
|
|
if (SUCCEEDED(hr = CoInitialize(0)))
|
|
{
|
|
fRet = g_pfnDownloadUpdatedFiles(hConnection, hwnd, pDownloadInfo, lpDownloadPath, uSize, puRequiredSize);
|
|
|
|
CoUninitialize();
|
|
return fRet;
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_Error(szOpenCDMContextFirst);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL WINAPI FindMatchingDriver(
|
|
IN HANDLE hConnection,
|
|
IN PDOWNLOADINFO pDownloadInfo,
|
|
OUT PWUDRIVERINFO pWuDriverInfo
|
|
)
|
|
{
|
|
LOG_Block("FindMatchingDriver");
|
|
|
|
HRESULT hr;
|
|
BOOL fRet;
|
|
if (g_pfnFindMatchingDriver)
|
|
{
|
|
if (SUCCEEDED(hr = CoInitialize(0)))
|
|
{
|
|
fRet = g_pfnFindMatchingDriver(hConnection, pDownloadInfo, pWuDriverInfo);
|
|
|
|
CoUninitialize();
|
|
return fRet;
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_Error(szOpenCDMContextFirst);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// supports offline logging
|
|
// hConnection NOT used at all
|
|
// no network connection or osdet.dll needed for languauge, SKU, platform detection
|
|
void WINAPI LogDriverNotFound(
|
|
IN HANDLE hConnection,
|
|
IN LPCWSTR lpDeviceInstanceID,
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
LOG_Block("LogDriverNotFound");
|
|
|
|
HRESULT hr;
|
|
if (g_pfnLogDriverNotFound)
|
|
{
|
|
if (SUCCEEDED(hr = CoInitialize(0)))
|
|
{
|
|
g_pfnLogDriverNotFound(hConnection, lpDeviceInstanceID, dwFlags);
|
|
|
|
CoUninitialize();
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_Error(szOpenCDMContextFirst);
|
|
}
|
|
}
|
|
|
|
|
|
HANDLE WINAPI OpenCDMContext(
|
|
IN HWND /* hwnd */ //Window handle to use for any UI that needs to be presented (not used)
|
|
)
|
|
{
|
|
LOG_Block("OpenCDMContext");
|
|
|
|
return OpenCDMContextEx(TRUE);
|
|
}
|
|
|
|
HANDLE WINAPI OpenCDMContextEx(
|
|
IN BOOL fConnectIfNotConnected
|
|
)
|
|
{
|
|
LOG_Block("OpenCDMContextEx");
|
|
|
|
//
|
|
// Don't open a context if we are disabled (0 and -1 OK)
|
|
// Other functions will fail because their g_pfnXxxxx == NULL.
|
|
//
|
|
if (1 == IsWindowsUpdateUserAccessDisabled())
|
|
{
|
|
LOG_ErrorMsg(ERROR_SERVICE_DISABLED);
|
|
SetLastError(ERROR_SERVICE_DISABLED);
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Doesn't use COM
|
|
//
|
|
if (LoadCtlAndEngine(fConnectIfNotConnected))
|
|
{
|
|
//
|
|
// This is an obsolete function that just loads the engine (which may do autodial to connect).
|
|
// We just return non-NULL g_lLoadEngineRefCount to keep existing clients happy, but never use it.
|
|
//
|
|
|
|
|
|
return LongToHandle(g_lLoadEngineRefCount);
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int WINAPI QueryDetectionFiles(
|
|
IN HANDLE hConnection,
|
|
IN void* pCallbackParam,
|
|
IN PFN_QueryDetectionFilesCallback pCallback
|
|
)
|
|
{
|
|
LOG_Block("QueryDetectionFiles");
|
|
|
|
HRESULT hr;
|
|
int nRet;
|
|
if (g_pfnQueryDetectionFiles)
|
|
{
|
|
if (SUCCEEDED(hr = CoInitialize(0)))
|
|
{
|
|
nRet = g_pfnQueryDetectionFiles(hConnection, pCallbackParam, pCallback);
|
|
|
|
CoUninitialize();
|
|
return nRet;
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(hr);
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_Error(szOpenCDMContextFirst);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 502965 Windows Error Reporting bucket 2096553: Hang following NEWDEV.DLL!CancelDriverSearch
|
|
//
|
|
// Provide API to allow clients to cancel synchronous calls into CDM by calling this function
|
|
// asynchronously from a second thread.
|
|
//
|
|
HRESULT WINAPI CancelCDMOperation(void)
|
|
{
|
|
LOG_Block("CancelCDMOperation");
|
|
|
|
if (g_pfnSetOperationMode)
|
|
{
|
|
return g_pfnSetOperationMode(NULL, NULL, UPDATE_COMMAND_CANCEL);
|
|
}
|
|
else
|
|
{
|
|
LOG_ErrorMsg(E_ACCESSDENIED);
|
|
return E_ACCESSDENIED;
|
|
}
|
|
}
|