Download source code
I. Preface
I finally wrote the tenth time, and I have been hoping to write this time. Why? Automation is a very common, useful, and wonderful com
Function. Because office software such as Word and Excel provide the "macro" function, even the VC development environment we use also provides the "macro" function.
HTML, ASP, JSP, and so on all rely on script support, reflecting the importance of automated interfaces.
If you are using the development environment of vc6.0, read the previous one.
If you use vc.net 2003, continue ......
Ii. idispatch Interface
If it is a compilation language, we can let the compiler load the Type Library during compilation, that is, the description of the loading interface. In the seventh article
In this chapter, we use the # include method and # Import
Method. After the Type Library is loaded, the compiler will know how to compile the interface function call --- this is called "pre-binding ". However, if you want to use components in the script language, the problem will be big, because the script
This language is interpreted and executed, and it does not know the specific function address during execution. What should I do? The automated interface was born-"post-binding ".
Automated components are actually components that implement the idispatch interface. The idispatch interface has four functions. The Interpreter executes the functions provided by the component through the only four functions. The idispatch interface is described in the IDL format as follows: (Note 1)
[
Object,
UUID (00020400-0000-0000-c000-000000000046), // IID = iid_idispatch of the idispatch Interface
Pointer_default (unique)
]
Interface idispatch: iunknown
{
Typedef [unique] idispatch * lpdispatch; // convert idispatch * To lpdispatch
Hresult gettypeinfocount ([out] uint * pctinfo); // the two functions related to the Type Library. Let's talk about them later.
Hresult gettypeinfo ([in] uint itinfo, [in] lcid, [out] itypeinfo ** pptinfo );
Hresult getidsofnames (// obtain the function serial number (dispid) based on the function name)
[In] refiid riid,
[IN, size_is (cnames)] lpolestr * rgsznames,
[In] uint cnames,
[In] lcid,
[Out, size_is (cnames)] dispid * rgdispid
);
[Local] // functions of the local version
Hresult invoke (// explain the function execution function based on the function serial number
[In] dispid dispidmember,
[In] refiid riid,
[In] lcid,
[In] Word wflags,
[In, out] dispparams * pdispparams,
[Out] variant * pvarresult,
[Out] partition info * p1_info,
[Out] uint * puargerr
);
[Call_as (invoke)] // remote functions
Hresult remoteinvoke (
[In] dispid dispidmember,
[In] refiid riid,
[In] lcid,
[In] DWORD dwflags,
[In] dispparams * pdispparams,
[Out] variant * pvarresult,
[Out] partition info * p1_info,
[Out] uint * pargerr,
[In] uint cvarref,
[IN, size_is (cvarref)] uint * rgvarrefidx,
[In, out, size_is (cvarref)] variantarg * rgvarref
);
}
The above idispatch interface function is described in the next step. How can we implement these functions in component programs? Okay, okay. Just like iunknown, both MFC and ATL have helped us. This section focuses on the compilation of components. The next section describes the call methods of components.
Iii. use MFC to implement automated components
I wrote this entire series of articles-COM Component Design and Application, mostly using ATL
Write component programs, but because automation is very useful, in subsequent articles, we will also introduce the component's "Event" function, but also introduce how
It also supports the "macro" function. All of these require the use of MFC, so I will give the reader an answer :-)
3-1: create a solution
3-2: Create an mfc dll project named "simple7"
3-3: Be sure to select "Automation" in the additional functions. Remember! Remember!
3-4: Add a new class
3-5: supports automation in the new class
Class NameYou can write a class name.
Base ClassIt must be derived from ccomtarget. Only ccomtarget provides idispatch support.
Automation-NoneIt indicates that automation is not supported. If you want to select it, you just need to do it.
Automation-AutomationAutomation is supported, but cannot be directly instantiated. I will use multiple idispatches later. Don't worry about it now.
Automation-creation by type IDYou must select this project. In this way, in the subsequent call, VB can Createobject (), and VC can instantiate the component object by createdispatch. Note that this ID is actually the progid of the component.
3-6: Select an interface and add a function
3-7: Add a function. We need to write an integer addition function add ().
3-8: add the upper () function that converts the case of strings ().
3-9: Okay. Enter the program code below:
LONG CDispSimple::Add(LONG n1, LONG n2)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return n1 + n2;
}
BSTR CDispSimple::Upper(LPCTSTR str)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CString strResult(str);
strResult.MakeUpper();
return strResult.AllocSysString();
}
3-10: Compile and register
If an error occurs due to negligence, You can manually correct the error.
1. You can open the IDL file to modify the function. When modifying the function, be careful that there is a [ID (n)] function serial number in the function declaration;
2. Synchronously modify the function description and function body in H/CPP;
3. In the CPP file, modify begin_dispatch_map/end_dispatch_map () function to launch a macro as needed.
After correct compilation, vc.net 2003 is much smarter than vc6.0, and it automatically registers components. If you want to copy data to another computer, you also need to manually execute regsvr32.exe for registration.
4. implement dual interface components using ATL(For operation methods and steps, refer to COM Component Design and Application (6)
4-1: Create an ATL project named "simple8"
4-2: select the DLL type, non-attribute mode, and do not select any additional options
4-3: Add a new class and select a simple object of ATL
4-4: Enter the abbreviation and option. The option is implemented by default, that is, the dual interface method (note 2)
4-5: Add a function. Select Interface, right-click menu, add method...
Add ([in] variant V1, [in] variant V2, [out, retval] variant * pval );
Upper ([in] bstr str, [out, retval] BSTR * pval );
For the add () function, you can still use add ([in] Long N1, [in] Long N2, [out, retval] long *
Pval. But this time we didn't use long, but used variant for parameters and return values. Here, I will first sell a customs token and read it to know how to use it.
The beauty of variant.
4-6: complete the code
Stdmethodimp cdispsimple: add (variant V1, variant V2, variant * pval)
{
: Variantinit (pval); // always initialize the returned value is a good habit
Ccomvariant v_1 (V1 );
Ccomvariant V_2 (V2 );
If (v1.vt & vt_i4) & (v2.vt & vt_i4) // if all are integer types
{// Here = is not used, but the operator & is used. Do you know why?
V_1.changetype (vt_i4); // convert to an integer
V_2.changetype (vt_i4); // convert to an integer
Pval-> VT = vt_i4;
Pval-> lval = v_1.lval + v_2.lval; // Addition
}
Else
{
V_1.changetype (vt_bstr); // convert to a string
V_2.changetype (vt_bstr); // convert to a string
Ccombstr BSTR (v_1.bstrval );
BSTR. appendbstr (v_2.bstrval); // string connection
Pval-> VT = vt_bstr;
Pval-> bstrval = BSTR. Detach ();
}
Return s_ OK;
}
Stdmethodimp cdispsimple: Upper (bstr str, BSTR * pval)
{
* Pval = NULL; // It is a good habit to initialize the return value permanently.
Ccombstr S (STR );
S. toupper (); // converts to uppercase
* Pval = S. Copy ();
Return s_ OK;
}
I just sold the secret now ...... the addition function add () does not use the long type, but the benefit of using variant is that the function dynamically judges the parameter type, if it is an integer
Then the integer addition is performed. If it is a string, the string addition is performed (string addition is a string connection ). That is to say, if the parameter is variant, we can implement variable parameters of the function.
Data type. It's so cool!
5. Example of calling in script
Open the Notepad program, enter the script program, and save it as the XXX. vbs file. Then you can double-click it in the resource manager.
If you have the ability, you can also use JScript to write the above program and save it as a XXX. js file. You can also run it in the resource manager. Another point to note is that the icon in the script file (under Win 2000) is, if you are not like this (there is a software called "XX ". The developer level of the software is too low, and it is actually used. the extension file of vbs is used as its data stream file, which breaks the default file type shooting mode ......), you need to reset the settings:
6. Examples in Word
6-1: recording a macro Sequence
6-2: Select "keyboard". Of course, you can also put this "macro" program on the "toolbar. You can specify a shortcut, for example, CTRL + Z.
6-3: Start recording. You can enter something as needed. Click "stop"
6-4: Next, execute the menu, select the macro you just recorded, and edit it.
6-5: click "edit" and enter the following program:
If you have a little bit of VB, you can understand this stuff. Then save and close the VBA Editor (note 4 ).
6-6: Execute, execute, and see what the effect is ......
Press the shortcut key Ctrl + z
You have extended the MS word
Hey la ...... we just gave a simple example. In fact, this example has no practical significance, because
It supports case-insensitive conversion. However, through this small example, you can understand the functions of the automation components. Is it amazing ?!
VII. Summary
No summary! Hey hey :-)
Note 1: Later we will describe the interface functions in the IDL format.
Note 2: The dual interface is a special interface method that supports the idispatch interface. It will be discussed soon.
NOTE 3: VBA is a language dedicated to office development --- Visual Basic for application