629 lines
19 KiB
C++
629 lines
19 KiB
C++
// Copyright (c) 1996-2000 Microsoft Corporation
|
||
|
||
// --------------------------------------------------------------------------
|
||
//
|
||
// OLEACC
|
||
//
|
||
// DllMain and other entry points.
|
||
//
|
||
// --------------------------------------------------------------------------
|
||
|
||
|
||
#include "oleacc_p.h"
|
||
#include "classmap.h"
|
||
#include "w95trace.h"
|
||
#include "memchk.h"
|
||
#include "fwd_macros.h"
|
||
|
||
#include "PropMgr_Client.h"
|
||
|
||
|
||
// Define this locally instead of #including "PropMgr_Impl", since that
|
||
// drags in lots of ATL goo.
|
||
void PropMgrImpl_Uninit();
|
||
|
||
//
|
||
// Shared Globals
|
||
//
|
||
// Note that these are only used when running on 9x; and are not even present
|
||
// on builds which are specifically for W2K.
|
||
//
|
||
|
||
#ifndef NTONLYBUILD
|
||
#pragma data_seg("Shared")
|
||
LONG g_cProcessesMinus1 = -1; // number of attached processes minus 1 (the Interlocked APIs don't work well with 0 as a base)
|
||
HANDLE hheapShared = NULL; // handle to the shared heap (Win95 only)
|
||
#pragma data_seg()
|
||
#pragma comment(linker, "/Section:Shared,RWS")
|
||
#endif // NTONLYBUILD
|
||
|
||
|
||
//
|
||
// Globals
|
||
//
|
||
|
||
HANDLE g_hLoadedMutex; // Useful mutex - by using oh.exe to look for this,
|
||
// we can see who's loaded our .dll.
|
||
HINSTANCE g_hinstDll; // instance of this library - nothing actually uses this at the moment.
|
||
HINSTANCE hinstResDll; // instance of resource library
|
||
BOOL fCreateDefObjs; // running with new USER32?
|
||
BOOL g_fInitedOleacc = FALSE; // Set by InitOleacc()
|
||
#ifdef _X86_
|
||
BOOL fWindows95; // running on Windows '95?
|
||
#endif // _X86_
|
||
|
||
|
||
//
|
||
// Forward decls...
|
||
//
|
||
|
||
|
||
//
|
||
// DLL rountines that we chain - we combine:
|
||
// * Core oleacc (only DllMan, reg and unreg)
|
||
// * RemoteProxyFactory6432
|
||
// * Proxy/Stubs fpr the PropMgr
|
||
//
|
||
extern "C" {
|
||
BOOL WINAPI Oleacc_DllMain( HINSTANCE hinst, DWORD dwReason, LPVOID pvReserved );
|
||
HRESULT WINAPI Oleacc_DllRegisterServer();
|
||
HRESULT WINAPI Oleacc_DllUnregisterServer();
|
||
|
||
BOOL WINAPI ProxyStub_DllMain( HINSTANCE hinst, DWORD dwReason, LPVOID pvReserved );
|
||
HRESULT WINAPI ProxyStub_DllRegisterServer();
|
||
HRESULT WINAPI ProxyStub_DllUnregisterServer();
|
||
HRESULT WINAPI ProxyStub_DllCanUnloadNow();
|
||
HRESULT WINAPI ProxyStub_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
|
||
|
||
BOOL WINAPI ComATLMain_DllMain( HINSTANCE hinst, DWORD dwReason, LPVOID pvReserved );
|
||
HRESULT WINAPI ComATLMain_DllRegisterServer();
|
||
HRESULT WINAPI ComATLMain_DllUnregisterServer();
|
||
HRESULT WINAPI ComATLMain_DllCanUnloadNow();
|
||
HRESULT WINAPI ComATLMain_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
|
||
};
|
||
|
||
|
||
// This one is called from DLLMain... (not safe to use LoadLibrary etc.)
|
||
static BOOL InitOleaccDLL( HINSTANCE hInstance );
|
||
|
||
// And this one is called in DLLMain when exiting...
|
||
static void UninitOleacc();
|
||
|
||
|
||
// This displays a "oleacc version xxxxxx loading/unloading from process xxxx" message
|
||
#ifdef _DEBUG
|
||
static void DisplayLoadUnloadString( LPCTSTR pszAction );
|
||
#endif // _DEBUG
|
||
|
||
|
||
|
||
|
||
|
||
// if this W2K and not ALPHA enable 64b/32b interoperability
|
||
#if defined(UNICODE) && !defined(_M_AXP64)
|
||
#define ENABLE6432_INTEROP
|
||
#endif
|
||
|
||
|
||
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD dwReason, LPVOID pvReserved )
|
||
{
|
||
#ifdef _WIN64
|
||
DBPRINTF(TEXT("******** Hello from 64-bit OLEACC! ******** \r\n"));
|
||
#else
|
||
DBPRINTF(TEXT("******** Hello from 32-bit OLEACC! ******** \r\n"));
|
||
#endif
|
||
if( ! Oleacc_DllMain( hinst, dwReason, pvReserved ) )
|
||
{
|
||
DBPRINTF(TEXT("Oleacc_DllMain FAILED\r\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
// Call the remote proxy factory for 64/32 bit interop DllMain
|
||
// TODO Possible performance improvement: only call ProxyFactoryDllMain if loaded by DLLHost32/64
|
||
if( ! ComATLMain_DllMain( hinst, dwReason, pvReserved ) )
|
||
{
|
||
DBPRINTF(TEXT("ComATLMain_DllMain FAILED\r\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
if( ! ProxyStub_DllMain( hinst, dwReason, pvReserved ) )
|
||
{
|
||
DBPRINTF(TEXT("ProxyStub_DllMain FAILED\r\n"));
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// Note about what gets registered:
|
||
//
|
||
// Oleacc_DllRegisterServer regiters the main typelib - this registers the
|
||
// IAccessible interfaces, and sets them to use typelib marshalling.
|
||
//
|
||
// ProxyStub_DllRegisterServer re-registers the IAccessible interface, also
|
||
// registers the IAccProp* annotation interfaces, and sets all those
|
||
// interfaces to use proxy/stub marshalling, overwriting the previous
|
||
// typelib marshalling, if any.
|
||
//
|
||
// Oleacc's DLLMain calls Oleacc_DllRegisterServer, which again
|
||
// re-registers the interfaces, and sets IAccessible back to using
|
||
// typelib marshalling.
|
||
//
|
||
// Bottom line is that all the interfaces do get registered, though
|
||
// some may use typelib marshalling, some may use proxy/stub marshalling.
|
||
// Doesn't really matter which is used; both marshalling techniques
|
||
// have the same end result.
|
||
//
|
||
//
|
||
//
|
||
// When unregistering, Oleacc_DllUnregisterServer calls the typelib
|
||
// unregistration function, which removes the entries for all the IAccessible
|
||
// interfaces.
|
||
//
|
||
// ProxyStub_DllUnregister tries to unregister all the IAccessible and IAccProp
|
||
// interfaces - it will successfully remove all those that exist, but on 9x,
|
||
// it will return an error hresult because some of those have already been
|
||
// unregistered by Oleacc_DllUnregisterServer. (W2K doesn't complain about
|
||
// this.) We can safely ignore this error.
|
||
//
|
||
//
|
||
// One possible alternative to all the above would be to just use the
|
||
// proxy/stub registration and marshalling, and remove the IAccessible
|
||
// typelib stuff completely. This would simplify this code, and simplify
|
||
// the data in the registry. However, the typelib approach was kept
|
||
// just in case there is some code or tool out there that expects to
|
||
// be able to find a typelib for IAccessible via the registry.
|
||
//
|
||
//
|
||
// (Note that the ComATL_* registers/unregisters the Win64 helper
|
||
// classes, and that always uses typelib marshalling - using the
|
||
// second typelib in oleacc.dll. See those functions for more info.)
|
||
//
|
||
//
|
||
HRESULT WINAPI DllRegisterServer()
|
||
{
|
||
HRESULT hrRet = Oleacc_DllRegisterServer();
|
||
|
||
HRESULT hr = ComATLMain_DllRegisterServer();
|
||
if( hrRet == S_OK )
|
||
hrRet = hr;
|
||
|
||
hr = ProxyStub_DllRegisterServer();
|
||
if( hrRet == S_OK )
|
||
hrRet = hr;
|
||
|
||
return hrRet;
|
||
}
|
||
|
||
HRESULT WINAPI DllUnregisterServer()
|
||
{
|
||
HRESULT hrRet = Oleacc_DllUnregisterServer();
|
||
|
||
HRESULT hr = ComATLMain_DllUnregisterServer();
|
||
if( hrRet == S_OK )
|
||
hrRet = hr;
|
||
|
||
// We ignore the 'file not found' error returned by the proxy/stub unregistration
|
||
// code. It tries to unreg all interfaces mentioned in oleacc.idl - but most of those
|
||
// have already been unregd by Oleacc_DllUnregisterServer above. On 9x, it returns
|
||
// this error, which we must ignore. (The w2k version doesn't return this error -
|
||
// it looks like it ignores it internally.)
|
||
hr = ProxyStub_DllUnregisterServer();
|
||
if( hr != HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) && hrRet == S_OK )
|
||
hrRet = hr;
|
||
|
||
return hrRet;
|
||
}
|
||
|
||
|
||
HRESULT WINAPI DllCanUnloadNow()
|
||
{
|
||
HRESULT hr = ComATLMain_DllCanUnloadNow();
|
||
if( hr != S_OK )
|
||
return hr;
|
||
|
||
return ProxyStub_DllCanUnloadNow();
|
||
}
|
||
|
||
|
||
|
||
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
|
||
{
|
||
HRESULT hr = ComATLMain_DllGetClassObject(rclsid, riid, ppv);
|
||
if( hr == S_OK )
|
||
return hr;
|
||
|
||
return ProxyStub_DllGetClassObject(rclsid, riid, ppv);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// DLLMain
|
||
//
|
||
|
||
|
||
BOOL WINAPI Oleacc_DllMain( HINSTANCE hinst, DWORD dwReason, LPVOID unused( pvReserved ) )
|
||
{
|
||
if( dwReason == DLL_PROCESS_ATTACH )
|
||
{
|
||
// We don't need DLL_THREAD_XXX notifications - more efficient to not have them...
|
||
DisableThreadLibraryCalls( hinst );
|
||
|
||
if( ! InitOleaccDLL( hinst ) )
|
||
return FALSE;
|
||
}
|
||
else if (dwReason == DLL_PROCESS_DETACH)
|
||
{
|
||
UninitOleacc();
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// Oleacc_DllRegisterServer
|
||
//
|
||
|
||
#define TYPELIB_MAJORVER 1
|
||
#define TYPELIB_MINORVER 1
|
||
|
||
HRESULT WINAPI Oleacc_DllRegisterServer()
|
||
{
|
||
ITypeLib *pTypeLib = NULL;
|
||
HRESULT hr;
|
||
OLECHAR wszOleAcc[] = L"oleacc.dll";
|
||
|
||
hr = LoadTypeLib( wszOleAcc, &pTypeLib );
|
||
|
||
if ( SUCCEEDED(hr) )
|
||
{
|
||
hr = RegisterTypeLib( pTypeLib, wszOleAcc, NULL );
|
||
if ( FAILED(hr) )
|
||
DBPRINTF (TEXT("OLEACC: DllRegisterServer could not register type library hr=%lX\r\n"),hr);
|
||
pTypeLib->Release();
|
||
}
|
||
else
|
||
{
|
||
DBPRINTF (TEXT("OLEACC: DllRegisterServer could not load type library hr=%lX\r\n"),hr);
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
|
||
|
||
HRESULT WINAPI Oleacc_DllUnregisterServer()
|
||
{
|
||
// The major/minor typelib version number determine
|
||
// which regisered version of OLEACC.DLL will get
|
||
// unregistered.
|
||
|
||
return UnRegisterTypeLib( LIBID_Accessibility, TYPELIB_MAJORVER, TYPELIB_MINORVER, 0, SYS_WIN32 );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
// --------------------------------------------------------------------------
|
||
//
|
||
// Stubs for the exported APIs.
|
||
//
|
||
// The .def file references these (instead of referencing the exported APIs
|
||
// directly) - and these currently just call through to the API code.
|
||
// We can change these to pre/post process or jump elsewhere if necessary.
|
||
//
|
||
// --------------------------------------------------------------------------
|
||
|
||
#define FORWARD( ret, name, c, params ) /**/\
|
||
extern "C" ret WINAPI EXTERNAL_ ## name AS_DECL( c, params )\
|
||
{\
|
||
if( ! g_fInitedOleacc )\
|
||
InitOleacc();\
|
||
return name AS_CALL( c, params );\
|
||
}
|
||
|
||
#define FORWARD_VOID( name, c, params ) /**/\
|
||
extern "C" VOID WINAPI EXTERNAL_ ## name AS_DECL( c, params )\
|
||
{\
|
||
if( ! g_fInitedOleacc )\
|
||
InitOleacc();\
|
||
name AS_CALL( c, params );\
|
||
}
|
||
|
||
|
||
FORWARD( LRESULT, LresultFromObject, 3, ( REFIID, riid, WPARAM, wParam, LPUNKNOWN, punk ) )
|
||
FORWARD( HRESULT, ObjectFromLresult, 4, ( LRESULT, lResult, REFIID, riid, WPARAM, wParam, void**, ppvObject ) )
|
||
FORWARD( HRESULT, WindowFromAccessibleObject, 2, ( IAccessible *, ppAcc, HWND *, phwnd ) )
|
||
FORWARD( HRESULT, AccessibleObjectFromWindow, 4, ( HWND, hwnd, DWORD, dwId, REFIID, riid, void **, ppvObject ) )
|
||
FORWARD( HRESULT, AccessibleObjectFromEvent, 5, ( HWND, hwnd, DWORD, dwId, DWORD, dwChildId, IAccessible **, ppacc, VARIANT *, pvarChild ) )
|
||
FORWARD( HRESULT, AccessibleObjectFromPoint, 3, ( POINT, ptScreen, IAccessible **, ppacc, VARIANT *, pvarChild ) )
|
||
FORWARD( HRESULT, AccessibleChildren, 5, ( IAccessible *, paccContainer, LONG, iChildStart, LONG, cChildren, VARIANT *, rgvarChildren, LONG *, pcObtained ) )
|
||
FORWARD( UINT, GetRoleTextA, 3, ( DWORD, lRole, LPSTR, lpszRole, UINT, cchRoleMax ) )
|
||
FORWARD( UINT, GetRoleTextW, 3, ( DWORD, lRole, LPWSTR, lpszRole, UINT, cchRoleMax ) )
|
||
FORWARD( UINT, GetStateTextA, 3, ( DWORD, lStateBit, LPSTR, lpszState, UINT, cchState ) )
|
||
FORWARD( UINT, GetStateTextW, 3, ( DWORD, lStateBit, LPWSTR, lpszState, UINT, cchState ) )
|
||
FORWARD( HRESULT, CreateStdAccessibleObject, 4, ( HWND, hwnd, LONG, idObject, REFIID, riid, void **, ppvObject ) )
|
||
FORWARD( HRESULT, CreateStdAccessibleProxyA, 5, ( HWND, hwnd, LPCSTR, pClassName, LONG, idObject, REFIID, riid, void **, ppvObject ) )
|
||
FORWARD( HRESULT, CreateStdAccessibleProxyW, 5, ( HWND, hwnd, LPCWSTR, pClassName, LONG, idObject, REFIID, riid, void **, ppvObject ) )
|
||
|
||
FORWARD_VOID( GetOleaccVersionInfo, 2, ( DWORD *, pVer, DWORD *, pBuild ) )
|
||
|
||
|
||
|
||
|
||
|
||
//
|
||
// InitOleaccDLL
|
||
//
|
||
// Called from DLLMain - only do bare minimum init here - leave proper initing
|
||
// to InitOleacc(), which is called the first time one of the APIs is called.
|
||
//
|
||
// Since this is called from DLLMain, we can't use LoadLibrary() (or anything
|
||
// that uses that) here. See the docs on DLLMain for additional restrictions.
|
||
//
|
||
// Anything that can affect the success of this DLL loading/unloading should
|
||
// also go here.
|
||
//
|
||
static
|
||
BOOL InitOleaccDLL( HINSTANCE hInstance )
|
||
{
|
||
|
||
g_hLoadedMutex = CreateMutex(NULL,NULL,__TEXT("oleacc-msaa-loaded"));
|
||
|
||
|
||
g_hinstDll = hInstance;
|
||
|
||
// check platform version information
|
||
OSVERSIONINFO osvi;
|
||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||
GetVersionEx(&osvi);
|
||
|
||
// refuse to run on Win32s
|
||
if (osvi.dwPlatformId == VER_PLATFORM_WIN32s)
|
||
return FALSE;
|
||
|
||
#ifdef _X86_
|
||
fWindows95 = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
||
#endif // _X86_
|
||
|
||
// Load the resource-only DLL. We're not supposed to use regular
|
||
// LoadLibary from within DLLMain, but LoadLibraryEx is safe,
|
||
// since it only maps the file, and doesn't exec any code (that
|
||
// lib's DLLMain).
|
||
hinstResDll = LoadLibraryEx( TEXT("OLEACCRC.DLL"), NULL, LOAD_LIBRARY_AS_DATAFILE );
|
||
if( ! hinstResDll )
|
||
{
|
||
// Refuse to load if oleaccrc isn't present
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
// Use the counter g_cProcessesMinus1 to figure out if this is the
|
||
// first time this DLL is loaded. If so, do any necessary once-off
|
||
// setup - eg. setting up values in the (9x-only) shared segment.
|
||
|
||
// InterlockedIncrement() and Decrement() return 1 if the result is
|
||
// positive, 0 if zero, and -1 if negative. Therefore, the only
|
||
// way to use them practically is to start with a counter at -1.
|
||
// Then incrementing from -1 to 0, the first time, will give you
|
||
// a unique value of 0. And decrementing the last time from 0 to -1
|
||
// will give you a unique value of -1.
|
||
|
||
#ifndef NTONLYBUILD
|
||
#ifdef _X86_
|
||
if( InterlockedIncrement( & g_cProcessesMinus1 ) == 0 )
|
||
{
|
||
// if on Win95, create a shared heap to use when
|
||
// communicating with controls in other processes
|
||
if( fWindows95 )
|
||
{
|
||
hheapShared = HeapCreate( HEAP_SHARED, 0, 0 );
|
||
if( hheapShared == NULL )
|
||
return FALSE;
|
||
}
|
||
}
|
||
#endif // _X86_
|
||
#endif // NTONLYBUILD
|
||
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// InitOleacc
|
||
//
|
||
// Called when any of our APIs is called for the first time. Proper initialization
|
||
// happens here. Also called in DllGetClassObject.
|
||
//
|
||
BOOL InitOleacc()
|
||
{
|
||
if (g_fInitedOleacc)
|
||
return TRUE;
|
||
|
||
g_fInitedOleacc = TRUE;
|
||
|
||
// set the flag that causes proxies to work.
|
||
fCreateDefObjs = TRUE;
|
||
|
||
// Init any GetProcAddress'd imports
|
||
InitImports();
|
||
|
||
|
||
#ifdef _DEBUG
|
||
|
||
// Initialize the new/delete checker...
|
||
InitMemChk();
|
||
|
||
DisplayLoadUnloadString( TEXT("loading") );
|
||
|
||
#ifndef NTONLYBUILD
|
||
|
||
// On first load, show dialog with names of any imports not found...
|
||
if( g_cProcessesMinus1 == 0 )
|
||
{
|
||
TCHAR szErrorMsg[1024];
|
||
lstrcpy( szErrorMsg,TEXT("WARNING: the following functions were not found:\r\n") );
|
||
|
||
LPTSTR pEnd = szErrorMsg + lstrlen( szErrorMsg );
|
||
ReportMissingImports( pEnd );
|
||
|
||
if( *pEnd )
|
||
{
|
||
MessageBeep( MB_ICONEXCLAMATION );
|
||
MessageBox( NULL, szErrorMsg, TEXT("OLEACC.DLL"), MB_OK | MB_ICONEXCLAMATION );
|
||
DBPRINTF( szErrorMsg );
|
||
}
|
||
}
|
||
|
||
#endif // NTONLYBUILD
|
||
|
||
#endif // _DEBUG
|
||
|
||
|
||
// Everything that follows is done for every process attach.
|
||
|
||
// do a LoadLibrary of OLEAUT32.DLL to ensure that it stays
|
||
// loaded in every process that OLEACC is attched to.
|
||
// There is a slight chance of a crash. From Paul Vick:
|
||
// The problem occurs when oleaut32.dll is loaded into a process,
|
||
// used, unloaded and then loaded again. When you try to use
|
||
// oleaut32.dll in this case, you crash because of a problem
|
||
// manging state between us (oleaut32) and OLE. What happens is that when
|
||
// oleaut32.dll is loaded, we register some state with OLE so
|
||
// we are notified when OLE is uninitialized. In some cases
|
||
// (esp. multithreading), we are not able to clean up this
|
||
// state when we<77>re unloaded. When you reload oleaut32.dll,
|
||
// we try to set the state in OLE again and OLE tries to free
|
||
// the old (invalid) state, causing a crash later on.
|
||
LoadLibrary( TEXT("OLEAUT32.DLL") );
|
||
|
||
InitWindowClasses();
|
||
|
||
// Since Office 97 can mess up the registration,
|
||
// we'll call our self-registration function.
|
||
// may be slight perf hit on load, but not that big a deal,
|
||
// and this way we know we are always correctly registered..
|
||
Oleacc_DllRegisterServer();
|
||
|
||
// Initialize the property/annotation client
|
||
PropMgrClient_Init();
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// UninitOleacc
|
||
//
|
||
// Called on DLL Detach time from DLLMain. Any necessary cleanup happens here.
|
||
//
|
||
static
|
||
void UninitOleacc()
|
||
{
|
||
PropMgrImpl_Uninit();
|
||
|
||
PropMgrClient_Uninit();
|
||
|
||
// Release the resource DLL. Usually FreeLibrary isn't safe, but it's OK
|
||
// here since this is a resource-only DLL that was loaded _AS_DATAFILE.
|
||
if( hinstResDll )
|
||
FreeLibrary( hinstResDll );
|
||
|
||
#ifdef _DEBUG
|
||
// This reports the number of outstanding delete's, if any...
|
||
UninitMemChk();
|
||
DisplayLoadUnloadString( TEXT("unloading") );
|
||
#endif // _DEBUG
|
||
|
||
|
||
#ifndef NTONLYBUILD
|
||
// stuff that needs to be cleaned up on the last detach - clean
|
||
// up stuff in the shared data segment.
|
||
if (InterlockedDecrement(&g_cProcessesMinus1) == -1)
|
||
{
|
||
#ifdef _X86_
|
||
if (fWindows95)
|
||
{
|
||
if (hheapShared)
|
||
HeapDestroy(hheapShared);
|
||
hheapShared = NULL;
|
||
}
|
||
#endif // _X86_
|
||
UnInitWindowClasses();
|
||
}
|
||
#endif // NTONLYBUILD
|
||
|
||
if( g_hLoadedMutex )
|
||
CloseHandle( g_hLoadedMutex );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
#ifdef _DEBUG
|
||
|
||
void DisplayLoadUnloadString( LPCTSTR pszAction )
|
||
{
|
||
TCHAR szModName[255];
|
||
TCHAR szVer[1024] = TEXT("???");
|
||
|
||
// Output to debug terminal - oleacc was attached to process x,
|
||
// show which oleacc version is running, what directory it was
|
||
// loaded from, etc.
|
||
|
||
// NULL -> get application's name (not oleacc)
|
||
MyGetModuleFileName( NULL, szModName, ARRAYSIZE( szModName ) );
|
||
DBPRINTF( TEXT("'%s' is %s "),szModName, pszAction );
|
||
|
||
MyGetModuleFileName( g_hinstDll, szModName, ARRAYSIZE( szModName ) );
|
||
|
||
DWORD dwUseless;
|
||
DWORD dwSize = GetFileVersionInfoSize( szModName, & dwUseless );
|
||
if( dwSize )
|
||
{
|
||
LPVOID lpVersionData = LocalAlloc( LPTR, (UINT) dwSize );
|
||
if( GetFileVersionInfo( szModName, dwUseless, dwSize, lpVersionData ) )
|
||
{
|
||
VS_FIXEDFILEINFO * lpVersionInfo;
|
||
DWORD dwBytes;
|
||
VerQueryValue( lpVersionData, TEXT("\\"), (void**)&lpVersionInfo, (UINT*)&dwBytes );
|
||
wsprintf( szVer, TEXT("%d.%d.%d.%d"), HIWORD( lpVersionInfo->dwFileVersionMS ),
|
||
LOWORD( lpVersionInfo->dwFileVersionMS ),
|
||
HIWORD( lpVersionInfo->dwFileVersionLS ),
|
||
LOWORD( lpVersionInfo->dwFileVersionLS ) );
|
||
}
|
||
LocalFree( (HLOCAL) lpVersionData );
|
||
}
|
||
|
||
DBPRINTF( TEXT("%s version %s\r\n"), szModName, szVer );
|
||
}
|
||
|
||
#endif // _DEBUG
|