COM programming
In-process COM Server
In-Process COM Server, in the process, it is already a brief introduction, here, only intend to understand, understanding, understanding, and then programming may be better; within the process, the server is This name is obtained because they are implemented in the DLL. Therefore, the server accounts for the same address space as its application. All processes COM server output four standard functions: DllregisterServer, DllunRegisterServer, DllgetClassObject, and DllcanunloadNow. According to literally, we can also feel what these functions will work. Of course, Delphi has provided us with the default implementation of these functions. Therefore, the reader does not have to write code to implement these functions, but should understand what they specifically do.
2 dllregisterServer. DllRegisterServer is automatically called in two ways. IDE's Register ActiveX Server menu option calls it, Windows command line application regsvr32.exe (or Borland Application TregsVR) also calls it, in many cases, can be called directly with Register ActiveX Server, if manual is realized, Write a .bat file. Whether it is called in that way, DllRegisterServer uses a Windows registry to register a COM object.
2 dllunregisterServer. It can feel, this function and the DllregisterServer are the opposite work. In fact they are a phase reversible process, which removes all the entries in the Windows registry. This project can be called with Unregister ActiveX Server in IDE.
2 dllgetClassObject. DllgetClassObject is responsible for providing COM a class, which is used to create a COM object (when we discuss the class factory, we have also done a clear description).
2 dllcanunloadnow. COM is responsible for calling DllcanunloadNow to see if you can uninstall the COM server from memory.
Threading Support
Thread support is only suitable for internal servers in the process and does not apply to process external servers. The server can be attached to a few. The thread model of the server in the process is existing in the Windows registry, as follows:
2 ...
2 ...
2 ...
2 ...
..........
Registration Server (Registering the Server)
Here, it will no longer resculate how to register the server, just simply say why you want to register. We all know that ordinary DLL also needs to be registered to run, while COM objects or COM servers to provide services to the client, then the client first wants to know if this service is there? How to call or access this service, so it will find some useful key values, and the category of customers is the registry. Thus, the registration is really necessary and will be indispensable.
Constructor
It should be clear that it is an object or interface or one component that provides services. It is a construction, which is constructed, and the structure is also initialized, and we also said that the COM object is best derived from Tcomobject class. In this way, we have to consider the constructor in TcomObject to call the virtual method INITIALIZE. If you need to provide initiator code for your own COM object, you only need to overload the initialize method, define as follows: procedure initialize; virtual;
The reason why the initialization code is placed in Initialize rather than constructor is that the base class of the COM object in Delphi contains a series of non-virtual construct functions. The roots need to call different constructor in different instances. Initialize is a virtual method, and is the only way that can be considered when calling is a method for creating a COM object.
Create an instance of a COM object within a process
When the user needs to create a COM object in its own client code, the CreateConObject function is usually called, which is defined in COMOBJ.PAS, as follows:
Function CreateComobject (Const ClassID: Tguid): iunknown;
CreateComobject The GUID of the COM object will be created as a parameter and returns the iUnknown pointer to the COM object. If you can't find it in the Windows registry, you will throw an exception. Then let's analyze the implementation of the CreateComobject function as follows:
Function CreateComobject (Const ClassID: Tguid): iunknown;
Begin
Olecheck (CocreateInstance (ClassID, NIL, Clsctx_inproc_server OR
CLSCTX_LOCAL_SERVER, IUNKNOWN, RESULT);
END;
We have discussed Olecheck before, and now focus on CocreateInstance. If the root trace CocreateInstance will find the following information:
Function CocreateInstance; External Ole32 Name 'CocreateInstance';
Therefore, it is possible that the CreateComobject function is only called the Windows function CocreateInstance, and provides some default parameters.
CocreateInstance mainly has five parameters:
CLSID: CLSID is the GUID of the COM server we want to create. This is the only parameter that our specials passed to createComobject unique.
UNKOUTER: Only use it when this COM object is part of a collection.
DWClsContext: DWclsContext determines the type of reader wants to create. CreateComObject automatically requires a process (clsctx_inproc_server) or a local process server (Clsctx_local_server). Another tag that is sometimes used with this function is CLSCTX_REMOTE_SERVER. This flag is used in DCOM and will be discussed later.
IID: IID is the interface we want to get a reference to it. Delphi usually requires the application of the IUNKNOWN interface, because if you want other other references, most of the factories will fail. Microsoft uses this parameter mainly for future expansion.
PV: Mainly a pointer to the iUnknown interface.
{One need to register is: COCREATEINSTANCE internal creation is responsible for creating an instance of COM Object Camera, and then uses a class factory to create an object. After creating a COM object, the class is destroyed. Obviously, if you want to create multiple instances of the same COM object, this is not very effective. In this case, you will be able to create a CREATEINSTANCE method to use its CreateInstance method before deleting it. } As mentioned earlier, createComobject usually returns an iUnknown pointer. To get the needed interface, you should use the AS operator, such as:
Myintf: = CreateComobject (CLSID_MYSERVER) AS IMYINTERFACE
Example: A simple COM application
After discussing some of the basic concepts of the COM server, we use a simple small instance to explain how to call the COM server for the DLL form to provide services, and we will extend this COM server and will give a COM server. Advanced programming, but everything takes a step step.
Example Description:
This instance is a simple algorithm that can be implemented when logging in to a COM server correctly, and does not give a connection between the COM server and the database server, so the login is not a dynamic judgment from the database user information table, and It is a fixed username specified in the program. Of course, here, you can connect some text databases to perform dynamic judgment. The algorithm here is very simple, it is the traditional little monkey to eat peaches, a little monkey has some peaches, eat half a day, because of the mouth, eat more, this is half a day, when it is tenth day After eating, only one (more than half of the eating here), and the algorithm is to know how many peaches do the little monkey.
Problem Analysis: Because some methods of the COM server are required, you can temporarily make the following decision:
The user's information judgment, that is, whether the login is successfully confirmed to judge us, the client is just a simple error check and data submission, and it is really realizing a thin client;
{Description: The thin client here hopes that the reader friends do not only look at the client only according to literally, the less the client's code is, the work you have to do will make the server is thin. In fact, it should not be understood so, and the server / client we generally understand should be a server to handle some logically, business analysis, and some judgment errors can be completed by the client, although it is a customer End, but it also has some own check inside, although it is a server side, it still has some tasks to complete, more cases, maybe for readers, it feels better to make customers better }
The algorithm is actually very simple, and the loop can be used, and the recursive can be used, just simply analyzed here. If we use the loop to start, we will start from the back, and there is a peach after the tenth day. So tenth day, it should be four, the ninth day is ten, the eighth day is twenty-two ... ..., so, we can easily draw how many peaches, which can be processed:
VAR
ACOUNT: INTEGER;
ASUM: Integer;
Begin
ASUM: = 1;
For acount: = 10 DOWNTO 1 DO
ASUM: = (asum 1) * 2;
END;
It is easy to understand, there is still a peach left after tenth day, then, the tenth day should actually be four, which can be aware of the answer. It will be simpler as the following: Function Cal (Avalue: Integer): Integer;
Begin
If Avalue = 11 THEN
Result: = 1 else
Result; = (CAL (Avalue 1) 1) * 2;
END;
Monkey eats peach, although the topic is quite simple, but more or less is a bit of spare, we are very easy to use by cycles, and it is to use recursive completion of this process, there should be left after the 10th day. 1, equivalent to 4 peaches in day 11, so we can list: if dayvalue = 11 Then Sum = 1; the process of recursive is very simple, as long as we can grasp it is a pile process, go in It's still always coming, and advanced afterwards;
1. Create a COM server
To create a COM server to implement this algorithm, and this COM server also wants to log in to the interface. Delphi7 provides us with a good creation wizard, making us not as in delphi3, you need to manually type code, some questions need to be explained, because this app will make a process, so the first premise is to be a library, Everything should be carried out in the container of this library.
Create a new application (File -> New -> Other) Select the ActiveX tab, as shown below: ActiveX Library or select ActiveX Press Enter key, Delphi will automatically complete some work.
When you click the "OK" button, you are as follows:
Library Project2;
Uses
COMSERV;
Exports
DllgetClassObject,
DllcanunloadNow,
DllRegisterServer,
DllunregisterServer;
{$ R * .res}
Begin
End.
This creates a primary work in the inner COM server. DLLs are shown in the previous side of the code, and Delphi will automatically establish for us, and DllgetClassObject, DllcanunloadNow, DllregisterServer, DllunregisterServer In front of the chapter, we have introduced in detail, in some Complete. Please save this file as SRVPRO.
Take a slight analysis here, in order to implement the algorithm, we need to use the interface to call, and now we only completed the ActiveX Library library, the next job is to create a true COM component. It is also very simple to create a COM component. According to the Guide Tips (File-> New -> Other -> ActiveX), as shown below
Here we are simple to say the specific meaning of this COM Object dialog:
Class Name: Fill in the class name here, Delphi will automatically add "T";
Instancing: Service within the process, it is meaningless, because the COM server and application are in the same process;
Threading modal: Thread model, thread model specific to the content of threaded models, before we have introduced more, it will not be repeatedly elaborated, but it is necessary to know that there is a certain thread model, then this server is one What kind of thread model, but a reasonable arrangement in the programming process. Recommended the default thread model: Apartment; click "OK" button, and save the file into an accunt, will appear in the following code:
Unit Accunt;
{WARN SYMBOL_PLATFORM OFF}
Interface
Uses
Windows, ActiveX, Classes, Comobj;
Type
TACCEMP = Class (Tcomobject)
protected
END;
Const
Class_accemp: tguid = '{561FA61C-A985-4F70-8B5A-DF40BA9A7ED8}';
IMPLEMENTATION
Uses Comserv;
INITIALIZATION
TcomobjectFactory.create (COMSERVER, TACCEMP, CLASS_ACCEMP,
'Accemp', 'Instance Analysis', CIMULTIINSTANCE, TMAPARTMENT
End.
We make a short analysis of the above code:
TACCEMP is a class generated. Memolive, in the wizard we specify accemp for the class, Delphi automatically adds "T".
Class_Accemp constants is a GUID representing the COM server. Each interface implemented in the server will have a guid;
The initialization portion of the unit includes a single but complex constructor call. This call has established a class that is responsible for creating a TACCEMP COM object.
TcomObjectFactory.create is defined in COMOBJ.PAS:
Constructor TcomobjectFactory.create (COMSERVER: TCOMSERVEROBJECT;
COMCLASS: TCOMCLASS; Const ClassID: Tguid; Const ClassName,
DESCRIPTION: STRING ;TENSTANCING;
ThreadingModel: tthreadingmodel;
Begin
Ismultithread: = ismultithread or (ThreadingModel <> tmsingle);
IF ThreadingModel in [TMFree, Tmboth] THEN
Coinitflags: = Coinit_multithreaded Else
IF (threadingmodel = tMapartment) and (CoinitFlags <> Coinit_multithreaded) THEN
Coinitflags: = COINIT_APARTMENTTHREADED;
Comclassmanager.addObjectFactory (Self);
FCOMSERVER: = COMSERVER;
FCOMCLASS: = COMCLASS;
FCLASSID: = ClassID;
FclassName: = ClassName;
FDESCRIPTION: = Description;
Finstancing: = Instancing;
Ferroriid: = iUnknown;
FshowerRors: = true;
FthreadingModel: = threadingmodel; fregister: = -1;
END;
Combined with parameters to understand this process.
In 99% case, the user simply passes the global COMSERVER object as the parameter COMSERVER.
The second parameter COMCLASS accepts classes that will be created by the class. In this example, the multi-aeration of this class creates a TACCEMP instance.
The third parameter classID gets the GUID assigned to the TACCEMP class. Class_accemp;
Next, pass the description of the class accepts accemp and classes.
The instancing parameter is applied only to the process of COM server. It can be ignored here.
Delphi's COM object wizard fills in the default value CIMULTIInstance.
The last parameter accepts a value indicating the thread model, which is supported by this object. The various parameters of the above can be referenced according to its implementation code. In fact, its implementation process is more likely to position the parameters listed on the top. This process is left to reader friends. Of course, even if it is not very understanding of it, there is no problem.
From the description of the top, let's analyze:
TcomobjectFactory.create (COMSERVER, TACCEMP, CLASS_ACCEMP,
'Accemp', 'Instance Analysis', CIMULTIINSTANCE, TMAPARTMENT
Create a COM object TACCEMP instance accemp, and its GUID is the constant description of the class_accemp represents 'instance analysis', supports multi-threaded.
The COM object is inseparable from the interface. Only by the interface can be used to call the service from the service from the COM object. Next, we need to fill the interface of the interface, because the simple implementation of the login and algorithm, According to the previously mentioned, if the two contacts are not very close, we try to put the relative independence of the interface in different interfaces, in fact, the actual situation is true. Because the interface is invariant. Interface responsible for logging in We just need to implement two functions in the same interface, as follows:
Iaccintf = interface
['{Addfaffe-32d0-474f-909c-155e3906f0d1}']
Function getlogn (username, userpass: string): boolean;
Function GetSystime: String;
END;
Besides, the author reminds that the GUID should be created when each interface declaration is declared. It is assumed that it will not be created in the interface. In the interface separation of the rear, "does not support the interface", do not worry about GUID Will be used, even if there are hundreds of years, it will not be used in our existing GUID. Don't think about Copy - Paster GUID;
{DELPHI, Shift Ctrl G can generate a unique guid}
Implementing an algorithm interface Now we have to define a functional implementation; there is a problem, in order to seek time intervals, we need to add a time interval in this interface again? This is designed to some detail issues of systematic analysis. If the reader is writer, I suggest that this time is written on the client, even if the customer time is different from the server time, because we just take time intervals, of course, if it is to get the server The time should also be fill in a functional implementation in this interface. Of course, we can call this feature in other interfaces, however, for a very easy-to-implement function, the interface is separated or transformed, and there is not much necessary. This example is the use of interface separation to get the time function in other interfaces, which is designed to illustrate some problems to the reader friend. This interface is implemented as follows: Iaccsum = Interface
['{1D2F7597-6FCF-4706-810F-90A501953FFB}']
Function Accsum (Avalue: Integer): Integer;
END;
After the interface declaration is completed, the implementation process of writing the interface is required.
In unit Accunt, you can see the following code:
......
Type
TACCEMP = Class (Tcomobject)
......
......
Implementing the class TACCEMP does not implement the interface, which we only need to make the two interfaces that have just declared make it possible. The server-side code is as follows: