www.pudn.com > Microsoft Windows驱动程序模型设计 源代码.zip > TEST.CPP


// Test.cpp - WMI test program 
// Copyright (C) 1999 by Walter Oney 
// All rights reserved 
 
#include "stdafx.h" 
#include  
#include "..\sys\guids.h" 
#include  
#include "..\sys\ioctls.h" 
 
#define arraysize(p) (sizeof(p)/sizeof((p)[0])) 
 
void ReportError(LPCTSTR fcn, DWORD code); 
void ReportInfo(IWbemServices* services, LPCWSTR classname); 
void ReceiveEvent(IWbemServices* services, LPCWSTR classname); 
void CallMethod(IWbemServices* services, LPCWSTR classname, LPCWSTR methname); 
 
/////////////////////////////////////////////////////////////////////////////// 
 
int main(int argc, LPTSTR argv[]) 
	{							// main 
	// Initialize COM and get a pointer to the WbemLocator interface. We must use 
	// the DCOM flavor of services on a computer where DCOM is installed. WBEMTEST 
	// loads ole32.dll and uses GetProcAddress to learn these addresses. This test 
	// program simply assumes that it's running in a DCOM-enabled environment. 
 
	HRESULT hr = CoInitializeEx(NULL, 0); 
	if (!SUCCEEDED(hr)) 
		{						// can't initialize COM 
		ReportError(_T("CoInitialize"), hr); 
		return 1; 
		}						// can't initialize COM 
 
	hr = CoInitializeSecurity(NULL, -1, NULL, NULL,  
		RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE,  
		NULL, 0, 0); 
	if (!SUCCEEDED(hr)) 
		{						// can't fix security 
		ReportError(_T("CoInitializeSecurity"), hr); 
		CoUninitialize(); 
		return 1; 
		}						// can't fix security 
 
	IWbemLocator* locator; 
	hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (PVOID*) &locator); 
	if (SUCCEEDED(hr)) 
		{						// found locator 
 
		// Connect to the WMI server on this computer. Note that ConnectServer requires 
		// us to allocate a system string for the namespace argument -- a constant causes 
		// a crash in the WMI server. 
 
		IWbemServices* services; 
		BSTR pnamespace = SysAllocString(L"root\\WMI"); 
		hr = locator->ConnectServer(pnamespace, NULL, NULL, 0, 0, NULL, NULL, &services); 
		SysFreeString(pnamespace); 
		if (SUCCEEDED(hr)) 
			{					// found server 
 
			// Set the interface security to allow the server to impersonate us. Failing to 
			// to do this causes an "access denied" failure in CreateInstanceEnum. 
 
			IClientSecurity* security; 
			hr = services->QueryInterface(IID_IClientSecurity, (PVOID*) &security); 
			if (SUCCEEDED(hr)) 
				{				// set security 
				hr = security->SetBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, 
					NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, 
					NULL, EOAC_NONE); 
				if (!SUCCEEDED(hr)) 
					ReportError(_T("IClientSecurity::SetBlanket"), hr); 
				security->Release(); 
				}				// set security 
 
			// Report WMI information about the specified class 
 
			ReportInfo(services, L"wmiextra_expensive"); 
 
			// Test event reception 
 
			ReceiveEvent(services, L"wmiextra_event"); 
 
			// Test method invocation 
 
			CallMethod(services, L"wmiextra_method", L"AnswerMethod"); 
 
			services->Release(); 
			}					// found server 
		else 
			ReportError(_T("IWbemLocator::ConnectServer"), hr); 
 
		locator->Release(); 
		}						// found locator 
	else 
		ReportError(_T("CoCreateInstance(WbemLocator)"), hr); 
 
	CoUninitialize(); 
	return 0; 
	}							// main 
 
/////////////////////////////////////////////////////////////////////////////// 
 
