Design of ActiveX Control Using MFC-Step 2

Source: Internet
Author: User
This step requires some COM basics, because without this foundation, there may be questions about why to do this, is it necessary, and so on. This time we will look at the dual interface and add a dual interface for the control designed by MFC (the dual interface is not explained ).
Here we refer to the example of acdual in msdn and apply some Macros in the example. You can search for msdn for this example and refer to TN065: Dual-Interface Support for OLE Automation Servers.

I always use an example, and I am tired of it. Here's a new example, the TDual control.
OK. Start:
1. Create an MFC Control Project. Here, a "Hello" property is added (the string corresponding to the "Hello" property is displayed on the control) and a method "SayHello" is added. A message box is displayed, showing the strings in the method parameters.
2. transformation interface,
Add second interface
[Uuid (C3180013-EB23-4e8f-924C-38F5A201D3D8 ),
Helpstring ("Double interface "),
Oleautomation,
Dual]
Interface ITDual: IDispatch
{
[Propput, id (1)] HRESULT Hello ([in] BSTR newText );
[Propget, id (1)] HRESULT Hello ([out, retval] BSTR * ret );
[Id (2)] HRESULT SayHello (BSTR strHello );
}
The interface description must contain oleautomation and dual attributes, and the interface must be derived from IDispatch.
The interface definition here is very similar to the IDL definition in ATL. If the control is designed using ATL, it should be no stranger. The specific rules will not be too long. If it is unclear, please search for the information by yourself. You can compare it with the original interface definition in MFC:
Properties:
// NOTE-ClassWizard will maintain property information here.
// Use extreme caution when editing this section.
// {AFX_ODL_PROP (CTDualCtrl)
[Id (1)] BSTR Hello;
//} AFX_ODL_PROP

Methods:
// NOTE-ClassWizard will maintain method information here.
// Use extreme caution when editing this section.
// {AFX_ODL_METHOD (CTDualCtrl)
[Id (2)] void SayHello (BSTR strHello );
//} AFX_ODL_METHOD
After defining a new interface, you need to add a reference to the new interface in the coclass description, as shown below:
[Uuid (A1E75855-8561-4416-BE49-97B4D9A228E2 ),
Helpstring ("TDual Control"), control]
Coclass TDual
{
// [Default] dispinterface _ DTDual;
// [Default, source] dispinterface _ DTDualEvents;
[Default] interface ITDual;
[Default, source] dispinterface _ DTDualEvents;
Dispinterface _ DTDual;
};
Set the default Interface to ITDual instead of the original dispinterface _ DTDual.

3. After the interface is modified, it is necessary to implement this new interface. MFC uses a nested class to implement an interface. The nested class is obtained by using BEGIN_INTERFACE_PART/END_INTERFACE_PART macro pair, and then implementing the corresponding interface functions of the nested class (including IUnknown and IDispatch interface functions) you can.
Here we useBEGIN_DUAL_INTERFACE_PART andThe END_DUAL_INTERFACE_PART macro pair and the DELEGATE_DUAL_INTERFACE macro simplify the implementation of interface functions in IUnknown and IDispatch. The macro definitions are listed at the end.

In TDualCtl. h, # include "mfcdual. h"
Add a new interface PART as follows:
// Event maps
// {AFX_EVENT (CTDualCtrl)
//} AFX_EVENT
DECLARE_EVENT_MAP ()

// Add part here
Public:
//////////////////////////////////////// /////////////////////////////////////
// Double Interface Part
DECLARE_INTERFACE_MAP ()
BEGIN_DUAL_INTERFACE_PART (TDual, ITDual)
STDMETHOD (put_Hello) (THIS _ BSTR newText );
STDMETHOD (get_Hello) (THIS _ bstr far * ret );
STDMETHOD (SayHello) (THIS _ BSTR strHello );
END_DUAL_INTERFACE_PART (TDual)

In TDualCtl. cpp

//////////////////////////////////////// /////////////////////////////////////
// Control type information

Static const DWORD BASED_CODE _ dwTDualOleMisc =
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE (CTDualCtrl, IDS_TDUAL, _ dwTDualOleMisc)

// Add AddRef, QueryInterface, and other general functions
DELEGATE_DUAL_INTERFACE (CTDualCtrl, TDual)

......

