├── .gitignore
├── LICENSE
├── LazComDll
├── LazComDll.lpi
├── LazComDll.lpr
├── LazComDll.lps
├── LazComDll.ridl
├── LazComDll.tlb
├── lazcomlib_1_0_tlb.pas
└── lazcomunit.pas
├── LazComDllApp
├── LazComDllApp.lpi
├── LazComDllApp.lpr
├── LazComDllApp.lps
├── comobjunit.pas
├── lazcomlib_1_0_tlb.pas
└── mainunit.pas
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | __history
2 | backup
3 | /LazComDll/lib
4 | /LazComDll/LazComDll.dll
5 | /LazComDllApp/lib
6 | /LazComDllApp/LazComDllApp.exe
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 MartinTrummer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/LazComDll/LazComDll.lpi:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/LazComDll/LazComDll.lpr:
--------------------------------------------------------------------------------
1 | library LazComDll;
2 |
3 | {$mode objfpc}{$H+}
4 |
5 | uses
6 | Classes
7 | { you can add units after this }
8 | , LazComLib_1_0_TLB
9 | , ComServ, LazComUnit;
10 |
11 | {$R *.TLB}
12 |
13 | exports
14 | DllGetClassObject,
15 | DllCanUnloadNow,
16 | DllRegisterServer,
17 | DllUnregisterServer;
18 |
19 | begin
20 |
21 | end.
22 |
23 |
--------------------------------------------------------------------------------
/LazComDll/LazComDll.lps:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/LazComDll/LazComDll.ridl:
--------------------------------------------------------------------------------
1 | // ************************************************************************ //
2 | // WARNING
3 | // -------
4 | // This file is generated by the Type Library importer or Type Libary Editor.
5 | // Barring syntax errors, the Editor will parse modifications made to the file.
6 | // However, when applying changes via the Editor this file will be regenerated
7 | // and comments or formatting changes will be lost.
8 | // ************************************************************************ //
9 | // File generated on 19/11/2014 15:56:50 (- $Rev: 12980 $, 23204571).
10 |
11 | [
12 | uuid(570A55B0-1122-49AE-A335-1F630EC4FE65),
13 | version(1.0)
14 |
15 | ]
16 | library LazComLib
17 | {
18 |
19 | importlib("stdole2.tlb");
20 |
21 | interface ILazCom;
22 | coclass LazComCoClass;
23 |
24 |
25 | [
26 | uuid(247EAD48-16D6-4C1C-9265-F841BF4BD411),
27 | dual,
28 | oleautomation
29 | ]
30 | interface ILazCom: IDispatch
31 | {
32 | };
33 |
34 | [
35 | uuid(C5B9D6F8-76A4-4D4A-A40C-CA718637C07B)
36 | ]
37 | coclass LazComCoClass
38 | {
39 | [default] interface ILazCom;
40 | };
41 |
42 | };
43 |
--------------------------------------------------------------------------------
/LazComDll/LazComDll.tlb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MartinTrummer/lazarus-com-example/9db9ad7dbfdcbcc0d82db05b31fea2473b78f9c5/LazComDll/LazComDll.tlb
--------------------------------------------------------------------------------
/LazComDll/lazcomlib_1_0_tlb.pas:
--------------------------------------------------------------------------------
1 | Unit LazComLib_1_0_TLB;
2 |
3 | // Imported LazComLib on 19/11/2014 15:59:16 from D:\_development\Lazarus\LazComDll\LazComDll.tlb
4 |
5 | {$mode delphi}{$H+}
6 |
7 | interface
8 |
9 | Uses
10 | Windows,ActiveX,Classes,Variants;
11 | Const
12 | LazComLibMajorVersion = 1;
13 | LazComLibMinorVersion = 0;
14 | LazComLibLCID = 0;
15 | LIBID_LazComLib : TGUID = '{570A55B0-1122-49AE-A335-1F630EC4FE65}';
16 |
17 | IID_ILazCom : TGUID = '{247EAD48-16D6-4C1C-9265-F841BF4BD411}';
18 | CLASS_LazComCoClass : TGUID = '{93E11168-E984-415C-ACD6-853226D22CF9}';
19 |
20 | //Enums
21 |
22 | //Forward declarations
23 |
24 | Type
25 | ILazCom = interface;
26 | ILazComDisp = dispinterface;
27 |
28 | //Map CoClass to its default interface
29 |
30 | LazComCoClass = ILazCom;
31 |
32 | //records, unions, aliases
33 |
34 |
35 | //interface declarations
36 |
37 | // ILazCom :
38 |
39 | ILazCom = interface(IDispatch)
40 | ['{247EAD48-16D6-4C1C-9265-F841BF4BD411}']
41 | // LazComMethod :
42 | procedure LazComMethod;safecall;
43 | end;
44 |
45 |
46 | // ILazCom :
47 |
48 | ILazComDisp = dispinterface
49 | ['{247EAD48-16D6-4C1C-9265-F841BF4BD411}']
50 | // LazComMethod :
51 | procedure LazComMethod;dispid 201;
52 | end;
53 |
54 | //CoClasses
55 | CoLazComCoClass = Class
56 | Public
57 | Class Function Create: ILazCom;
58 | Class Function CreateRemote(const MachineName: string): ILazCom;
59 | end;
60 |
61 | implementation
62 |
63 | uses comobj;
64 |
65 | Class Function CoLazComCoClass.Create: ILazCom;
66 | begin
67 | Result := CreateComObject(CLASS_LazComCoClass) as ILazCom;
68 | end;
69 |
70 | Class Function CoLazComCoClass.CreateRemote(const MachineName: string): ILazCom;
71 | begin
72 | Result := CreateRemoteComObject(MachineName,CLASS_LazComCoClass) as ILazCom;
73 | end;
74 |
75 | end.
76 |
--------------------------------------------------------------------------------
/LazComDll/lazcomunit.pas:
--------------------------------------------------------------------------------
1 | unit LazComUnit;
2 |
3 | {$mode objfpc}{$H+}
4 |
5 | interface
6 |
7 | uses
8 | ComObj, LazComLib_1_0_TLB;
9 |
10 | type
11 |
12 | { TLazCom }
13 | TLazCom = class(TAutoObject, ILazCom)
14 | public
15 | procedure LazComMethod;safecall;
16 | end;
17 |
18 | implementation
19 |
20 | uses
21 | comserv;
22 |
23 | { TLazCom }
24 |
25 | procedure TLazCom.LazComMethod; safecall;
26 | begin
27 | WriteLn('LazComMethod called');
28 | end;
29 |
30 |
31 | initialization
32 | TAutoObjectFactory.Create(ComServer, TLazCom, CLASS_LazComCoClass,
33 | ciMultiInstance, tmApartment);
34 |
35 | end.
36 |
37 |
--------------------------------------------------------------------------------
/LazComDllApp/LazComDllApp.lpi:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/LazComDllApp/LazComDllApp.lpr:
--------------------------------------------------------------------------------
1 | program LazComDllApp;
2 |
3 | {$mode objfpc}{$H+}
4 |
5 | uses
6 | {$IFDEF UNIX}{$IFDEF UseCThreads}
7 | cthreads,
8 | {$ENDIF}{$ENDIF}
9 | Classes, SysUtils, CustApp, ComObjUnit, LazComLib_1_0_TLB
10 | { you can add units after this };
11 |
12 | type
13 |
14 | { TLazComDll }
15 |
16 | TLazComDll = class(TCustomApplication)
17 | protected
18 | procedure DoRun; override;
19 | public
20 | constructor Create(TheOwner: TComponent); override;
21 | destructor Destroy; override;
22 | procedure WriteHelp; virtual;
23 | end;
24 |
25 | { TLazComDll }
26 |
27 | procedure TLazComDll.DoRun;
28 | var
29 | ErrorMsg: String;
30 | begin
31 | // quick check parameters
32 | ErrorMsg:=CheckOptions('h','help');
33 | if ErrorMsg<>'' then begin
34 | ShowException(Exception.Create(ErrorMsg));
35 | Terminate;
36 | Exit;
37 | end;
38 |
39 | // parse parameters
40 | if HasOption('h','help') then begin
41 | WriteHelp;
42 | Terminate;
43 | Exit;
44 | end;
45 |
46 | UseComObj();
47 |
48 | // stop program loop
49 | Terminate;
50 | end;
51 |
52 | constructor TLazComDll.Create(TheOwner: TComponent);
53 | begin
54 | inherited Create(TheOwner);
55 | StopOnException:=True;
56 | end;
57 |
58 | destructor TLazComDll.Destroy;
59 | begin
60 | inherited Destroy;
61 | end;
62 |
63 | procedure TLazComDll.WriteHelp;
64 | begin
65 | { add your help code here }
66 | writeln('Usage: ',ExeName,' -h');
67 | end;
68 |
69 | var
70 | Application: TLazComDll;
71 | begin
72 | Application:=TLazComDll.Create(nil);
73 | Application.Title:='Lazarus Com Dll App';
74 | Application.Run;
75 | Application.Free;
76 | end.
77 |
78 |
--------------------------------------------------------------------------------
/LazComDllApp/LazComDllApp.lps:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/LazComDllApp/comobjunit.pas:
--------------------------------------------------------------------------------
1 | unit ComObjUnit;
2 |
3 | {$mode objfpc}{$H+}
4 |
5 | interface
6 |
7 | uses
8 | Classes, SysUtils, LazComLib_1_0_TLB;
9 |
10 | procedure UseComObj();
11 |
12 | implementation
13 |
14 | procedure UseComObj();
15 | var
16 | LazCom: ILazCom;
17 | begin
18 | WriteLn('creating the com object');
19 | LazCom := CoLazComCoClass.Create();
20 | WriteLn('calling the com method:');
21 | LazCom.LazComMethod();
22 | WriteLn('done');
23 | end;
24 |
25 | end.
26 |
27 |
--------------------------------------------------------------------------------
/LazComDllApp/lazcomlib_1_0_tlb.pas:
--------------------------------------------------------------------------------
1 | Unit LazComLib_1_0_TLB;
2 |
3 | // Imported LazComLib on 19/11/2014 16:19:46 from D:\_development\Lazarus\LazComDll\LazComDll.dll
4 |
5 | {$mode delphi}{$H+}
6 |
7 | interface
8 |
9 | Uses
10 | Windows,ActiveX,Classes,Variants;
11 | Const
12 | LazComLibMajorVersion = 1;
13 | LazComLibMinorVersion = 0;
14 | LazComLibLCID = 0;
15 | LIBID_LazComLib : TGUID = '{570A55B0-1122-49AE-A335-1F630EC4FE65}';
16 |
17 | IID_ILazCom : TGUID = '{247EAD48-16D6-4C1C-9265-F841BF4BD411}';
18 | CLASS_LazComCoClass : TGUID = '{93E11168-E984-415C-ACD6-853226D22CF9}';
19 |
20 | //Enums
21 |
22 | //Forward declarations
23 |
24 | Type
25 | ILazCom = interface;
26 | ILazComDisp = dispinterface;
27 |
28 | //Map CoClass to its default interface
29 |
30 | LazComCoClass = ILazCom;
31 |
32 | //records, unions, aliases
33 |
34 |
35 | //interface declarations
36 |
37 | // ILazCom :
38 |
39 | ILazCom = interface(IDispatch)
40 | ['{247EAD48-16D6-4C1C-9265-F841BF4BD411}']
41 | // LazComMethod :
42 | procedure LazComMethod;safecall;
43 | end;
44 |
45 |
46 | // ILazCom :
47 |
48 | ILazComDisp = dispinterface
49 | ['{247EAD48-16D6-4C1C-9265-F841BF4BD411}']
50 | // LazComMethod :
51 | procedure LazComMethod;dispid 201;
52 | end;
53 |
54 | //CoClasses
55 | CoLazComCoClass = Class
56 | Public
57 | Class Function Create: ILazCom;
58 | Class Function CreateRemote(const MachineName: string): ILazCom;
59 | end;
60 |
61 | implementation
62 |
63 | uses comobj;
64 |
65 | Class Function CoLazComCoClass.Create: ILazCom;
66 | begin
67 | Result := CreateComObject(CLASS_LazComCoClass) as ILazCom;
68 | end;
69 |
70 | Class Function CoLazComCoClass.CreateRemote(const MachineName: string): ILazCom;
71 | begin
72 | Result := CreateRemoteComObject(MachineName,CLASS_LazComCoClass) as ILazCom;
73 | end;
74 |
75 | end.
76 |
--------------------------------------------------------------------------------
/LazComDllApp/mainunit.pas:
--------------------------------------------------------------------------------
1 | unit MainUnit;
2 |
3 | {$mode objfpc}{$H+}
4 |
5 | interface
6 |
7 | uses
8 | Classes, SysUtils;
9 |
10 | implementation
11 |
12 | end.
13 |
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | lazarus-com-example
2 | ===================
3 |
4 | example project to test COM programming in the Lazarus IDE
5 |
6 | # Goal
7 | The goal of this example is to document how you can use the free Lazarus IDE to create a DLL that contains a COM object and its type library. So that you can use the COM object easily: i.e. use regsvr32 to register the COM object, read the type library from the DLL and thus use the COM object in any application.
8 |
9 | We will build 2 projects:
10 |
11 | 1. Dll Project (LazComDll): this project will create the DLL file that includes the COM object
12 | 2. Exe Project (LazComDllApp): this project will create an EXE file which will use the registered COM object (in the DLL) and call a method on it
13 |
14 | ## System description
15 | - Windows® 7 SP1 64 bit
16 | - Lazarus IDE 32 bit: http://www.lazarus.freepascal.org/
17 | - Version #: 1.2.6
18 | - Date: 2014-10-11
19 | - FPC: Version 2.6.4
20 | - SVN Revision: 46529
21 | - i386-win32-win32/win64
22 | - LazActiveX: http://wiki.lazarus.freepascal.org/LazActiveX/
23 | - required to import type libraries
24 |
25 | ## Dll Project
26 | ### Type Library
27 | The first thing that we need is the type library. I could not find out how to build a type library in Lazarus, thus I have created one in Delphi (Does anyone know a simpler alternative or even a Lazarus extension?)
28 |
29 | In Delphi it is easy to define the type library in a RIDL file and then generated the type library file
30 |
31 | ### Crate Lazarus Library Project
32 | The next step is to build a Lazarus project which will finally create a DLL file: File - New - Project - Library
33 |
34 | ### Import the type library
35 | Now we import the type library file: Tools - Import Type Library - select the *.tlb file.
36 | Lazarus will then create a new pascal file based on the definitions of the type library file.
37 |
38 | ### Include the type library as a resource in the DLL
39 | We want that the created DLL file includes the type library file as a resource, so that other programs can read and use the type library. This is easy to do in free Pascal: In the Lazarus project file, include the type library file as a resource:
40 | ```pascal
41 | {$R *.TLB}
42 | ```
43 |
44 | ### Export Functions
45 | In the same file, we will now define the functions that the DLL exports, so that users of the DLL can use the regsvr32.exe utility to register the COM object.
46 | - add ComServ to the uses clause
47 | - export the following functions:
48 | ```pascal
49 | exports
50 | DllGetClassObject,
51 | DllCanUnloadNow,
52 | DllRegisterServer,
53 | DllUnregisterServer;
54 | ```
55 |
56 | ### Implement the ComObject
57 | Now that the basic plumbing is done, we can implement the ComObject. In Lazarus: File - New - Unit: `LazComUnit`
58 |
59 | We keep it as simple as possible. The class is called `TLazCom` and it inherits from `TAutoObject` (in the ComObj unit) and implements the COM interface `ILazCom` that is defined in the type library: The one and only method of this interface/class will print a message to stdout.
60 |
61 | ```pascal
62 | uses
63 | ComObj, LazComLib_1_0_TLB;
64 |
65 | type
66 | { TLazCom }
67 | TLazCom = class(TAutoObject, ILazCom)
68 | public
69 | procedure LazComMethod;safecall;
70 | end;
71 |
72 | implementation
73 |
74 | { TLazCom }
75 |
76 | procedure TLazCom.LazComMethod; safecall;
77 | begin
78 | WriteLn('LazComMethod called');
79 | end;
80 | ```
81 |
82 | ### Create the Object Factory
83 | In the initialization part of the file, we will create the Object Factory (note: you must add `ComServ` to the uses list):
84 |
85 | ```pascal
86 | initialization
87 | TAutoObjectFactory.Create(ComServer, TLazCom, CLASS_LazComCoClass,
88 | ciMultiInstance, tmApartment);
89 | ```
90 |
91 | ### Build the DLL
92 | In Lazarus: Run - Build
93 | That's it: now we have a DLL that includes the type library and the implentation of our COM object. The DLL also exports some functions that can be used by the regsvr32 utility to register the COM object in the Windows® Registry.
94 |
95 | #### Register the COM object
96 | In a Windows® command prompt go to the directory where the DLL file is located and run the regsvr32 utility like this:
97 | ```Batchfile
98 | regsvr32 LazComDll.dll
99 | ```
100 | You should see an information message box saying: `DllRegisterServer in LazComDll.dll succeeded.`
101 |
102 | ## Exe Project
103 | The Exe project will be a simple console application.
104 |
105 | ### Create the console application
106 | In Lazarus: File - New… - Console Application
107 |
108 | ### Import the type library
109 | Now we import the type library file: Tools - Import Type Library - select our `LazComDll.dll` file (which includes the type library).
110 | Lazarus will then create a new pascal file based on the definitions of the type library file.
111 |
112 | ### Using the COM Object
113 | Create a new unit that will instantiate the COM object: In Lazarus: File - New - Unit: `ComObjUnit`
114 |
115 | ```pascal
116 | uses
117 | Classes, SysUtils, LazComLib_1_0_TLB;
118 |
119 | procedure UseComObj();
120 |
121 | implementation
122 |
123 | procedure UseComObj();
124 | var
125 | LazCom: ILazCom;
126 | begin
127 | WriteLn('creating the com object');
128 | LazCom := CoLazComCoClass.Create();
129 | WriteLn('calling the com method:');
130 | LazCom.LazComMethod();
131 | WriteLn('done');
132 | end;
133 | ```
134 |
135 | ### Execute the application
136 | In the console application project file, we call our function like this:
137 | ```pascal
138 | UseComObj();
139 | ```
140 |
141 | then build the project: Run - Build
142 |
143 | And start the exe in a Winodws® command prompt. You should see this output:
144 | ```
145 | creating the com object
146 | calling the com method:
147 | LazComMethod called
148 | done
149 | ```
150 |
151 | ----
152 | this document was created with the haroo-pad markdown editor: http://pad.haroopress.com/
153 |
--------------------------------------------------------------------------------