void ReportInfo(IWbemServices* services, LPCWSTR classname) 
	{							// ReportInfo 
 
	// Open an instance enumerator for the class. 
 
	IEnumWbemClassObject* enumerator = NULL; 
	BSTR pclass = SysAllocString(classname); 
	HRESULT hr = services->CreateInstanceEnum(pclass, WBEM_FLAG_SHALLOW | WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &enumerator); 
 
	if (SUCCEEDED(hr)) 
		{						// enumerate instances 
		while (TRUE) 
			{					// for each instance 
			ULONG junk;				 
			IWbemClassObject* cop = NULL; 
			hr = enumerator->Next(INFINITE, 1, &cop, &junk); // i.e., no timeout, 1 object wanted 
			if (hr == WBEM_S_FALSE) 
				break; 
			if (hr) 
				{ 
				ReportError(_T("IEnumWbemClassObject::Next"), hr); 
				break; 
				} 
 
			VARIANT instname; 
			BSTR propname; 
 
			// Determine the instance name 
 
			propname = SysAllocString(L"InstanceName"); 
			hr = cop->Get(propname, 0, &instname, NULL, NULL); 
			SysFreeString(propname); 
 
			if (!SUCCEEDED(hr)) 
				{				// can't get instance name 
				ReportError(_T("IWbemClassObject::Get(InstanceName)"), hr); 
				cop->Release(); 
				continue; 
				}				// can't get instance name 
 
			// Determine the current value of the property 
			 
			VARIANT answer; 
			propname = SysAllocString(L"ExpensiveData"); 
			hr = cop->Get(propname, 0, &answer, NULL, NULL); 
 
			if (!SUCCEEDED(hr)) 
				{				// can't get instance name 
				ReportError(_T("IWbemClassObject::Get(ExpensiveData)"), hr); 
				SysFreeString(propname); 
				cop->Release(); 
				continue; 
				}				// can't get instance name 
 
			printf(_T("The answer from %ws was %d\n"), instname.bstrVal, answer.lVal); 
 
			SysFreeString(propname); 
			VariantClear(&instname); 
			VariantClear(&answer); 
			 
			cop->Release(); 
			} 
		enumerator->Release(); 
		} 
	else 
		ReportError("CreateInstanceEnum", hr); 
 
	SysFreeString(pclass); 
	}							// ReportInfo 
 
/////////////////////////////////////////////////////////////////////////////// 
 
