I. Dynamic call:
Early binding means that the type has been determined during the compilation period. After compilationCodeExecution efficiency is very high; late binding determines the type only at runtime. Late binding requires determining the type at runtime, so the efficiency is relatively low, but it brings great flexibility. I think dynamic calling is a specific form of late binding, that is, calling the functions in the DLL without the header file and Lib.
Currently, the plug-in system software developed based on ATL mostly adopts the former, that is, the. h and _ I. c files compiled by IDL. This method is sometimes rigid and lacks dynamic mechanisms. In fact, any of the technologies described below can be used to construct your own plug-in system and can be designed flexibly.
The following are the three dynamic call methods I know (the example is based on vs2005 ):
1. dll function call: (obtain the function address)
HypothesisDllfunc. dllThere is a function: int add (int A, int B). The procedure for calling the client is as follows:
// Load dynamic library
Hmodule = Loadlibrary (_ T ( " Dllfunc. dll " ));
If (Hmodule)
{
// Get function address
Fnadd = (Lpfunc) getprocaddress (hmodule, " Add " );
If (Fnadd)
{
// Call a function
Iret = Fnadd ( 2 , 4 );
Printf ( " Result is % d " , Iret );
}
// Release a dynamic library
Freelibrary (hmodule );
Hmodule = NULL;
}
2. COM component function call (invoke of idispatch)
Assume that there is a component whose progid is "atlfunc. mymath.1". The attributes and interface methods are as follows:
Interface Imymath: idispatch {
[Propget, ID (1), Helpstring ("Property result")] Hresult result ([Out, Retval] Long*Pval );
[Propput, ID (1), Helpstring ("Property result")] Hresult result ([In] Long newval );
[ID (2), Helpstring ("Method Add")] Hresult add (long a, long B ,[Out, Retval] Long*PC );
} ;
The procedure for calling a client is as follows:
// Initialize the com Library
Coinitialize (null );
// Create component based on progid
HR = Pimymath. cocreateinstance (_ T ( " Atlfunc. mymath.1 " ));
If (Succeeded (HR ))
{
// Obtain the dispid of the add function.
HR = Pimymath -> Getidsofnames (iid_null, & Szmember, 1 , Locale_user_default, & Dispid );
If (HR = S_ OK)
{
Pvarsin = New Ccomvariant [ 2 ];
Pvarsin [ 0 ]. Vt = Vt_i4;
Pvarsin [ 0 ]. Intval = 2 ;
Pvarsin [ 1 ]. Vt = Vt_i4;
Pvarsin [ 1 ]. Intval = 4 ;
Dispparams dispparam = {Pvarsin, null,2,0} ;
// Call the Add function
Variantinit ( & Vtout );
HR = Pimymath -> Invoke (dispid, iid_null, locale_user_default, dispatch_method, & Dispparam, & Vtout, null, null );
If (Succeeded (HR ))
{
Printf ("% D", Vtout. intval );
}
Variantclear ( & Vtout );
Delete [] pvarsin;
Pvarsin = NULL;
}
// In fact, if we know the interface method or the dispid of the attribute, we can directly call it through dispid.
Variantinit ( & Vtout );
Dispparams dispparam = {Null, null,0,0} ;
HR = Pimymath -> Invoke ( 1 , Iid_null, locale_user_default, dispatch_propertyget, & Dispparam, & Vtout, null, null );
If (Succeeded (HR ))
{
Printf ("% D", Vtout. intval );
}
Variantclear ( & Vtout );
}
// Release the COM component before couninitialize. Otherwise, the component may be released after the com library is uninstalled.
Pimymath = NULL;
// Release com Library
Couninitialize ();
3... NET Component function call: (reflection technology)
Assume a CLR class libraryProgramThere is a class mymath in the set that contains the int add (int A, int B) method. The call steps on the client are as follows:
Try
{
// Load assembly
Passembly = Assembly: load (L " Clrfunc " );
// Obtains the clrfunc. mymath type in a dataset.
Ptype = Passembly -> GetType (L " Clrfunc. mymath " , True , True );
// Obtain method information
PMI = Ptype -> Getmethod (L " Add " );
// Create a clrfunc. mymath instance
Pobject = Activator: createinstance (ptype );
P [ 0 ] = 2 ;
P [ 1 ] = 4 ;
// Call Method
Iret = Safe_cast < Int32 ^> (PMI -> Invoke (pobject, p ));
System: Console: writeline (iret );
}
Catch (Exception ^ Exp)
{
System: Console: writeline (exp->Message );
}
The so-called plug-in technology only specifies a set of interfaces on the main program. All the load modules that follow the interfaces are plug-ins. The main program can use the above method to load any DLL and call the method function. As long as the function is satisfied, the plug-in system is no longer limited to the COM interface level, A plug-in can be implemented in the above three forms.
Ii. Other basic methods:
Void cuse1dlg: onbnclickedbutton1 ()
{
: Coinitialize (null );
Iunknown * punk = NULL;
Ifun * pfun = NULL;
Hresult hr;
Try
{
HR =: cocreateinstance (
Clsid_fun,
Null,
Clsctx_inproc_server, // load in the way of In-process component DLL
Iid_iunknown, // you want to obtain the iunknown interface pointer
(Lpvoid *) & punk );
If (failed (HR) Throw (_ T ("not registered? "));
HR = punk-> QueryInterface (// obtain other interface pointers from iunknown
Iid_ifun, // you want to obtain the ifun interface pointer
(Lpvoid *) & pfun );
If (failed (HR) Throw (_ T ("actually no interface? "));
Long nsum;
HR = pfun-> Add (1, 2, & nsum); // ifun: add ()
If (succeeded (HR ))
{
Cstring smsg;
Smsg. Format (_ T ("1 + 2 = % d"), nsum );
Afxmessagebox (smsg );
}
BSTR S1 =: sysallocstring (L "hello ");
BSTR S2 =: sysallocstring (L "world ");
BSTR S3 = NULL;
HR = pfun-> CAT (S1, S2, & S3); // ifun: CAT ()
If (succeeded (HR ))
{
Cstring smsg (S3 );
Afxmessagebox (smsg );
}
// Ifun: CAT () The last parameter is the [out] direction attribute, so the caller needs to release
If (S3): sysfreestring (S3 );
}
Catch (lpctstr lperr)
{
Afxmessagebox (lperr );
}
If (punk) punk-> release ();
If (pfun) pfun-> release ();
: Couninitialize ();
}
// Contains the header file required to use ccombstr
# Include <atlbase. h>
Void cuse1dlg: onbnclickedbutton2 ()
{
: Coinitialize (null );
Ifun * pfun = NULL;
Hresult hr;
Try
{
HR =: cocreateinstance (
Clsid_fun,
Null,
Clsctx_inproc_server,
Iid_ifun, // get the ifun interface pointer directly without passing through iunknown
(Lpvoid *) & pfun );
If (failed (HR) Throw (_ T ("not registered, right? Or no interface? "));
Long nsum;
HR = pfun-> Add (1, 2, & nsum );
If (succeeded (HR ))
{
Cstring smsg;
Smsg. Format (_ T ("1 + 2 = % d"), nsum );
Afxmessagebox (smsg );
}
Ccombstr S1 ("hello"); // no longer using APIs to operate BSTR
Ccombstr S2 ("world"); // It is relatively simple to use ccombstr, and
Ccombstr S3; // The biggest benefit is that we don't have to release it ourselves.
HR = pfun-> CAT (S1, S2, & S3 );
If (succeeded (HR ))
{
Cstring smsg (S3 );
Afxmessagebox (smsg );
}
}
Catch (lpctstr lperr)
{
Afxmessagebox (lperr );
}
If (pfun) pfun-> release ();
: Couninitialize ();
}
2
Void cuse2dlg: onbnclickedbutton3 () // ccomptr example
{
// The COM Initialization is called using the afxoleinit () function and placed in cuse2app: initinstance.
Ccomptr <iunknown> spunk; // defines the iunknown smart pointer
Ccomptr <ifun> spfun; // defines the ifun smart pointer
Hresult hr;
Try
{
// You can use CLSID to start the component or progid
HR = spunk. cocreateinstance (clsid_fun );
If (failed (HR) Throw (_ T ("no registered component? "));
HR = spunk. QueryInterface (& spfun );
If (failed (HR) Throw (_ T ("actually no interface? "));
Long nsum;
HR = spfun-> Add (1, 2, & nsum );
If (succeeded (HR ))
{
Cstring smsg;
Smsg. Format (_ T ("1 + 2 = % d"), nsum );
Afxmessagebox (smsg );
}
Ccombstr S1 ("hello"), S2 ("world"), S3;
HR = spfun-> CAT (S1, S2, & S3 );
If (succeeded (HR ))
{
Cstring smsg (S3 );
Afxmessagebox (smsg );
}
}
Catch (lpctstr lperr)
{
Afxmessagebox (lperr );
}
// The biggest benefit of Smart interface pointers is that we do not have to release them.
}
Void cuse2dlg: onbnclickedbutton4 () // ccomqiptr example
{
Ccomptr <iunknown> spunk; // smart pointer iunknown
Ccomqiptr <ifun> spfun; // smart pointer ifun
Hresult hr;
Try
{
// Use progid to start the component
HR = spunk. cocreateinstance (L "simple2.fun. 1 ");
If (failed (HR) Throw (_ T ("not registered? "));
Spfun = spunk; // ccomqiptr will automatically call QueryInterface
If (! Spfun) Throw (_ T ("is there no interface? "); // Whether the operation is successful or not, the non-null value can be determined.
Long nsum;
HR = spfun-> Add (1, 2, & nsum );
If (succeeded (HR ))
{
Cstring smsg;
Smsg. Format (_ T ("1 + 2 = % d"), nsum );
Afxmessagebox (smsg );
}
Ccombstr S1 ("hello"), S2 ("world"), S3;
HR = spfun-> CAT (S1, S2, & S3 );
If (succeeded (HR ))
{
Cstring smsg (S3 );
Afxmessagebox (smsg );
}
}
Catch (lpctstr lperr)
{
Afxmessagebox (lperr );
}
}
Void cuse2dlg: onbnclickedbutton5 () // no longer passes iunknown
{
Ccomqiptr <ifun, & iid_ifun> spfun; // defines the ifun smart pointer.
Hresult hr;
Try
{
HR = spfun. cocreateinstance (L "simple2.fun. 1 ");
If (failed (HR) Throw (_ T ("no component registered or interface found "));
Long nsum;
HR = spfun-> Add (1, 2, & nsum );
If (succeeded (HR ))
{
Cstring smsg;
Smsg. Format (_ T ("1 + 2 = % d"), nsum );
Afxmessagebox (smsg );
}
Ccombstr S1 ("hello"), S2 ("world"), S3;
HR = spfun-> CAT (S1, S2, & S3 );
If (succeeded (HR ))
{
Cstring smsg (S3 );
Afxmessagebox (smsg );
}
}
Catch (lpctstr lperr)
{
Afxmessagebox (lperr );
}
}
3
Void cuse3dlg: onbnclickedbutton6 () // release smart pointer
{
//: Coinitialize (null); // If COM Initialization is performed here, pay attention to the release of smart pointers.
Ccomqiptr <ifun, & iid_ifun> spfun;
Hresult hR = spfun. cocreateinstance (clsid_fun );
Assert (succeeded (HR ));
// For the sake of simplicity, if is no longer used to judge hresult. Ifun: add () is not called either.
Ccombstr S1 ("hello"), S2 ("world"), S3;
HR = spfun-> CAT (S1, S2, & S3 );
Assert (succeeded (HR ));
Cstring smsg (S3 );
Afxmessagebox (smsg );
// Spfun-> release (); // a big mistake !!!
// Spfun. Release (); // Positive Solution
//: Couninitialize ();
}
4
Void cuse4dlg: onbnclickedbutton7 () // # Use of Import
{
/*************************************** *******************
1. Use afxoleinit () in cuse4app: initinstance () for initialization
2. Open the stdafx. h file, insert # import, and compile
Generate smart pointer packaging for. tlh and. tlh.
3. # using no_namespace for Import means no namespace is used
4. The smart pointer is packaged in the form of ixxxptr. xxx indicates the interface name.
**************************************** *******************/
Ifunptr spfun;
Hresult hR = spfun. createinstance (L "simple2.fun. 1"); // use progid
// Hresult hR = spfun. createinstance (_ uuidof (fun); // use CLSID
Assert (succeeded (HR ));
Try
{
Long nsum = spfun-> Add (1, 2 );
Cstring smsg;
Smsg. Format (_ T ("1 + 2 = % d"), nsum );
Afxmessagebox (smsg );
_ Bstr_t scat = spfun-> CAT (_ T ("hello"), _ T ("world "));
Afxmessagebox (SCAT );
}
Catch (_ com_error & E)
{
// Detailed error information can be obtained here
// Details about the isupporterrorinfo interface in the future
// E. Description ();
// E. errormessage ();
// E. errorinfo ();
//......
E; // because E is not used, add this line to cancel the compilation warning.
Afxmessagebox (_ T ("error "));
}
}
5
Void cuse5dlg: onbnclickedbutton8 ()
{
// Because # import in stdafx. h does not use no_namespace, The namespace must be used.
// The namespace is simple2lib, which is specified by the component IDL file library.
Try
{
// This time, the component is started using the constructor of the smart pointer, which is easy to write.
// But it also has disadvantages, because if it fails, you do not know the cause of the error.
// Simple2lib: ifunptr spfun (L "simple2.fun. 1"); // progid
Simple2lib: ifunptr spfun (_ uuidof (simple2lib: Fun); // CLSID Method
Long nsum = spfun-> Add (1, 2 );
Cstring smsg;
Smsg. Format (_ T ("1 + 2 = % d"), nsum );
Afxmessagebox (smsg );
_ Bstr_t scat = spfun-> CAT (_ T ("hello"), _ T ("world "));
Afxmessagebox (SCAT );
}
Catch (_ com_error & E)
{
E;
Afxmessagebox (_ T ("error "));
}
}