windows8内置的flash播放控件,因为对Activex的支持不佳,很多基于flash Activex的软件无法正常运行。我们不可能要求用户安装某个版本的flash播放器,最好的方法就是无缝加载我们指定的ocx控件。
所贴代码仅限32位程序,64位程序修改钩子实现代码后应该也能用。适用于MFC程序,只需要在现有代码里增加少许代码即可。
1.安装适用版本的flash控件,把Windows\System32\Macromed\Flash\*.ocx拷贝出来,改名Flash32.ocx,和我们的主程序放一起。
2.在App类的实现cpp里添加两个全局函数,代码如下:
//实现加载我们指定的OCX文件。
HRESULT GetFlashObject(REFCLSID clsid, LPUNKNOWN pUnkOuter,
DWORD dwClsCtx, REFIID iid, LPVOID* ppv, BSTR& bstrLicKey)
{
HRESULT hr;
static HMODULE hOcx = NULL;
const TCHAR* pOcxName = _T("Flash32.ocx");
if(!hOcx)
{
TCHAR szBuffer[_MAX_PATH];
::GetModuleFileName(NULL, szBuffer, _MAX_PATH);
TCHAR* pExeName = _tcsrchr(szBuffer, _T('\\'));
*++pExeName = 0;
_tcscat(pExeName, pOcxName);
hOcx = ::LoadLibrary(szBuffer);
}
typedef HRESULT (_stdcall* DllGetClassObjectPtr)(REFCLSID, REFIID, LPVOID);
static DllGetClassObjectPtr pDllGetClassObject = NULL;
if(!pDllGetClassObject && hOcx)
{
pDllGetClassObject = (DllGetClassObjectPtr)::GetProcAddress(hOcx, "DllGetClassObject");
}
if(!pDllGetClassObject)
{
return S_FALSE;
}
if (::SysStringLen(bstrLicKey) == 0)
{
LPCLASSFACTORY pClassFactory = NULL;
if (SUCCEEDED(hr = pDllGetClassObject(clsid, IID_IClassFactory, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstance(pUnkOuter, iid, ppv);
pClassFactory->Release();
}
}
else
{
LPCLASSFACTORY2 pClassFactory = NULL;
if (SUCCEEDED(hr = pDllGetClassObject(clsid, IID_IClassFactory2, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstanceLic(pUnkOuter, NULL, iid,
bstrLicKey, ppv);
pClassFactory->Release();
}
}
return hr;
}
//实现加载Activex时的分发动作。
AFX_STATIC HRESULT AFXAPI MyCoCreateInstanceLic(REFCLSID clsid, LPUNKNOWN pUnkOuter,
DWORD dwClsCtx, REFIID iid, LPVOID* ppv, BSTR bstrLicKey)
{
HRESULT hr;
static CLSID const swfid
= { 0xD27CDB6E, 0xAE6D, 0x11CF, { 0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0 } };
if(swfid == clsid)
{
return GetFlashObject(clsid, pUnkOuter, dwClsCtx, iid, ppv, bstrLicKey);
}
if (::SysStringLen(bstrLicKey) == 0)
{
LPCLASSFACTORY pClassFactory = NULL;
if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
IID_IClassFactory, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstance(pUnkOuter, iid, ppv);
pClassFactory->Release();
}
}
else
{
LPCLASSFACTORY2 pClassFactory = NULL;
if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
IID_IClassFactory2, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstanceLic(pUnkOuter, NULL, iid,
bstrLicKey, ppv);
pClassFactory->Release();
}
}
return hr;
}
在App类的构造函数里添加如下代码:
//挂钩_AfxCoCreateInstanceLic,不同VS版本,实现的流程可能不同,也可能不是_AfxCoCreateInstanceLic。
extern HRESULT AFXAPI _AfxCoCreateInstanceLic(REFCLSID clsid, LPUNKNOWN pUnkOuter,
DWORD dwClsCtx, REFIID iid, LPVOID* ppv, BSTR bstrLicKey);
ASSERT(sizeof(long) == 4);
long lFunOld = (long)_AfxCoCreateInstanceLic;
long lFunNew = (long)MyCoCreateInstanceLic;
BYTE nCodes[5] = {0xE9, 0};
long* pAddress = (long*)&nCodes[1];
*pAddress = lFunNew - lFunOld - 5;
SIZE_T nSize = sizeof(nCodes);
DWORD dwProtect = PAGE_EXECUTE_READWRITE;
VirtualProtect((LPVOID)lFunOld, nSize, dwProtect, &dwProtect);
WriteProcessMemory(GetCurrentProcess(), (LPVOID)lFunOld, nCodes, nSize, &nSize);
VirtualProtect((LPVOID)lFunOld, nSize, dwProtect, &dwProtect);
从原理上讲,该方法应该适用于所有Activex的自定义加载。