void ReceiveEvent(IWbemServices* services, LPCWSTR classname) 
	{							// ReceiveEvent 
	BSTR language = SysAllocString(L"WQL"); 
 
	WCHAR query[256]; 
	wcscpy(query, L"select * from "); 
	wcscat(query, classname); 
	BSTR pquery = SysAllocString(query); 
 
	IEnumWbemClassObject* enumerator = NULL; 
	HRESULT hr = services->ExecNotificationQuery(language, pquery, 
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &enumerator); 
	SysFreeString(pquery); 
	SysFreeString(language); 
 
	if (!SUCCEEDED(hr)) 
		{ 
		ReportError(_T("IWbemServices::ExecNotificationQuery"), hr); 
		return; 
		} 
 
	// For purposes of this simple-minded test, send our driver an IOCTL that will make 
	// it generate an event. Then poll a few times for the event we expect to have 
	// delivered 
 
	HANDLE hDevice = CreateFile(_T("\\\\.\\WMIEXTRA"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 
	if (hDevice == INVALID_HANDLE_VALUE) 
		ReportError(_T("CreateFile"), GetLastError()); 
	else 
		{						// trigger event 
		DWORD junk; 
		if (DeviceIoControl(hDevice, IOCTL_FIRE_EVENT, NULL, 0, NULL, 0, &junk, NULL)) 
			{					// wait for event 
			for (int i = 0; i < 10; ++i) 
				{				// poll 
				IWbemClassObject* cop = NULL; 
				hr = enumerator->Next(1000, 1, &cop, &junk); 
				if (hr == WBEM_S_FALSE || hr == WBEM_S_TIMEDOUT) 
					continue; 
				if (hr) 
					{ 
					ReportError(_T("IEnumWbemClassObject::Next"), hr); 
					break; 
					} 
 
				BSTR propname; 
				VARIANT instname, evdata; 
 
				// Determine which instance signalled the event 
 
				propname = SysAllocString(L"InstanceName"); 
				hr = cop->Get(propname, 0, &instname, NULL, NULL); 
				SysFreeString(propname); 
 
				if (SUCCEEDED(hr)) 
					{ 
 
					// Get the event data and print a message 
 
					propname = SysAllocString(L"EventInfo"); 
					hr = cop->Get(propname, 0, &evdata, NULL, NULL); 
					if (SUCCEEDED(hr)) 
						{ 
						printf(_T("Instance %ws signalled event with data %d after %d poll(s)\n"), instname.bstrVal, evdata.lVal, i); 
						} 
					else 
						ReportError(_T("IWbemClassObject::Get(EventInfo)"), hr); 
 
					VariantClear(&instname); 
					} 
				else 
					ReportError(_T("IWbemClassObject::Get(InstanceName)"), hr); 
 
				cop->Release(); 
				break; 
				}				// poll 
 
			if (i >= 10) 
				puts(_T("No events found after 10 attempts")); 
			}					// wait for event 
		else 
			ReportError(_T("DeviceIoControl"), GetLastError()); 
 
		CloseHandle(hDevice); 
		}						// trigger event 
 
	enumerator->Release(); 
	}							// ReceiveEvent 
 
/////////////////////////////////////////////////////////////////////////////// 
 
void CallMethod(IWbemServices* services, LPCWSTR classname, LPCWSTR methname) 
	{							// CallMethod 
	BSTR pclass = SysAllocString(classname); 
	BSTR pmethod = SysAllocString(methname); 
	BSTR objpath = NULL; 
	HRESULT hr; 
 
	// Develop the name of one object instance whose method we'll invoke. This is 
	// a gigantic pain in the neck. Really, now, there ought to be a method routine 
	// we could call to do this! 
 
	IEnumWbemClassObject* enumerator = NULL; 
	hr = services->CreateInstanceEnum(pclass,  WBEM_FLAG_SHALLOW | WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &enumerator); 
	if (SUCCEEDED(hr)) 
		{						// have enumerator 
		IWbemClassObject* instance = NULL; 
		ULONG junk; 
		hr = enumerator->Next(INFINITE, 1, &instance, &junk); 
		if (SUCCEEDED(hr)) 
			{					// have class instance 
			VARIANT instname; 
			BSTR propname = SysAllocString(L"InstanceName"); 
			hr = instance->Get(propname, 0, &instname, NULL, NULL); 
			SysFreeString(propname); 
			if (SUCCEEDED(hr)) 
				{				// have instance name 
				WCHAR fullpath[256]; 
				WCHAR escapedname[256]; 
				WCHAR* s = instname.bstrVal; 
				WCHAR* t = escapedname; 
				WCHAR ch; 
				while (ch = *s++) 
					{ 
					*t++ = ch; 
					if (ch == L'\\') 
						*t++ = ch;	// double any backslashes 
					} 
				*t = 0; 
				swprintf(fullpath, L"%ws.InstanceName=\"%s\"", classname, escapedname); 
				objpath = SysAllocString(fullpath); 
				VariantClear(&instname); 
				}				// have instance name 
			else 
				ReportError(_T("IWbemClassObject::Get"), hr); 
 
			instance->Release(); 
			}					// have class instance 
		else 
			ReportError(_T("IEnumWbemClassObject::Next"), hr); 
 
		enumerator->Release(); 
		}						// have enumerator 
	else 
		ReportError(_T("IWbemServices::CreateInstanceEnum"), hr); 
 
	if (FAILED(hr)) 
		{ 
		SysFreeString(pclass); 
		SysFreeString(pmethod); 
		return; 
		} 
 
#if 0 
	IWbemCallResult* result = NULL; 
	IWbemClassObject* outargs = NULL; 
	hr = services->ExecMethod(objpath, pmethod, 0, NULL, NULL, &outargs, &result); 
	if (SUCCEEDED(hr)) 
		{ 
		if (outargs) 
			outargs->Release(); 
		if (result) 
			result->Release(); 
		} 
	else 
		ReportError(_T("IWbemServices::ExecMethod"), hr); 
#else 
	// Get the class object 
	 
	IWbemClassObject* cop = NULL; 
	hr = services->GetObject(pclass, 0, NULL, &cop, NULL); 
	if (SUCCEEDED(hr)) 
		{						// have class object 
 
		// Get the input argument class object for the method we want to call 
 
		IWbemClassObject* iop = NULL; 
		hr = cop->GetMethod(pmethod, 0, &iop, NULL); 
 
		if (SUCCEEDED(hr)) 
			{					// have input argument class 
 
			// Create an instance of the input argument object 
 
			IWbemClassObject* inarg = NULL; 
			hr = iop->SpawnInstance(0, &inarg); 
			if (SUCCEEDED(hr)) 
				{				// have input argument 
 
				// Set the input argument value 
 
				BSTR argname = SysAllocString(L"TheAnswer"); 
				VARIANT argval; 
				argval.vt = VT_I4; 
				argval.lVal = 99; 
				hr = inarg->Put(argname, 0, &argval, 0); 
				SysFreeString(argname); 
				if (FAILED(hr)) 
					ReportError(_T("IWbemClassObject::Put"), hr); 
 
				// Invoke the method 
 
				IWbemClassObject* result = NULL; 
				hr = services->ExecMethod(objpath, pmethod, 0, NULL, inarg, &result, NULL); 
				if (SUCCEEDED(hr)) 
					{			// method call succeeded 
 
					// Print the resulting object by calling GetObjectText 
 
					BSTR restext = NULL; 
					hr = result->GetObjectText(0, &restext); 
					if (SUCCEEDED(hr)) 
						{		// print result 
 
						/////////////////////////////////////////////////////// 
						//     HERE'S WHERE WE FINALLY PRINT THE RESULT 
						/////////////////////////////////////////////////////// 
 
						_tprintf(_T("The %ws method returned:\n%ws\n"), methname, restext); 
						SysFreeString(restext); 
						}		// print result 
					else 
						ReportError(_T("IWbemObject::GetObjectText"), hr); 
 
					result->Release(); 
					}			// method call succeeded 
				else 
					ReportError(_T("IWbemServices::ExecMethod"), hr); 
				inarg->Release(); 
				}				// have input argument 
			else 
				ReportError(_T("IWbemClassObject::SpawnInstance"), hr); 
 
			iop->Release(); 
			}					// have input argument class 
		else 
			ReportError(_T("IWbemClassObject::GetMethod"), hr); 
 
 
		cop->Release(); 
		}						// have class object 
	else 
		ReportError(_T("IWbemServices::GetObject"), hr); 
#endif 
 
	SysFreeString(pclass); 
	SysFreeString(pmethod); 
	if (objpath) 
		SysFreeString(objpath); 
	}							// CallMethod 
 
/////////////////////////////////////////////////////////////////////////////// 
 
void ReportError(LPCTSTR fcn, DWORD code) 
	{							// ReportError 
	static struct {DWORD code; LPTSTR text;} wmierrors[] = { 
		{WBEM_S_FALSE, _T("WBEM_S_FALSE")}, 
		{WBEM_S_ALREADY_EXISTS, _T("WBEM_S_ALREADY_EXISTS")}, 
		{WBEM_S_RESET_TO_DEFAULT, _T("WBEM_S_RESET_TO_DEFAULT")}, 
		{WBEM_S_DIFFERENT, _T("WBEM_S_DIFFERENT")}, 
		{WBEM_S_TIMEDOUT, _T("WBEM_S_TIMEDOUT")}, 
		{WBEM_S_NO_MORE_DATA, _T("WBEM_S_NO_MORE_DATA")}, 
		{WBEM_S_OPERATION_CANCELLED, _T("WBEM_S_OPERATION_CANCELLED")}, 
		{WBEM_S_PENDING, _T("WBEM_S_PENDING")}, 
		{WBEM_S_DUPLICATE_OBJECTS, _T("WBEM_S_DUPLICATE_OBJECTS")}, 
		{WBEM_E_FAILED, _T("WBEM_E_FAILED")}, 
		{WBEM_E_NOT_FOUND, _T("WBEM_E_NOT_FOUND")}, 
		{WBEM_E_ACCESS_DENIED, _T("WBEM_E_ACCESS_DENIED")}, 
		{WBEM_E_PROVIDER_FAILURE, _T("WBEM_E_PROVIDER_FAILURE")}, 
		{WBEM_E_TYPE_MISMATCH, _T("WBEM_E_TYPE_MISMATCH")}, 
		{WBEM_E_OUT_OF_MEMORY, _T("WBEM_E_OUT_OF_MEMORY")}, 
		{WBEM_E_INVALID_CONTEXT, _T("WBEM_E_INVALID_CONTEXT")}, 
		{WBEM_E_INVALID_PARAMETER, _T("WBEM_E_INVALID_PARAMETER")}, 
		{WBEM_E_NOT_AVAILABLE, _T("WBEM_E_NOT_AVAILABLE")}, 
		{WBEM_E_CRITICAL_ERROR, _T("WBEM_E_CRITICAL_ERROR")}, 
		{WBEM_E_INVALID_STREAM, _T("WBEM_E_INVALID_STREAM")}, 
		{WBEM_E_NOT_SUPPORTED, _T("WBEM_E_NOT_SUPPORTED")}, 
		{WBEM_E_INVALID_SUPERCLASS, _T("WBEM_E_INVALID_SUPERCLASS")}, 
		{WBEM_E_INVALID_NAMESPACE, _T("WBEM_E_INVALID_NAMESPACE")}, 
		{WBEM_E_INVALID_OBJECT, _T("WBEM_E_INVALID_OBJECT")}, 
		{WBEM_E_INVALID_CLASS, _T("WBEM_E_INVALID_CLASS")}, 
		{WBEM_E_PROVIDER_NOT_FOUND, _T("WBEM_E_PROVIDER_NOT_FOUND")}, 
		{WBEM_E_INVALID_PROVIDER_REGISTRATION, _T("WBEM_E_INVALID_PROVIDER_REGISTRATION")}, 
		{WBEM_E_PROVIDER_LOAD_FAILURE, _T("WBEM_E_PROVIDER_LOAD_FAILURE")}, 
		{WBEM_E_INITIALIZATION_FAILURE, _T("WBEM_E_INITIALIZATION_FAILURE")}, 
		{WBEM_E_TRANSPORT_FAILURE, _T("WBEM_E_TRANSPORT_FAILURE")}, 
		{WBEM_E_INVALID_OPERATION, _T("WBEM_E_INVALID_OPERATION")}, 
		{WBEM_E_INVALID_QUERY, _T("WBEM_E_INVALID_QUERY")}, 
		{WBEM_E_INVALID_QUERY_TYPE, _T("WBEM_E_INVALID_QUERY_TYPE")}, 
		{WBEM_E_ALREADY_EXISTS, _T("WBEM_E_ALREADY_EXISTS")}, 
		{WBEM_E_OVERRIDE_NOT_ALLOWED, _T("WBEM_E_OVERRIDE_NOT_ALLOWED")}, 
		{WBEM_E_PROPAGATED_QUALIFIER, _T("WBEM_E_PROPAGATED_QUALIFIER")}, 
		{WBEM_E_PROPAGATED_PROPERTY, _T("WBEM_E_PROPAGATED_PROPERTY")}, 
		{WBEM_E_UNEXPECTED, _T("WBEM_E_UNEXPECTED")}, 
		{WBEM_E_ILLEGAL_OPERATION, _T("WBEM_E_ILLEGAL_OPERATION")}, 
		{WBEM_E_CANNOT_BE_KEY, _T("WBEM_E_CANNOT_BE_KEY")}, 
		{WBEM_E_INCOMPLETE_CLASS, _T("WBEM_E_INCOMPLETE_CLASS")}, 
		{WBEM_E_INVALID_SYNTAX, _T("WBEM_E_INVALID_SYNTAX")}, 
		{WBEM_E_NONDECORATED_OBJECT, _T("WBEM_E_NONDECORATED_OBJECT")}, 
		{WBEM_E_READ_ONLY, _T("WBEM_E_READ_ONLY")}, 
		{WBEM_E_PROVIDER_NOT_CAPABLE, _T("WBEM_E_PROVIDER_NOT_CAPABLE")}, 
		{WBEM_E_CLASS_HAS_CHILDREN, _T("WBEM_E_CLASS_HAS_CHILDREN")}, 
		{WBEM_E_CLASS_HAS_INSTANCES, _T("WBEM_E_CLASS_HAS_INSTANCES")}, 
		{WBEM_E_QUERY_NOT_IMPLEMENTED, _T("WBEM_E_QUERY_NOT_IMPLEMENTED")}, 
		{WBEM_E_ILLEGAL_NULL, _T("WBEM_E_ILLEGAL_NULL")}, 
		{WBEM_E_INVALID_QUALIFIER_TYPE, _T("WBEM_E_INVALID_QUALIFIER_TYPE")}, 
		{WBEM_E_INVALID_PROPERTY_TYPE, _T("WBEM_E_INVALID_PROPERTY_TYPE")}, 
		{WBEM_E_VALUE_OUT_OF_RANGE, _T("WBEM_E_VALUE_OUT_OF_RANGE")}, 
		{WBEM_E_CANNOT_BE_SINGLETON, _T("WBEM_E_CANNOT_BE_SINGLETON")}, 
		{WBEM_E_INVALID_CIM_TYPE, _T("WBEM_E_INVALID_CIM_TYPE")}, 
		{WBEM_E_INVALID_METHOD, _T("WBEM_E_INVALID_METHOD")}, 
		{WBEM_E_INVALID_METHOD_PARAMETERS, _T("WBEM_E_INVALID_METHOD_PARAMETERS")}, 
		{WBEM_E_SYSTEM_PROPERTY, _T("WBEM_E_SYSTEM_PROPERTY")}, 
		{WBEM_E_INVALID_PROPERTY, _T("WBEM_E_INVALID_PROPERTY")}, 
		{WBEM_E_CALL_CANCELLED, _T("WBEM_E_CALL_CANCELLED")}, 
		{WBEM_E_SHUTTING_DOWN, _T("WBEM_E_SHUTTING_DOWN")}, 
		{WBEM_E_PROPAGATED_METHOD, _T("WBEM_E_PROPAGATED_METHOD")}, 
		{WBEM_E_UNSUPPORTED_PARAMETER, _T("WBEM_E_UNSUPPORTED_PARAMETER")}, 
		{WBEM_E_MISSING_PARAMETER_ID, _T("WBEM_E_MISSING_PARAMETER_ID")}, 
		{WBEM_E_INVALID_PARAMETER_ID, _T("WBEM_E_INVALID_PARAMETER_ID")}, 
		{WBEM_E_NONCONSECUTIVE_PARAMETER_IDS, _T("WBEM_E_NONCONSECUTIVE_PARAMETER_IDS")}, 
		{WBEM_E_PARAMETER_ID_ON_RETVAL, _T("WBEM_E_PARAMETER_ID_ON_RETVAL")}, 
		{WBEM_E_INVALID_OBJECT_PATH, _T("WBEM_E_INVALID_OBJECT_PATH")}, 
		{WBEM_E_OUT_OF_DISK_SPACE, _T("WBEM_E_OUT_OF_DISK_SPACE")}, 
		{WBEMESS_E_REGISTRATION_TOO_BROAD, _T("WBEMESS_E_REGISTRATION_TOO_BROAD")}, 
		{WBEMESS_E_REGISTRATION_TOO_PRECISE, _T("WBEMESS_E_REGISTRATION_TOO_PRECISE")}, 
		}; 
 
	LPTSTR msg = NULL; 
 
	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 
		NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
		(LPTSTR) &msg, 0, NULL)) 
 
		_tprintf(_T("Error %8.8lX in %s: %s\n"), code, fcn, msg); 
	else 
		{						// not a standard message 
		for (int i = 0; i < arraysize(wmierrors); ++i) 
			if (wmierrors[i].code == code) 
				break; 
		if (i < arraysize(wmierrors)) 
			_tprintf(_T("Error %8.8lX in %s: %s\n"), code, fcn, wmierrors[i].text); 
		else 
			_tprintf(_T("Error %8.8lX in %s\n"), code, fcn); 
		}						// not a standard message 
 
	if (msg) 
		LocalFree((LPVOID) msg); 
	}							// ReportError