// These two functions are the Hello attribute and SayHello method functions used for distribution by the original Dispatch interface.
Void CTDualCtrl: OnHelloChanged ()
{
// TODO: Add notification handler code
InvalidateControl ();
SetModifiedFlag ();
}

Void CTDualCtrl: SayHello (LPCTSTR strHello)
{
// TODO: Add your dispatch handler code here
AfxMessageBox (strHello );
}

// These three functions are implemented by the newly added interfaces. Generally, they are implemented by calling the functions of the original interface. Here, a description is added to indicate that they are called from the vtable.
STDMETHODIMP CTDualCtrl: XTDual: put_Hello (BSTR newText)
{
METHOD_PROLOGUE (CTDualCtrl, TDual)
// MFC automatically converts from Unicode BSTR
// Ansi CString, if necessary...
CString str = newText;
PThis-> m_hello = "vtable:" + str;
PThis-> OnHelloChanged ();
Return NOERROR;
}
STDMETHODIMP CTDualCtrl: XTDual: get_Hello (BSTR * ret)
{
METHOD_PROLOGUE (CTDualCtrl, TDual)
// MFC automatically converts from Ansi CString
// Unicode BSTR, if necessary...
PThis-> m_hello.SetSysString (ret );
Return NOERROR;
}

STDMETHODIMP CTDualCtrl: XTDual: SayHello (BSTR strHello)
{
METHOD_PROLOGUE (CTDualCtrl, TDual)
// MFC automatically converts from Ansi CString
// Unicode BSTR, if necessary...
CString str = strHello;
Str = "I'm vtable SayHello/n" + str;
PThis-> SayHello (str );
Return NOERROR;
}

4. Connect the new interface to the QueryInterface interface Table Mechanism of MFC, so that the ITDual interface can be obtained through QueryInterface.
Add in. h
Public:
//////////////////////////////////////// /////////////////////////////////////
// Double Interface Part
DECLARE_INTERFACE_MAP ()
BEGIN_DUAL_INTERFACE_PART (TDual, ITDual)
STDMETHOD (put_Hello) (THIS _ BSTR newText );
STDMETHOD (get_Hello) (THIS _ bstr far * ret );
STDMETHOD (SayHello) (THIS _ BSTR strHello );
END_DUAL_INTERFACE_PART (TDual)


Add in. cpp
//////////////////////////////////////// /////////////////////////////////////
// Event map
BEGIN_EVENT_MAP (CTDualCtrl, COleControl)
// {AFX_EVENT_MAP (CTDualCtrl)
// NOTE-ClassWizard will add and remove event map entries
// Do not edit what you see in these blocks of generated code!
//} AFX_EVENT_MAP
END_EVENT_MAP ()

// Connect the new interface to the QueryInterface Mechanism
BEGIN_INTERFACE_MAP (CTDualCtrl, COleControl)
INTERFACE_PART (CTDualCtrl, IID_IDispatch, Dispatch)
INTERFACE_PART (CTDualCtrl, DIID _ DTDual, Dispatch)
INTERFACE_PART (CTDualCtrl, IID_ITDual, TDual)
END_INTERFACE_MAP ()

5. An error will be prompted during compilation because there is no ITDual interface declaration and some IID definitions. Click TDual. right-click odl and choose Setting from the shortcut menu. In the Output header file name, enter the interface you want to Output. h file name. ITDual is used here. h, and then set ITDual. h is included in stdafx. h, so that it can be used everywhere.
Next, create an initIIDs. cpp file and add the following code:

# Include <ole2.h>
# Include <initguid. h>
# Include "ITDual. h"

This initIIDs. cpp is useless, but only used to implement several IIDS. However, in Project-Setting, set the Precompiled Headers of initIIDs. cpp to Not using precompiled headers.
Compile TDual. odl, OK

6. Added Exception Handling and automated error interfaces. This section is not provided in this example. For more information, see the acdual example.

