Create a COM DLL in C ++

zhaozj2021-02-16  55

Today, I will learn from COM programming, find some self-think of value file sharing to everyone:

Create a COM DLL in C

In this article we will discuss how to develop a very simple ActiveX DLL in MSVC , and call it in Visual Basic, where examples will be used to Active Template Library (ATL) and related wizard tools. This article does not involve the working principle of COM and ATL (although this is required), it is not required to have any ATL experience.

IDL: Main difference

Developing ActiveX in C and VB (except for language and other small aspects) is the introduction of IDL. IDL is an interface definition language (Interface Definition Language), just like his name, it defines the interface of the DLL. The client can use the interface to bind yourself with objects and DLL methods, but its role is not limited to this.

By using IDL, we can completely open the appearance and code of the object, hide anything after the interface can be changed at any time, and any client program using the DLL does not need to have any changes, because the interface has not changed. IDL also defines data types and parameters transmitted between processes.

Since IDL is completely independent of the specific language, it is not limited to COM or C , and CORBA can also use IDL to define the interface.

All VB AX (ActiveX) objects use the IDL type library when compiling, how to define the object, method, and function in the VB program, VB will complete all work behind the scenes. In MSVC , you don't automatically generate IDL when you create an AX DLL. The type library is not required for COM objects (DirectX COM API is a good example.) This work requires C programmers to complete.

MSVC COM ATL Project

Create an ATL COM AppWizard project and name it MYAXDLL. The specific method I am not awkward here.

AppWizard will add some files in the project. The most important thing is myaxdll.cpp, which includes DLL export functions that must be available for each COM object. DLLCanunloadNow, DllgetClassObject, DllRegisterServer, and DllunregisterServer, which is DLL in registration and creation. There is. The wizard code Forwards calls the variable of the basic ATL CCommodule class _Module, which contains all the basic functions that COM objects creation, registration, and logout it.

AppWizard also adds a MyAxdll.idl file that contains the IDL of all objects, properties, and methods in the project.

This project itself doesn't have useful things, it just includes some of the COM objects and functions, and if you want to have a certain function, you need to add an object. The method of adding an object is believed that everyone is a simple thing, I am not discussed in detail here.

The wizard adds three files in the project, MyObject.cpp, and myObject.h, myObject.cpp, and myObject.RGS, the RGS file contains registration settings for COM classes written in a registration language, and their content is in the compiled DLL file. As a registration source, it can be used by the registration to properly register the DLL. The MyObject.h file contains the definition of the MyObject class, open the file and observes its code, you can find that the file contains a class ━━cmyObject, which is generated by other four class inheritance, three of which is The mode board class is a separate class (ISUPPORTERRORINFO). In addition, some macro definitions are included: declare_registry_resourceId (idR_myObject)

Declare_protect_final_construct ()

Begin_COM_MAP (CMYOBJECT)

Com_interface_entry (iMyObject)

COM_ITERFACE_ENTRY (Idispatch)

COM_Interface_entry (Isupp PorterrorInfo)

END_COM_MAP ()

The DECLARE_REGISTRY_RESOURCEID macro expansion is a static function that registers the server in the system registry (COM object), and IDR_MYOBJECT is the source ID of the class to register.

DECLARE_PROTECT_FINAL_CONSTRUCT () ensures that any internal object does not generate an object that calls FinalConstruct (), and the object being combined must use the macro.

Begin_com_map (), COM_INTERFACE_ENTRY () and end_com_map () definitions are advanced, and their discussion has exceeded the scope of this article. We can use each interface that the class performs, and com_map in COM_MAP is required.

The code next to myObject.h is a definition of a function:

SecDMethod (InterfaceSupportSerrorInfo) (Refiid RIID)

The code for this function is done in myObject.cpp. Macro STDMETHOD (FUNCTIONNAME) can be expanded into the following form:

Virtual HRESULT stdmethodcalltype functionname

StdMethodCallType is a standard __stdcall type, so Macro STDMETHOD ensures that the function uses a standard call rule and returns a value of a HRESULT type.

The InterfaceSupportSerrorInfo function is a unique function other than the required function in the iSupp PortERRORINFO interface. By performing this interface, the server can set an error information object, and the client can use this error message. Although errors in VB are in the same type, this way of handling error information is very different from VB. Since the appropriate error message processing method is extremely important for software, it is necessary to discuss this problem.

