Separating the software interface is a common method of developing a normal desktop application, which can bring a variety of benefits, such as convenient software automatic update and maintenance (we rarely see all all things of the software to an exe) . The usual approach is to encapsulate business logic or core in a separate component, such as COM or even standard DLL libraries. We discuss ordinary DLL here.
Only only normal functions or processes in the DLL must not work, object-oriented design and development, good model applications are essential, this requires us to provide an external access to the object in DLL. For example, Delphi can use the BPL package, or Interface to access objects in the DLL, Visual C is simpler, and the MFC extension DLL even allows you to export this class. However, Delphi and VC have advantages in the development, and Delphi quickly develops a very suitable interface, and there is a large number of 3rd round library available, which can develop a very beautiful interface. This point I personally think that it is more than VC. A lot (of course. Net hosting C exceptions, because it can directly use the library provided by .NET); and the advantage of VC is the flexibility and efficiency of the C language itself, which is ideal for the core part of the software (for example, you can also use Intel) C compiler to recompile the code, greatly enhance the performance in the Intel platform). If we can use Delphi to develop the software interface, use VC to develop core business logic not very good? Delphi Accessing the normal export function in the C DLL is of course no problem, but how can I access the object by interface? I studied for a day or two, carefully analyzed the object model of C and Object Pascal, finally got, shared my experience here:
Interface and C in Object Pascal are very different, for example, we can declare a C interface below
Struct iFoo: Public IUNKNOWN {Virtual INT_STDCALL ADD (INT X, INT Y) = 0; // Since the virtual function in the class needs to be exported, the interface, and the virtual function in the class should be used _stdcall practice Virtual INT _STDCALL DIVD (int X, INT Y) = 0;
Then we use an export function to export C objects through this interface:
EXTERN "C" _Declspec (DLLEXPORT) iFoo * getMaininterface () {return Dynamic_cast
(Mainfoo); // mainfoo is an object pointer to a class of IFOO, initialization when DLL is loaded
}
Declare the corresponding interface and interface pointer in Delphi:
Ifoo = interface function add (x, y: integer): integer; stdcall; function Divd (x, y: integer): integer; stdcall;
Pifoo = ^ iFoo
Then import the object by the following steps:
GetMainInterface: function: PIFoo; stdcall; // C function corresponding to the derived ... Libhwnd: = loadlibrary ( 'DLL path'); @GetMainInterface: = GetProcAddress (Libhwnd, 'GetMainInterface'); MainIntf: = GetMainInterface; / The type of mainintf is pifoo; ok, I first thought that all it was done, it was very simple, but when I was called through Mainintf ^ .divd (15, 3), there was no income, and later Through analysis, I know that INTERFACE in Object Pascal is a pointer, although its type is not a pointer, but it is indeed a pointer to the interface VMT, and Pifoo is a pointer of a pointer, and the IFOO * in C is not a 2 Heavy pointer, look at the assembly code below:
MOV EAX, [EBX $ 000002FC] // Accommoded the first address of the interface to the EAX register Push Eax // Don't use it MOV EAX, [EAX] // Look at the first 32-digit address in the interface memory as a pointer, this pointer The content is the entrance to the VMT ... MOV EAX, [EAX] // The most critical is here, in fact, this directive is redundant, so I don't know which block has fallen, the following call is of course There will be memory access errors. Why have this extra directive? It is the reason I am saying above, mainintf is a 2-rewarded pointer, and the Delphi compiler thinks to pass two MOV EAX, [EAX] can get the entrance to the object VMT, so there is a problem, which is also visible Object Pascal. , VCL, Delphi IDE has enough skill, but the combination is too tight. Call DWORD PTR [EAX $ 10] // The entry of the VMT is plus the appropriate bias movement is the method pointer to call.
How to solve this problem? We can only convert the mainintf 2 heavy pointer to the interface to delphi (IFOO (Mainintf) .divd (15, 3) is a correct call).