ATL编写的控件中动态调用加载dll文件,并调用函数,动态加载的好处主要是脱离依赖关系。
1. clientnodetool.dll文件中的接口定义形式为:
extern "C" BOOL CLIENTNODETOOL_API CreatePlayer()
{
}
extern "C" bool CLIENTNODETOOL_API SetSrcID(int nID, LPCTSTR szUserClientPath)
{
}
注意:这里的"C"必须是大写的,不然就会出错哦
其中#define CLIENTNODETOOL_API __declspec(dllexport)
那么在此dll中就有此两个输出接口。
假设clientnodetool依赖于socket.dll,socket.dll依赖于natsock.dll,下面的使用时要注意这几个库的加载。
2.AtlVideo.dll中使用clientnodetool.dll库中的函数接口:
<1>动态加载库
::LoadLibraryA(strRunPath + "//natsockd.dll");
::LoadLibraryA(strRunPath + "//socket.dll");
HINSTANCE ToolDLLInst = ::LoadLibraryA(strRunPath + "//clientnodetool.dll");
按这个顺序加载库,这里可以用depends查看dll所依赖的库,一定要加载完全,否者返回的ToolDLLInst的值为空(偶不够细心,在此受挫过)。
<2>定义接口,获取接口指针
//创建LocalPlayer对象的接口
BOOL (__stdcall * FunCreatePlayer)();
//设置视频源的接口
typedef bool (FAR __cdecl FunSetSrcID)(int nID, LPCTSTR szUserClientPath);
FunSetSrcID* g_fun = NULL;
此处注意:由于DLL中TEST的定义为C语言调用规范,因此TEST前一定要用__cdecl,而VC中常用的__stdcall是PASCAL调用规范,不可以的。一定要注意,偶
在此耽误过不少时间。
如果<1>中toolDllInst不为空
FunCreatePlayer = (BOOL(__stdcall*)())GetProcAddress(ToolDLLInst, "CreatePlayer");
g_fun = (FunSetSrcID*)GetProcAddress(ToolDLLInst, "SetSrcID");
不出错的话会有返回值。
注意:此处出错可能是GetProcAddress的第二个参数不对,上文中的1.中如果不声明extern "C",那么此处"CreatePlayer"可能会是"?CreatePlayer@.."什
么的,那是c++中的函数重载的一些原因导致的。可以用depends工具查看接口的描述。
3.使用接口函数
//创建LocalPlayer对象
if((*FunCreatePlayer) != NULL)
{
BOOL bres = (*FunCreatePlayer)();
}
//设置视频源
if(g_fun != NULL)
{
g_fun(nVideoID, strRunPath);
}
4.
使用完后:FreeLibrary(ToolDLLInst);