每个activex dll都应该有个dllgetclassobject函数,利用该函数就可以直接创建所需的com对象,而不需要通过注册表(或者注册),
stdapi dllgetclassobject(
refclsid rclsid, //clsid for the class object
refiid riid, //reference to the identifier of the interface
// that communicates with the class object
lpvoid * ppv //address of output variable that receives the
// interface pointer requested in riid
);
这里必须知道两样东西,一个rclsid,就是需要创建的com对象的clsid,另一个是 riid,该对象的一个接口的 id.
然而,调用dllgetclassobject,并不能直接创建所需要的对象,但可以得到对应的 iclassfactory,再由 iclassfactory.createinstance得到所需的对象.
vb实现代码大概如下:
需要用到一个库,http://www.mvps.org/emorcillo/download/vb6/tl_ole.zip
(引用页,http://www.mvps.org/emorcillo/en/code/vb6/wbframe.shtml)
另外,也将那个activex dll引用进工程,这里,并不是需要注册它,而是为了方便使用它的方法,因为并没有使用new来创建对象,
程序编译后即使不注册那个dll文件都能够正常使用.
option explicit
假设activex dll 的文件名为dlldemo.dll,并且处于工程同一目录
private declare function dllgetclassobject lib “dlldemo.dll” ( _
rclsid as uuid, riid as uuid, byref ppv as any) as long
class id
private const clsstr_obj as string = “{c1a334ba-d1a4-48d0-98d5-47fe934961df}”
接口id
private const iidstr_ins as string = “{231114d5-e046-4dae-b192-0ab49d493a85}”
iclassfactory id
private const striid_iclassfactory as string = “{00000001-0000-0000-c000-000000000046}”
private clsid_obj as uuid
private iid_ins as uuid
private iid_iunknow as uuid
private iid_iclassfactory as uuid
private sub command1_click()
dim tobj as olelib.iunknown
dim tobj2 as dlldemo.idemo
dim tfac as olelib.iclassfactory
call dllgetclassobject(clsid_obj, iid_iclassfactory, tfac)
tfac.createinstance nothing, iid_iunknow, tobj
set tfac = nothing
set tobj2 = tobj
调用idemo.test测试所创建的对象
tobj2.test
end sub
private sub form_load()
将string转换为 uuid
clsidfromstring clsstr_obj, clsid_obj
clsidfromstring iidstr_ins, iid_ins
clsidfromstring iidstr_iunknown, iid_iunknow
clsidfromstring striid_iclassfactory, iid_iclassfactory
end sub
至此,问题似乎已经解决了,只要为不同的activex dll编写对应的dllgetclassobject函数就可以了,只是当文件名未定时就比较难办了,例如编写插件时.
解决办法是用loadlibrary动态的调用各个dll上的dllgetclassobject.可惜的是vb不支持函数指针.我的办法是借助vc来解决.用vc写dll供vb调用,主要代码如下:
// crcom.cpp : defines the entry point for the dll application.
//
#include “stdafx.h”
#include <unknwn.h>
#include <objbase.h>
typedef int (callback *myproc)(refclsid,refiid,lpvoid *);
bool apientry dllmain( handle hmodule,
dword ul_reason_for_call,
lpvoid lpreserved
)
{
return true;
}
// if(riid==null)riid=&iid_iunknown
int _stdcall crcomobj(
lpcstr lpdll,
clsid *rclsid,
iid *riid,
lpvoid * ppv)
{
hinstance hinstlib;
myproc procadd;
bool ffreeresult, fruntimelinksuccess = false;
int rtn=0;
// get a handle to the dll module.
hinstlib = loadlibrary(lpdll);
// if the handle is valid, try to get the function address.
if (hinstlib != null)
{
procadd =(myproc)getprocaddress(hinstlib, “dllgetclassobject”);
// if the function address is valid, call the function.
if (fruntimelinksuccess = (procadd != null))
{
if(rclsid==null)
{
freelibrary(hinstlib);
return 0;
}
if(riid==null)
riid=(iid *)&iid_iunknown;
iclassfactory *pif;
pif=null;
if(procadd(*rclsid,iid_iclassfactory,(void **)&pif)==s_ok && pif!=null)
{
if(pif->createinstance(null,*riid,ppv)==s_ok)
rtn=(int)hinstlib;
pif->release();
pif=null;
}
}
// free the dll module.
if(!rtn)ffreeresult = freelibrary(hinstlib);
}
return rtn;
}
// if strriid==null, use iid_iunknown;
int _stdcall crcomobj2(
lpcstr lpdll,
lpcstr strrclsid,
lpcstr strriid,
lpvoid * ppv )
{
hinstance hinstlib;
myproc procadd;
bool ffreeresult, fruntimelinksuccess = false;
int rtn=0;
// get a handle to the dll module.
hinstlib = loadlibrary(lpdll);
// if the handle is valid, try to get the function address.
if (hinstlib != null)
{
procadd =(myproc)getprocaddress(hinstlib, “dllgetclassobject”);
// if the function address is valid, call the function.
if (fruntimelinksuccess = (procadd != null))
{
clsid rclsid;
iid riid;
if(strrclsid==null)
{
freelibrary(hinstlib);
return 0;
}
clsidfromstring((lpolestr )strrclsid,&rclsid);
if(strriid!=null)
clsidfromstring((lpolestr )strriid,&riid);
else
riid=iid_iunknown;
iclassfactory *pif=null;
if(procadd(rclsid,iid_iclassfactory,(void **)&pif)==s_ok && pif!=null)
{
if(pif->createinstance(null,riid,ppv)==s_ok)
rtn=(int)hinstlib;
pif->release();
pif=null;
}
}
// free the dll module.
if(!rtn)ffreeresult = freelibrary(hinstlib);
}
return rtn;
}
在vb中的使用方法,crcomobj传递的是uuid,crcomobj2传递的是string,
函数声明
private declare function crcomobj lib “crcom.dll” ( _
byval lpdll as string, byval rclsid as long, byval riid as long, byref ppv as any) as long
private declare function crcomobj2 lib “crcom.dll” ( _
byval lpdll as string, byval strrclsid as long, byval strriid as long, byref ppv as any) as long
dim tobj as olelib.iunknown
dim tobj2 as dlldemo.idemo
hlib = crcomobj(app.path & “\dlldemo.dll”, varptr(clsid_obj), 0, tobj)
set tobj2 = tobj
tobj2.test
或者
hlib=crcomobj2(app.path & “\dlldemo.dll”, strptr(clsstr_obj), 0, tobj)
set tobj2 = tobj
tobj2.test
crcomobj与crcomobj2返回的是loadlibrary的返回值,必要的时候需要用freelibrary释放.
后记:
我的多页面浏览器le中,也实现了不注册调用activex dll,我是直接使用了一本书(advanced visual basic)的代码,代码颇长,似乎也挺复杂,原先使用的时候也不明所以然,后来终于搞清楚了,其原理是一样的,但是因为vb不支持函数指针,于是它花了很大力气去处理这个问题.相比而言,我觉得还是借用一下vc比较好,这样的话简捷的多.