COM (5) -- inherit from the idispatch Interface
(1) Objectives
This article uses a simple example to describe how to make our COM Object accessible to the scripting language.
(2) IDL files
To use COM components in the script language environment, the COM specification specifies that the COM to be used in the script language environment must implement the idispatch interface.
The itimebeijing interface is defined below. Note the differences between this file and our previous file:
Import "oaidl. IDL ";
Import "ocidl. IDL ";
[
UUID (30002489-29d8-4c48-9b1f-d6660a818e7b ),
Object,
Dual, // This identifier defines a dual Interface
Pointer_default (unique)
]
Interface itimebeijing: idispatch // It must be derived from the idispatch Interface
{
[ID (1)] hresult gethour ([out, retval] int * hour); // each function has an ID before calling
[ID (2)] hresult getminute ([out, retval] int * min );
[ID (3)] hresult getsecond ([out, retval] int * Sec );
};
[
UUID (8ae3c9ba-cee9-4d33-a4c1-db4fbfbb9a43 ),
Version (1.0 ),
]
Library timebeijinglib
{
Importlib ("stdole32.tlb ");
Importlib ("stdole2.tlb ");
[
UUID (ECE8BF15-11FB-45a4-90A1-1788DDAB31AC ),
]
Coclass timebeijingclass // com class
{
[Default] interface itimebeijing;
};
};
(3) create a com class timebeijingclass
Note the differences with the previous ones.
The class must implement three interfaces: iunknown, idispatch, and itimebeijing.
// Timebeijingclass. h: interface for the timebeijingclass.
//
//////////////////////////////////////// //////////////////////////////
# If! Defined (afx_timebeijingclass_hsf-e9800212_16e2_4be3_b646_420dc02f50ae1_encoded _)
# Define afx_timebeijingclass_hsf-e9800212_16e2_4be3_b646_420dc02f50ae1_encoded _
# If _ msc_ver> 1000
# Pragma once
# Endif // _ msc_ver> 1000
# Include "timebeijing. H"
Class timebeijingclass: Public itimebeijing
{
Public:
Timebeijingclass ();
~ Timebeijingclass ();
Public:
// Iunknown
Stdmethod (QueryInterface) (refiid riid, void ** GMM );
Stdmethod _ (ulong, addref )();
Stdmethod _ (ulong, release )();
// Idispatch
Stdmethod (gettypeinfocount) (uint * pit );
Stdmethod (gettypeinfo) (uint it, lcid, itypeinfo ** ppti );
Stdmethod (getidsofnames) (refiid riid,
Olechar ** pnames,
Uint nnames,
Lcid,
Dispid * pdispids );
Stdmethod (invoke) (dispid ID,
Refiid riid,
Lcid,
Word wflags,
Dispparams * PD,
Variant * pvarresult,
Raise info * PE,
Uint * Pu );
// Itimebeijing
Stdmethod (gethour) (int * hour );
Stdmethod (getminute) (int * min );
Stdmethod (getsecond) (int * Sec );
PRIVATE:
Long m_cref;
};
# Endif //! Defined (afx_timebeijingclass_hsf-e9800212_16e2_4be3_b646_420dc02f50ae1_encoded _)
// Timebeijingclass. cpp: Implementation of the timebeijingclass class.
//
//////////////////////////////////////// //////////////////////////////
# Include "timebeijingclass. H"
# Include "stdio. H"
# Include <time. h>
# Include "timebeijing_ I .c"
//////////////////////////////////////// //////////////////////////////
// Construction/destruction
//////////////////////////////////////// //////////////////////////////
Timebeijingclass: timebeijingclass ()
{
Printf ("timebeijingclass-constructor/N ");
M_cref = 0;
}
Timebeijingclass ::~ Timebeijingclass ()
{
Printf ("timebeijingclass-destructor/N ");
}
// Iunknown
Stdmethodimp timebeijingclass: QueryInterface (refiid riid, void ** GMM)
{
Printf ("timebeijingclass-QueryInterface/N ");
If (riid = iid_itimebeijing)
* GMM = static_cast <itimebeijing *> (this );
Else if (riid = iid_iunknown)
* GMM = static_cast <itimebeijing *> (this );
Else if (riid = iid_idispatch)
* GMM = static_cast <idispatch *> (this );
Else {
* PVS = 0;
Return e_nointerface;
}
Reinterpret_cast <iunknown *> (* GMM)-> addref ();
Return s_ OK;
}
Stdmethodimp _ (ulong) timebeijingclass: addref ()
{
Printf ("timebeijingclass-addref/N ");
Return ++ m_cref;
}
Stdmethodimp _ (ulong) timebeijingclass: release ()
{
Printf ("timebeijingclass-release/N ");
Ulong res = -- m_cref;
If (RES = 0)
Delete this;
Return res;
}
// Idispatch
// This function is important. Refer to the program and msdn to understand the parameter meaning.
Stdmethodimp timebeijingclass: invoke (dispid ID, refiid riid, lcid,
Word wflags, dispparams * PD,
Variant * pvarresult, interval info * PE, uint * Pu)
{
If (riid = iid_itimebeijing)
{
If (1 = ID)
Return gethour (& pvarresult-> intval );
Else if (2 = ID)
Return getminute (& pvarresult-> intval );
Else if (3 = ID)
Return getsecond (& pvarresult-> intval );
Else
Return e_fail;
}
Else
Return e_nointerface;
}
// The following interface functions are not implemented to simplify the program
Stdmethodimp timebeijingclass: getidsofnames (refiid riid, olechar ** pnames,
Uint nnames, lcid, dispid * pdispids)
{
Return e_notimpl;
}
Stdmethodimp timebeijingclass: gettypeinfo (uint it, lcid, itypeinfo ** ppti)
{
Return e_notimpl;
}
Stdmethodimp timebeijingclass: gettypeinfocount (uint * pit)
{
Return e_notimpl;
}
// Itimebeijing
Stdmethodimp timebeijingclass: gethour (int * hour)
{
Printf ("timebeijingclass-gethour/N ");
Time_t ltime;
Struct TM * today;
Time (& ltime );
Today = localtime (& ltime );
* Hour = today-> tm_hour;
Return s_ OK;
}
Stdmethodimp timebeijingclass: getminute (int * min)
{
Printf ("timebeijingclass-getminute/N ");
Time_t ltime;
Struct TM * today;
Time (& ltime );
Today = localtime (& ltime );
* Min = today-> tm_min;
Return s_ OK;
}
Stdmethodimp timebeijingclass: getsecond (int * Sec)
{
Printf ("timebeijingclass-getminute/N ");
Time_t ltime;
Struct TM * today;
Time (& ltime );
Today = localtime (& ltime );
* Sec = today-> tm_sec;
Return s_ OK;
}
(4) class factory files (minor changes: QueryInterface)
// Timebeijingclassfactory. h: interface for the timebeijingclassfactory class.
//
//////////////////////////////////////// //////////////////////////////
# If! Defined (partition _)
# Define DEFINE _
# If _ msc_ver> 1000
# Pragma once
# Endif // _ msc_ver> 1000
# Include <unknwn. h>
Class timebeijingclassfactory: Public iclassfactory
{
Public:
Timebeijingclassfactory ();
~ Timebeijingclassfactory ();
Public:
// Iunknow Method
Stdmethodimp QueryInterface (refiid, void **);
Stdmethodimp _ (ulong) addref ();
Stdmethodimp _ (ulong) release ();
// Iclassfactory Method
Stdmethodimp createinstance (iunknown *, refiid, void **);
Stdmethodimp lockserver (bool flock );
PRIVATE:
Long m_cref;
};
# Endif //! Defined (partition _)
// Timebeijingclassfactory. cpp: Implementation of the timebeijingclassfactory class.
//
//////////////////////////////////////// //////////////////////////////
# Include "timebeijingclassfactory. H"
# Include "stdio. H"
# Include "timebeijingclass. H"
//////////////////////////////////////// //////////////////////////////
// Construction/destruction
//////////////////////////////////////// //////////////////////////////
Extern long g_cobjectandlocks;
Timebeijingclassfactory: timebeijingclassfactory ()
{
Printf ("timebeijingclassfactory-constructor/N ");
M_cref = 0;
}
Timebeijingclassfactory ::~ Timebeijingclassfactory ()
{
Printf ("timebeijingclassfactory-destructor/N ");
}
Stdmethodimp _ (ulong) timebeijingclassfactory: addref (void)
{
Printf ("timebeijingclassfactory-addref/N ");
Return interlockedincrement (& m_cref );
}
Stdmethodimp _ (ulong) timebeijingclassfactory: release (void)
{
Printf ("timebeijingclassfactory-release/N ");
Return: interlockeddecrement (& m_cref );
}
Stdmethodimp timebeijingclassfactory: QueryInterface (refiid riid, void ** GMM)
{
Printf ("timebeijingclassfactory-QueryInterface/N ");
* GMM = NULL;
If (riid = iid_iunknown | riid = iid_iclassfactory | riid = iid_idispatch) // Changes here !!!
{
* GMM = static_cast <iclassfactory *> (this );
Reinterpret_cast <iunknown *> (* GMM)-> addref ();
Return s_ OK;
}
Else
Return (* GMM = 0), e_nointerface;
}
Stdmethodimp timebeijingclassfactory: createinstance (iunknown * punkouter, refiid riid, void ** bp)
{
Printf ("timebeijingclassfactory-createinstance/N ");
* GMM = NULL;
If (punkouter! = NULL)
Return class_e_noaggregation;
Timebeijingclass * ptimebeijingclass = new timebeijingclass;
If (ptimebeijingclass = NULL)
Return e_outofmemory;
Hresult hR = ptimebeijingclass-> QueryInterface (riid, GMM );
If (failed (HR ))
Delete ptimebeijingclass;
Return hr;
}
Stdmethodimp timebeijingclassfactory: lockserver (bool flock)
{
Printf ("timebeijingclassfactory-lockserver/N ");
If (flock)
: Interlockedincrement (& g_cobjectandlocks );
Else
: Interlockeddecrement (& g_cobjectandlocks );
Return noerror;
}
(5) server master file server. cpp (unchanged)
# Include <objbase. h>
# Include <initguid. h>
# Include "timebeijing. H"
# Include "timebeijing_ I .c"
# Include "timebeijingclassfactory. H"
Hinstance g_hinstdll; // DLL instance handle
Long g_cobjectandlocks;
Const char * g_regtable [] [3] = {// COM Object Registration
{"CLSID // {ECE8BF15-11FB-45a4-90A1-1788DDAB31AC }",
0,
"Timebeijing "},
{"CLSID // {ECE8BF15-11FB-45a4-90A1-1788DDAB31AC} // inprocserver32 ",
0,
(Const char *)-1 },
{"CLSID // {ECE8BF15-11FB-45a4-90A1-1788DDAB31AC} // progid", 0, "Justin. timebeijing.3 "},
{"Justin. timebeijing.3", 0, "timebeijing "},
{"Justin. timebeijing.3 // CLSID", 0, "{ECE8BF15-11FB-45a4-90A1-1788DDAB31AC }"},
};
// DLL entry
Bool apientry dllmain (handle hmodule,
DWORD ul_reason_for_call,
Lpvoid lpreserved
)
{
G_hinstdll = (hinstance) hmodule; // Save the handle
Return true;
}
Stdapi dllunregisterserver (void) // log out of the Registry
{
Hresult hR = s_ OK;
Char szfilename [max_path];
: Getmodulefilename (g_hinstdll, szfilename, max_path );
Int nentries = sizeof (g_regtable)/sizeof (* g_regtable );
For (INT I = 0; succeeded (HR) & I <nentries; I ++)
{
Const char * pszkeyname = g_regtable [I] [0];
Long err =: regdeletekey (hkey_classes_root, pszkeyname );
If (Err! = Error_success)
HR = s_false;
}
Return hr;
}
Stdapi dllregisterserver (void) // register the server
{
Hresult hR = s_ OK;
Char szfilename [max_path];
: Getmodulefilename (g_hinstdll, szfilename, max_path );
Int nentries = sizeof (g_regtable)/sizeof (* g_regtable );
For (INT I = 0; succeeded (HR) & I <nentries; I ++)
{
Const char * pszkeyname = g_regtable [I] [0];
Const char * pszvaluename = g_regtable [I] [1];
Const char * pszvalue = g_regtable [I] [2];
If (pszvalue = (const char *)-1)
{
Pszvalue = szfilename;
}
Hkey;
Long err =: regcreatekey (hkey_classes_root, pszkeyname, & hkey );
If (ERR = error_success)
{
Err =: regsetvalueex (hkey,
Pszvaluename,
0,
REG_SZ,
(Const byte *) pszvalue,
(Strlen (pszvalue) + 1 ));
: Regclosekey (hkey );
}
If (Err! = Error_success)
{
: Dllunregisterserver ();
HR = e_fail;
}
}
Return hr;
}
Stdapi dllgetclassobject (refclsid rclsid, refiid riid, void ** bp)
{
If (rclsid = clsid_timebeijingclass)
{
Timebeijingclassfactory * pfactory = new timebeijingclassfactory;
If (pfactory = NULL)
Return e_outofmemory;
Hresult hR = pfactory-> QueryInterface (riid, GMM );
Return hr;
}
Return class_e_classnotavailable;
}
Stdapi dllcanunloadnow (void)
{
Return (g_cobjectandlocks = 0)
? S_ OK: e_fail;
}
(6) def file (unchanged)
Library "timebeijing. dll"
Exports
Dllcanunloadnow @ 1 private
Dllgetclassobject @ 2 Private
Dllregisterserver @ 3 private
Dllunregisterserver @ 4 private
Compile the above file to get the server program.
Let's start the server: regsvr32 timebeijing. dll (Press ENTER)
(7) VC Client
The following is the test phase. First, we create a VC client for testing.
// Test. cpp: defines the entry point for the console application.
//
# Include "stdafx. H"
# Include "test. H"
# Include "../timebeijing_ I .c"
# Include "atlbase. H"
# Ifdef _ debug
# Define new debug_new
# UNDEF this_file
Static char this_file [] = _ file __;
# Endif
//////////////////////////////////////// /////////////////////////////////////
// The one and only Application Object
Cwinapp theapp;
Using namespace STD;
Int _ tmain (INT argc, tchar * argv [], tchar * envp [])
{
Cout <"initialize com runtime ......";
Hresult hR =: coinitialize (null );
If (succeeded (HR ))
Cout <"OK" <Endl;
Else
{
Cout <"failed" <Endl;
Couninitialize ();
System ("pause ");
Exit (1 );
}
Idispatch * pdispatch = NULL; // idispatch interface pointer
Cout <"Get idispatch interface pointer ......";
HR =: cocreateinstance (clsid_timebeijingclass,
Null,
Clsctx_inproc,
Iid_idispatch,
(Void **) & pdispatch );
If (succeeded (HR ))
Cout <"OK" <Endl;
Else
{
Cout <"failed" <Endl;
Couninitialize ();
System ("pause ");
Exit (1 );
}
Cout <"now use idispatch interface..." <Endl;
Ccomvariant varresult1;
Ccomvariant varresult2;
Ccomvariant varresult3;
Varresult1.clear ();
Varresult2.clear ();
Varresult3.clear ();
Cout <"Use method id.1 ......";
HR = pdispatch-> invoke (0x1, // Id 1
Iid_itimebeijing,
Locale_user_default,
Dispatch_method,
Null,
& Varresult1,
Null,
Null );
If (succeeded (HR ))
Cout <"OK" <Endl;
Else
{
Cout <"failed" <Endl;
Pdispatch-> release ();
Couninitialize ();
System ("pause ");
Exit (1 );
}
Cout <"Use method id.2 ......";
HR = pdispatch-> invoke (0x2, // ID 2
Iid_itimebeijing,
Locale_user_default,
Dispatch_method,
Null,
& Varresult2,
Null,
Null );
If (succeeded (HR ))
Cout <"OK" <Endl;
Else
{
Cout <"failed" <Endl;
Pdispatch-> release ();
Couninitialize ();
System ("pause ");
Exit (1 );
}
Cout <"Use method id.3 ......";
HR = pdispatch-> invoke (0x3, // Id 1
Iid_itimebeijing,
Locale_user_default,
Dispatch_method,
Null,
& Varresult3,
Null,
Null );
If (succeeded (HR ))
Cout <"OK" <Endl;
Else
{
Cout <"failed" <Endl;
Pdispatch-> release ();
Couninitialize ();
System ("pause ");
Exit (1 );
}
Printf ("time now: % d-% d/N", varresult1.intval,
Varresult2.intval, varresult3.intval );
Cout <"Close com runtime..." <Endl;
Pdispatch-> release ();
: Couninitialize ();
System ("pause ");
Return 0;
}
Test results:
Initialize com runtime... OK
Get idispatch interface pointer... timebeijingclassfactory-Constructor
Timebeijingclassfactory-QueryInterface
Timebeijingclassfactory-addref
Timebeijingclassfactory-createinstance
Timebeijingclass-Constructor
Timebeijingclass-QueryInterface
Timebeijingclass-addref
Timebeijingclass-addref
Timebeijingclass-release
Timebeijingclassfactory-release
Timebeijingclass-QueryInterface
Timebeijingclass-addref
Timebeijingclass-release
OK
Now use idispatch interface...
Use method id.1. ...... timebeijingclass-gethour
OK
Use method id.2.... timebeijingclass-getminute
OK
Use method id.3. ...... timebeijingclass-getminute
OK
Time now: 14-37-50
Close com runtime ......
Timebeijingclass-release
Timebeijingclass-destructor
Press any key to continue...
(8) VB Client
Create a standard EXE project with a button.
Select project --> references --> timebeijinglib
Enter the following code:
Private sub commandementclick ()
Dim C as timebeijingclass
Dim h as integer
Dim M as integer
Dim s as integer
Set c = new timebeijingclass
H = C. gethour
M = C. getminute
S = C. getsecond
Print "time now:"; h; "-"; m; "-"; s
End sub
The result is as follows:
Time now: 20-6-34