7. create a common MFC dialog box exe project testdual, introduce TDual in the project. ocx, the method used here is in stdafx. add # import "<YourPath //> TDual to h. ocx "no_namespace.
Add the member variable CWnd m_wnd to the CTestdualDlg, respond to the WM_CREATE message, and add the following code
CRect rect (10, 10,100,100 );
BOOL B = m_wnd.CreateControl (_ uuidof (TDual), NULL, WS_CHILD | WS_VISIBLE, rect, this, 1 );
If (! B ){
AfxMessageBox ("Can't CreateControl ");
Return 0;
}
LPUNKNOWN pukn = m_wnd.GetControlUnknown ();
If (! Pukn ){
AfxMessageBox ("Can't get IUnknown interface ");
Return 0;
}
ITDual * pdual = NULL;
Pukn-> QueryInterface (_ uuidof (ITDual), (void **) & pdual );
If (! Pdual ){
AfxMessageBox ("Can't get ITDual interface ");
Return 0;
}
CString str = "Thanks ";
Pdual-> SayHello (str. AllocSysString ());
Pdual-> put_Hello (str. AllocSysString ());
Pdual-> Release ();
Compile and run the program. The specific results will not be mentioned.

This article mainly describes how to do this. If you want to do so, you can leave it blank. If you are interested, you can study it on your own. Here are several URLs for your reference only.
Http://www.microsoft.com/china/msdn/archives/others/visualc/atlmfc.asp
Http://blog.csdn.net/RedStar81/archive/2003/04/03/19761.aspx

The following is some macro definition code in the acdual example.

# Define BEGIN_DUAL_INTERFACE_PART (localClass, baseClass )/
BEGIN_INTERFACE_PART (localClass, baseClass )/
STDMETHOD (GetTypeInfoCount) (uint far * pctinfo );/
STDMETHOD (GetTypeInfo) (UINT itinfo, LCID lcid, ITypeInfo FAR * pptinfo );/
STDMETHOD (GetIDsOfNames) (REFIID riid, olechar far * rgszNames, UINT cNames, LCID lcid, dispid far * rgdispid );/
STDMETHOD (Invoke) (DISPID handle, REFIID riid, LCID lcid, WORD wFlags, dispparams far * handle, variant far * pvarResult, interval info FAR * p1_info, uint far * puArgErr );/

//////////////////////////////////////// /////////////////////////////
// END_DUAL_INTERFACE_PART is just like END_INTERFACE_PART. It
// Is only added for authentication Ry...
# Define END_DUAL_INTERFACE_PART (localClass )/
END_INTERFACE_PART (localClass )/

//////////////////////////////////////// /////////////////////////////
// DELEGATE_DUAL_INTERFACE expands to define the standard IDispatch
// Methods for a dual interface, delegating back to the default
// MFC implementation
# Define DELEGATE_DUAL_INTERFACE (objectClass, dualClass )/
STDMETHODIMP _ (ULONG) objectClass: X # dualClass: AddRef ()/
{/
METHOD_PROLOGUE (objectClass, dualClass )/
Return pThis-> ExternalAddRef ();/
}/
STDMETHODIMP _ (ULONG) objectClass: X # dualClass: Release ()/
{/
METHOD_PROLOGUE (objectClass, dualClass )/
Return pThis-> ExternalRelease ();/
}/
STDMETHODIMP objectClass: X # dualClass: QueryInterface (/
REFIID iid, LPVOID * ppvObj )/
{/
METHOD_PROLOGUE (objectClass, dualClass )/
Return pThis-> ExternalQueryInterface (& iid, ppvObj );/
}/
STDMETHODIMP objectClass: X # dualClass: GetTypeInfoCount (/
Uint far * pctinfo )/
{/
METHOD_PROLOGUE (objectClass, dualClass )/
LPDISPATCH lpDispatch = pThis-> GetIDispatch (FALSE );/
ASSERT (lpDispatch! = NULL );/
Return lpDispatch-> GetTypeInfoCount (pctinfo );/
}/
STDMETHODIMP objectClass: X # dualClass: GetTypeInfo (/
UINT itinfo, LCID lcid, ITypeInfo FAR * pptinfo )/
{/
METHOD_PROLOGUE (objectClass, dualClass )/
LPDISPATCH lpDispatch = pThis-> GetIDispatch (FALSE );/
ASSERT (lpDispatch! = NULL );/
Return lpDispatch-> GetTypeInfo (itinfo, lcid, pptinfo );/
}/
STDMETHODIMP objectClass: X # dualClass: GetIDsOfNames (/
REFIID riid, olechar far * rgszNames, UINT cNames ,/
LCID lcid, dispid far * rgdispid )/
{/
METHOD_PROLOGUE (objectClass, dualClass )/
LPDISPATCH lpDispatch = pThis-> GetIDispatch (FALSE );/
ASSERT (lpDispatch! = NULL );/
Return lpDispatch-> GetIDsOfNames (riid, rgszNames, cNames ,/
Lcid, rgdispid );/
}/
STDMETHODIMP objectClass: X # dualClass: Invoke (/
DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags ,/
Dispparams far * pdispparams, variant far * pvarResult ,/
Raise info FAR * p1_info, uint far * puArgErr )/
{/
METHOD_PROLOGUE (objectClass, dualClass )/
LPDISPATCH lpDispatch = pThis-> GetIDispatch (FALSE );/
ASSERT (lpDispatch! = NULL );/
Return lpDispatch-> Invoke (dispidMember, riid, lcid ,/
WFlags, pdispparams, pvarResult ,/
P1_info, puArgErr );/
}/