COM and COM errors

The COM object in the MyAxdll project performs the ISUPPORTERRORINFO interface, which enables the server's client to query the extended error message. This way is confused by users who have been accustomed to standard VB error handling methods. The difference between the two is the return value of the method of the object. In VB, we define the type of return value in the first part of the function, as shown below:

Public Function Doot () As long ... DOIT = SomeValueEnd Function

The above code defines the type of function returns the value into long type data, which has no problem in VB and scripting languages. It is completely different in C , the head of this function will become the format as shown below: HRESULT __STDCALL DOIT (long * return_value) {... * return_value = SomeValue; Return S_OK;}

The above function header defines the return value to S_OK, indicating to the client, the function is successful, and the return value that is actually available is transmitted to a parameter similar to byref. So why is this this?

The reason is the construction method of COM. The COM subsystem sometimes needs to notify the client error in the function call, for example, if a client is accessing a remote server, if the server is not on the network, there is a number of return values ​​available for the COM subsystem. And the self-care of the abnormality has great dependence on the language. Therefore, almost all COM methods returns a HRESULT value, which indicates the execution of the function. In the SDK

The file defines some basic return types, the most commonly used two kinds of: S_OK, which indicates that the function is executed properly; E_FAIL indicates that the function performs an exception.

Table 1 lists some common returns:

E_NOTIMPL: No execution

E_OUTOFMEMORY: Memory overflow

E_INVALIDARG: One or more parameters are invalid

E_NOINTERFACE: Does not support the interface

E_POINTER: Invalid pointer

E_HANDLE: Invalid handle

E_ABORT: Operation

The above table lists the messages that can be passed between procedures, once the process is not normal, COM can notify the client in the VB, how is this implementation in VB?

VB also has the same mechanism. If a VB function is successfully executed, VB will return to a S_OK value; if the function is exception, there will be an error, and the VB will return an error code for an error object that is HRESULT.

When the VB client program accesses the COM server, if a call failed HRESULT value is returned, VB will immediately query the server to see if it supports the ISUPPORTERRORINFO interface. Because if the server supports this interface, VB will give the interfaceSupp PortRRORINFO function query failure to support extended error messages.

Since both the same, InterfaceSupp PortrorInfo will return a TRUE value, indicating that the interface does not support extension error messages, and VB will ask other interfaces to see if they support this information. This is all made after the ATL is completed behind the scenes, so as long as the COM server The corresponding information is set, VB is available for extended error messages. VB uses this information to establish a similar error object, and then give an error type value ━━ Type of HRESULT.

Therefore, if an error message is found in VB, the real error is only limited to the range of COM objects, and VB simply returns the value of Err.Number, which is only used to query the expand error message to the COM object.

Later, we will carefully discuss how to set the error message.

Add a method in the object

Now let's add a method to the object. There are three objects in this example:

1. Take two long type values, add the two, and return the result.

2, take a long data and report the error message

3. Take a long data, convert it to BSTR data, and return this data

Adding a method in a COM object requires two steps: 1, you need to define a method in the IDL file; 2, must be implemented by the MyObject class. To illustrate the specific steps of adding methods in the COM object, we will use the first method in manual manual, second, and three methods, using the AppWizard wizard to complete. Open myaxdll.idl file. The IDL in the file can be divided into two parts, the first part is the definition of the MyObject object, and below is all methods, attributes of the object. The code is as follows:

MyObject Definitions

[

Object,

UUID (28D7C31F-1FB2-4BF8-BC98-C8A256348354), DUAL,

Helpstring ("ImyObject Interface",

Pointer_DEFAULT (UNIQUE)

Interface IMYOBJECT: IDISPATCH

{

}

The myaxdll definitions:

[UUID (E37200F2-E3DD-4243-9248-AA6A7FE71369),

Version (1.0),

Helpstring ("Myaxdll 1.0 Type Library")

]

Library myaxdllib

{

Importlib ("stdole32.tlb"); importlib ("stdole2.tlb");

[

UUID (09374147-1b90-4d78-b5b1-6e5b97c60df2), Helpstring ("MyObject Class")

]

CoClass myObject

{

[default] interface IMYOBJECT;

}

}

MyAxdll puts myObject interface as a joint class.

To define a method for MyObject, the method must be added in the middle of the iMyObject: iDispatch {} in the above code. Add the following to two parentheses:

[ID (1), Helpstring ("Addlongs Method - Adds Two Longs and Return The")]]]

