Introduction
After porting one of my old VC 6.0 projects to VC 7.0, I found that all the
executable files were dependant on the library oleacc.dll, which is the core file
of Microsoft Active Accessibility (MSAA). Because MSAA is released in 1997, some
old OSs - Windows 95, Windows NT and Windows 98 (without Active Accessibility
Options installed) do not support it normally. So my program failed to run on these
platforms! This has caused me quite a headache.
I checked the MFC source code and found that only these 3 procedures in oleacc.dll
were called by MFC 7.0 in some member functions of class CWnd:
-
AccessibleObjectFromWindow(HWND hwnd, DWORD dwId, REFIID riid, void **ppvObject)
-
CreateStdAccessibleObject(HWND hwnd, LONG idObject, REFIID riid, void** ppvObject)
-
LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN punk)
After did some simple researches, I found the solution:
- Remove the dependence to oleacc.lib from my project
Select "Properties..." from the "Project" menu. In the configuration tree of
the dialog, select catalog "Linker" and click "Input". Click "Ignore
Specific Library" and enter "oleacc.lib".
- Write my own proxy functions
All of these functions have the same name to the corresponding MSAA APIs. In
these functions, I dynamically load oldacc.dll, and then call the
corresponding procedures in oleacc.dll if it is loaded successfully. I
encapsulated these function to 2 files: oleaccproxy.h and oleaccproxy.cpp and
then added the them to my project. The source code for the proxy is shown
below.
- Rebuild the project
After rebuilt the project, the output executable file does not depend on
oleacc.dll and if MSAA is present on target platform, the MSAA features will
still function properly.
Source Code
The header file
#pragma once
typedef LRESULT (_stdcall *pfnAccessibleObjectFromWindow)(HWND hwnd, DWORD dwId,
REFIID riid, void **ppvObject);
typedef LRESULT (_stdcall *pfnCreateStdAccessibleObject)(HWND hwnd, LONG idObject,
REFIID riid, void** ppvObject);
typedef LRESULT (_stdcall *pfnLresultFromObject)(REFIID riid, WPARAM wParam,
LPUNKNOWN punk);
class COleaccProxy
{
public:
COleaccProxy(void);
virtual ~COleaccProxy(void);
private:
static HMODULE m_hModule;
static BOOL m_bFailed;
public:
static void Init(void);
static pfnAccessibleObjectFromWindow m_pfnAccessibleObjectFromWindow;
static pfnCreateStdAccessibleObject m_pfnCreateStdAccessibleObject;
static pfnLresultFromObject m_pfnLresultFromObject;
};
The implementation file
#include "StdAfx.h"
#include "oleaccproxy.h"
extern "C" LRESULT _stdcall AccessibleObjectFromWindow(HWND hwnd, DWORD dwId,
REFIID riid, void **ppvObject)
{
COleaccProxy::Init();
return COleaccProxy::m_pfnAccessibleObjectFromWindow ?
COleaccProxy::m_pfnAccessibleObjectFromWindow(hwnd, dwId, riid, ppvObject) : 0;
}
extern "C" LRESULT _stdcall CreateStdAccessibleObject(HWND hwnd, LONG idObject,
REFIID riid, void** ppvObject)
{
COleaccProxy::Init();
return COleaccProxy::m_pfnCreateStdAccessibleObject ?
COleaccProxy::m_pfnCreateStdAccessibleObject(hwnd, idObject, riid, ppvObject) : 0;
}
extern "C" LRESULT _stdcall LresultFromObject(REFIID riid, WPARAM wParam, LPUNKNOWN punk)
{
COleaccProxy::Init();
return COleaccProxy::m_pfnLresultFromObject ?
COleaccProxy::m_pfnLresultFromObject(riid, wParam, punk) : 0;
}
HMODULE COleaccProxy::m_hModule = NULL;
BOOL COleaccProxy::m_bFailed = FALSE;
pfnAccessibleObjectFromWindow COleaccProxy::m_pfnAccessibleObjectFromWindow = NULL;
pfnCreateStdAccessibleObject COleaccProxy::m_pfnCreateStdAccessibleObject = NULL;
pfnLresultFromObject COleaccProxy::m_pfnLresultFromObject = NULL;
COleaccProxy::COleaccProxy(void)
{
}
COleaccProxy::~COleaccProxy(void)
{
}
void COleaccProxy::Init(void)
{
if (!m_hModule && !m_bFailed)
{
m_hModule = ::LoadLibrary(_T("oleacc.dll"));
if (!m_hModule)
{
m_bFailed = TRUE;
return;
}
m_pfnAccessibleObjectFromWindow
= (pfnAccessibleObjectFromWindow)::GetProcAddress(m_hModule,
_T("AccessibleObjectFromWindow"));
m_pfnCreateStdAccessibleObject
= (pfnCreateStdAccessibleObject)::GetProcAddress(m_hModule,
_T("CreateStdAccessibleObject"));
m_pfnLresultFromObject = (pfnLresultFromObject)::GetProcAddress(m_hModule,
_T("LresultFromObject"));
}
}