//////////////////////////////////////// /////////////////////////////
// TRY_DUAL and CATCH_ALL_DUAL are used to provide exception handling
// For your dual interface methods. CATCH_ALL_DUAL takes care
// Returning the appropriate error code.

# Define TRY_DUAL (iidSource )/
HRESULT _ hr = S_ OK ;/
REFIID _ riidSource = iidSource ;/
TRY/

# Define CATCH_ALL_DUAL/
CATCH (COleException, e )/
{/
_ Hr = e-> m_ SC ;/
}/
AND_CATCH_ALL (e )/
{/
AFX_MANAGE_STATE (pThis-> m_pModuleState );/
_ Hr = DualHandleException (_ riidSource, e );/
}/
END_CATCH_ALL/
Return _ hr ;/

//////////////////////////////////////// /////////////////////////////
// DualHandleException is a helper function used to set the system's
// Error object, so that container applications that call through
// Vt1_can retrieve rich error information
HRESULT DualHandleException (REFIID riidSource, const CException * pAnyException );

//////////////////////////////////////// /////////////////////////////
// DECLARE_DUAL_ERRORINFO expands to declare the ISupportErrorInfo
// Support class. It works together with DUAL_ERRORINFO_PART and
// IMPLEMENT_DUAL_ERRORINFO defined below.
# Define DECLARE_DUAL_ERRORINFO ()/
BEGIN_INTERFACE_PART (SupportErrorInfo, ISupportErrorInfo )/
STDMETHOD (InterfaceSupportsErrorInfo) (THIS _ REFIID riid );/
END_INTERFACE_PART (SupportErrorInfo )/

//////////////////////////////////////// /////////////////////////////
// DUAL_ERRORINFO_PART adds the appropriate entry to the interface map
// For ISupportErrorInfo, if you used DECLARE_DUAL_ERRORINFO.
# Define DUAL_ERRORINFO_PART (objectClass )/
INTERFACE_PART (objectClass, IID_ISupportErrorInfo, SupportErrorInfo )/

//////////////////////////////////////// /////////////////////////////
// IMPLEMENT_DUAL_ERRORINFO expands to an implementation
// ISupportErrorInfo which matches the declaration in
// DECLARE_DUAL_ERRORINFO.
# Define IMPLEMENT_DUAL_ERRORINFO (objectClass, riidSource )/
STDMETHODIMP _ (ULONG) objectClass: XSupportErrorInfo: AddRef ()/
{/
METHOD_PROLOGUE (objectClass, SupportErrorInfo )/
Return pThis-> ExternalAddRef ();/
}/
STDMETHODIMP _ (ULONG) objectClass: XSupportErrorInfo: Release ()/
{/
METHOD_PROLOGUE (objectClass, SupportErrorInfo )/
Return pThis-> ExternalRelease ();/
}/
STDMETHODIMP objectClass: XSupportErrorInfo: QueryInterface (/
REFIID iid, LPVOID * ppvObj )/
{/
METHOD_PROLOGUE (objectClass, SupportErrorInfo )/
Return pThis-> ExternalQueryInterface (& iid, ppvObj );/
}/
STDMETHODIMP objectClass: XSupportErrorInfo: InterfaceSupportsErrorInfo (/
REFIID iid )/
{/
METHOD_PROLOGUE (objectClass, SupportErrorInfo )/
Return (iid = riidSource )? S_ OK: S_FALSE ;/
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.