HRESULT Addlongs ([in] long firstparam, [in] long secondparam, [out, return] long * rt);

This is the most basic IDL of the method to add a method in the object. [ID (1), Helpstring ("Addlongs Method - Adds Two Longs and Return The Result"] Set some properties to the method you want to add. ID (#) Sets the DISPID for the object used for the IDispatch interface function, Helpstring is a string that explains this method, and we can view this string in the object browser in VB.

Real function: hResult addparam, [in] long secondparam, [out, retval] long * RT); In addition to [Direction], it is very simple to indicate how and who is the parameters. Control, they have direct relationships with how VB communicates with the function. Some commonly used tag combinations listed below:

[IN] is the same as byval in VB, indicating that the parameter is allocated by the caller allocated storage and control.

[OUT] indicates that the parameter is allocated by the modified function.

[IN, OUT] is the same as byref in VB, indicating that the parameter should be allocated by the caller, and the called function can be reclaimed the storage space of the parameter, or the space can also be allocated to the parameter.

[OUT, RETVAL] is the same as the AS TYPE return value in VB. If the pointer points to a pointer, the called function can only be assigned a storage space for this parameter. To complete this function, you need to open myObject.h files. Add the following basic function definitions in the PUBLIC section of the class:

StdMethod (ADDLONGS) (Long Secondparam, long * rt);

This is just the definition of the object, but also you need to add the following in myObject.cpp file:

StdMethodimp CMYOBJECT :: Addlongs (Long Firstparam, Long Secondparam, long * rt)

{

* RT = firstParam SecondParam;

Return S_OK;

}

At this point, we add a method to the object.

The second function can be easily defined by using a wizard tool. Select the ClassView tab in the engineering resource manager, extend the CMYObject and select the IMYObject interface, right-click the interface and select "Add Method", name the method to Raisenerror, and add the following to the parameter box:

[in] long firstparam, [out, return] long * rt

At this point, the wizard has added the IDL of the method in MyAxdll.IDL, and the framework of the function is added to myObject.h, myObject.cpp file. Open myObject.cpp file, add the following in the RaiseAnError function:

StdMethodimp CMYOBJECT :: RaiseAnError (Long Firstparam, Long * RT)

{

/ / This function must set an error object

Return ATLREPORTERROR (CLSID_MYOBJECT, "UPPS An Error Occurred", IID_IMYOBJECT, E_FAIL);

}

This function uses the ATLREPORTERROR Help function that sets an error message and allows VB to get and displays these error messages.

Due to the use of BSTR, the last function is a bit special, BSTR is a simple pointer to OLECHAR, allocation, and recoverable storage of BSTR must be implemented via the SYSALLOCAXX string function, otherwise it may disrupt the COM system, which may make you encounter some strange The problem.

The Function Takes One Long Value, Convert It To A Bstr And Returns It Like this, Using The AppWizard Mention Adovement:

This function acquires a Long type data to convert to BSTR data and returns the result of the conversion to the caller. Use AppWizard as follows:

Name: ConvertToString

Parameters: [in] long firstparam, [out, return] BSTR * CONVERTEDVALUE

The generated code is very simple, as shown below:

STDMETHODIMP CMYOBJECT :: ConvertTString (Long FirstTString (Long Firstparam, BSTR * ConvertedValue)

{

Tchar tzconverted [20]; /

// Clear

MEMSET (Tzconverted, 0, 20);

// convert with C run library functions

_ITOA (Firstparam, Tzconverted, 10); // Convert to BSTR

Uses_Conversion;

IF (:: sysReallocstring (ConvertedValue, A2OL (Tzconverted))) Return S_OK;

Return E_OUTOFMEMORY;

}

More importantly, the allocation of the storage space of the return value is done by sysReallocString (). Since BSTR is created by the client program, use the sysallocstring () function to ensure that it is not overwritten.

.

After all 3 methods are added, compile the project and fix the errors.

Client software

Client software is a VB program that we can use this article (need to compile the DLL first) or create a VB program yourself. Establish a symbol for the Myaxdll.dll type library in the engineering symbol library.

in conclusion

This article has not discussed the knowledge of COM and ATL in detail, but it briefly introduces how to use ATL and COM to expand basic skills using ATL and COM.

转载请注明原文地址:https://www.9cbs.com/read-23271.html

New Post(0)