ActiveX Dll 호출을 등록하지 않음

6831 단어 ActiveX
모든 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의 도움을 빌려 해결하는 것이다.vb 호출을 위해 vc로 dll을 씁니다. 주요 코드는 다음과 같습니다.
//CrCom.cpp : Defines the entry point for the DLL application.//
#include "stdafx.h"#include #include
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 CrComObjLib'CCrCom.dll'( ByVal lpDll As String, ByVal lpDll As String, ByVal lpv As Any) As Long Prival Prival lpv As AAAs AAs As As As As Long Plllpv As As An An As As Annnllllllll'As As String(ByVyVy Val Llpv As As As As Strity String String, Byy Byy Byy As v 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를 좀 빌려 쓰는 것이 좋을 것 같아요. 이렇게 하면 간편한 말이 많아요.

좋은 웹페이지 즐겨찾기