今天在移植一个游戏的客户端网络通信库, 原始代码是VC6.0 ,在vs2003 平台上做了一次移植,然后我又将其移植到vs2010, 结果发现编译一切正常,但是进入游戏的发现Dll实例对象异常。 附加客户端主程序,调试Dll 发现问题出在这里。
STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID* ppv)
{
IUnknown* pIFactory = NULL;
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
if (CLSID_SC_BASENETWORK_DLL == rclsid)
{
hr = E_OUTOFMEMORY;
pIFactory = new CSC_BaseNetworkFactory;
if (pIFactory)
{
hr = pIFactory->QueryInterface(riid,ppv);
if (FAILED(hr))
{
delete pIFactory;
pIFactory = NULL;
}
}
}
return hr;
}
然后一看是类 CSC_BaseNetworkFactory 继承自 IClassFactory ,ISC_BaseNetwork接口继承自 IUnknown, 问题就出在这里,VS高版本对接口进行了修改,这里公布3种结果方法。
- 使用 CoCreateInstance 到处Dll 接口实例指针在客户端中调用。此方法包含在VC7.0 include 库 ObjBase.h 中,查看就可知调用方法。
__checkReturn WINOLEAPI CoCreateInstance(__in REFCLSID rclsid,
__in_opt LPUNKNOWN pUnkOuter,
__in DWORD dwClsContext,
__in REFIID riid,
__deref_out LPVOID FAR* ppv);
- 不通过工厂模式接口,直接返回实例对象,因为Dll在载入的过程中已经在内存中映射了对象。
STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID* ppv)
{
CSC_BaseNetwork* pFactory = NULL;
HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
if (CLSID_SC_BASENETWORK_DLL == rclsid)
{
hr = E_OUTOFMEMORY;
pFactory = new CSC_BaseNetwork;
if (pFactory)
{
hr = pFactory->QueryInterface(riid,ppv);
if (FAILED(hr))
{
delete pFactory;
pFactory = NULL;
}
}
}
return hr;
}
- 可以使用接口注入,这也是IOC和DI思想,控制反转和依赖注入的使用方式。
STDAPI DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID* ppv)
{
CSC_BaseNetworkFactory pFactory;
IUnknown* pIFactory = NULL;
return pFactory.CreateInstance(pIFactory,riid,ppv);
}
以上三种方式都能结果,VC6.0/vs2003 移植到vs2010以上IDE 遇到的Dll 获取实例化接口出现异常的解决方法,推荐使用1和3,第二种不建议使用,如果出现其他游戏也导入了同样的CLSID的Dll, 如果Dll作为共享DLL方式使用的话, 可能数据包会异常。建议使用第1种和第3种方式。
|