Sign in Join
Wiki copytemporary

Win32/64 Interface: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-*(Windows only)*
1+[![Windows logo - 2012.svg](https://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/Windows_logo_-_2012.svg/60px-Windows_logo_-_2012.svg.png)](</File:Windows_logo_-_2012.svg>)
22
3+This article applies to [Windows](</Category:Windows> "Category:Windows") only.
4+
5+See also: [[Multiplatform Programming Guide]]
6+
7+│ **English (en)** │ **[[Win32/64 Interface/ru|русский (ru)]]** │
8+
39## Introduction
410
5-The win32/64 interface is arguably the most polished and well developed interface of Lazarus, being also the most used one considering the number of downloads. Despite being the most complete, there are still some problems with it that need fixing.
11+The win32/64 interface is arguably the most polished and well developed interface of Lazarus, being also the most used one considering the number of downloads. Despite being the most complete, there are still some problems with it that need fixing.
612
7-Another important point about the win32/64 interface is that it is currently undergoing [[LCL Unicode Support|migration to unicode]].
13+Another important point about the win32/64 interface is that it is currently undergoing [[LCL Unicode Support|migration to unicode]].
814
9-Win64: please see warning [[Windows Programming Tips|here]] on not using certain FPC/Lazarus Win64 versions.
15+Win64: please see warning [[Windows Programming Tips|here]]> "Windows Programming Tips") on not using certain FPC/Lazarus Win64 versions.
1016
1117## Current issues
1218
1319### Scrolling
1420
15-The scrolling is currently done by moving child controls instead of the client area as the LCL expects. For example in some cases it looks as if the children are being scrolled in reverse. The truth is that the scrolling is pretty much broken. Scrolling the child controls is incompatible with the other widgetsets and also has this drawback: Moving one child after the other generates several move messages. The LCL receives the messages and has to react each time (for instance it has to realign all anchored children). For a single widgetset you can attempt to overcome this problem, but the solution will never work well for all the other widgetsets. This approach works for Delphi's VCL, but not for the LCL. Therefore another approach must be implemented:
21+The scrolling is currently done by moving child controls instead of the client area as the LCL expects. For example in some cases it looks as if the children are being scrolled in reverse. The truth is that the scrolling is pretty much broken. Scrolling the child controls is incompatible with the other widgetsets and also has this drawback: Moving one child after the other generates several move messages. The LCL receives the messages and has to react each time (for instance it has to realign all anchored children). For a single widgetset you can attempt to overcome this problem, but the solution will never work well for all the other widgetsets. This approach works for Delphi's VCL, but not for the LCL. Therefore another approach must be implemented:
1622
1723**Solution**
1824
19-A solution would be to insert a 'client area' window between each child's window and its parent window. The child windows are placed on the 'client area' window, and when the children are scrolled the 'client area' window gets moved instead. This is already done by the other widgetsets.
25+A solution would be to insert a 'client area' window between each child's window and its parent window. The child windows are placed on the 'client area' window, and when the children are scrolled the 'client area' window gets moved instead. This is already done by the other widgetsets.
2026
21-Mattias: I will implement this eventually, but my winapi interface knowledge is limited and I have a lot of other Lazarus tasks already, so I can't say when I will implement it.
27+Mattias: I will implement this eventually, but my winapi interface knowledge is limited and I have a lot of other Lazarus tasks already, so I can't say when I will implement it.
2228
2329**Related bug reports**
2430
25-- [10400](http://bugs.freepascal.org/view.php?id=10400)
26-- [10188](http://bugs.freepascal.org/view.php?id=10188)
27-- [10471](http://bugs.freepascal.org/view.php?id=10471)
28-- [10091](http://bugs.freepascal.org/view.php?id=10091)
31+ * [10400](<http://bugs.freepascal.org/view.php?id=10400>)
32+ * [10188](<http://bugs.freepascal.org/view.php?id=10188>)
33+ * [10471](<http://bugs.freepascal.org/view.php?id=10471>)
34+ * [10091](<http://bugs.freepascal.org/view.php?id=10091>)
2935
3036### Focus indication on themed controls
3137
32-Controls (TCheckBox, TButton, TRadioButton, etc) loose their focus indication when the application is using themes.
38+Controls (TCheckBox, TButton, TRadioButton, etc) loose their focus indication when the application is using themes.
3339
3440**Hints to solve**
3541
36-- According to Paul it isn't related to WM_PAINT
42+ * According to Paul it isn't related to WM_PAINT
3743
3844**Related bug reports**
3945
40-- <http://bugs.freepascal.org/view.php?id=10685>
46+ * <http://bugs.freepascal.org/view.php?id=10685>
4147
4248### Navigating controls with the arrow keys
4349
4450**Related bug reports**
4551
46-- <http://bugs.freepascal.org/view.php?id=10742>
52+ * <http://bugs.freepascal.org/view.php?id=10742>
4753
4854## Implementation details
4955
50-This list explains how specific parts of the LCL are implemented on the Win32 interface to help people find the appropriate code in it to do bug fixes.
56+This list explains how specific parts of the LCL are implemented on the Win32 interface to help people find the appropriate code in it to do bug fixes.
5157
5258### Background color of Standard Controls
5359
5460See also: [[Windows CE Development Notes|Windows_CE_Development_Notes#TRadioButton_and_TGroupBox]]
5561
56-One might notice that on Windows there is no implementation for TWSWin32WinControl.SetColor and neither does it have for most standard controls (GroupBox, RadioButton, CheckBox, etc), even thougth those controls can have their background color changed.
62+One might notice that on Windows there is no implementation for TWSWin32WinControl.SetColor and neither does it have for most standard controls (GroupBox, RadioButton, CheckBox, etc), even thougth those controls can have their background color changed.
5763
58-The reason is that this is implemented by handling a WM_CTLCOLOR* message. Most standard controls (GroupBox, RadioButton, CheckBox, etc) will send a WM_CTLCOLORSTATIC message. On this message one can set the background color and a handle to the brush used to paint the control must be returned.
64+The reason is that this is implemented by handling a WM_CTLCOLOR* message. Most standard controls (GroupBox, RadioButton, CheckBox, etc) will send a WM_CTLCOLORSTATIC message. On this message one can set the background color and a handle to the brush used to paint the control must be returned.
5965
60-Another important detail about this is that child controls have their messages sent to the WindowProc of their parent. So, if one has a Form with a GroupBox and a couple of CheckBoxes inside the GroupBox the messages of the GroupBox will go to the Form and the messages of the CheckBoxes will go to the GroupBox (including the WM_CTLCOLORSTATIC message). To overcome this the win32 widgetset uses SetWindowLong to reset the WindowProc of controls with child controls to our centralized WindowControl on win32callback.inc.
66+Another important detail about this is that child controls have their messages sent to the WindowProc of their parent. So, if one has a Form with a GroupBox and a couple of CheckBoxes inside the GroupBox the messages of the GroupBox will go to the Form and the messages of the CheckBoxes will go to the GroupBox (including the WM_CTLCOLORSTATIC message). To overcome this the win32 widgetset uses SetWindowLong to reset the WindowProc of controls with child controls to our centralized WindowControl on win32callback.inc.
6167
6268### TCheckListBox
6369
6470See also: [[Windows CE Development Notes|Windows_CE_Development_Notes#TCheckListBox]]
6571
66-- TWin32WSCustomCheckListBox implements some minimal methods
67-- TWin32WSCustomListBox implements handle creating and most methods
68-- TWin32CheckListBoxStrings is the main TStrings descendent for this class
72+ * TWin32WSCustomCheckListBox implements some minimal methods
73+ * TWin32WSCustomListBox implements handle creating and most methods
74+ * TWin32CheckListBoxStrings is the main TStrings descendent for this class
6975
70-On Windows, a TCheckListBox is a normal window of the class 'LISTBOX' which has the LBS_OWNERDRAWFIXED style set. When the listbox is created a WM_MEASUREITEM message will be sent, and after a WM_DRAWITEM message will be sent whenever an item needs to be painted. In the handler for this message a message LM_DRAWITEM message will be created.
76+On Windows, a TCheckListBox is a normal window of the class 'LISTBOX' which has the LBS_OWNERDRAWFIXED style set. When the listbox is created a WM_MEASUREITEM message will be sent, and after a WM_DRAWITEM message will be sent whenever an item needs to be painted. In the handler for this message a message LM_DRAWITEM message will be created.
7177
72-The LM_DRAWITEM message is then intercepted by TWin32WidgetSet.CallDefaultWndHandler and handled in it's internal function:
78+The LM_DRAWITEM message is then intercepted by TWin32WidgetSet.CallDefaultWndHandler and handled in it's internal function:
7379
74-procedure DrawCheckListBoxItem(CheckListBox: TCheckListBox; Data: PDrawItemStruct);
80+procedure DrawCheckListBoxItem(CheckListBox: TCheckListBox; Data: PDrawItemStruct);
7581
76-And here is the real code to paint the TCheckListBox items.
82+And here is the real code to paint the TCheckListBox items.
7783
78-Note: This is kind of ugly, maybe this code should be moved to the LCL so we have a generic code to paint items in case the widgetset doesn't do it itself.
84+Note: This is kind of ugly, maybe this code should be moved to the LCL so we have a generic code to paint items in case the widgetset doesn't do it itself.
7985
80-MSDN Docs about the LISTBOX:
86+MSDN Docs about the LISTBOX:
8187
82-- <http://msdn2.microsoft.com/en-us/library/bb775146(VS.85>).aspx
83-- <http://msdn2.microsoft.com/en-us/library/bb775149(VS.85>).aspx
88+ * <http://msdn2.microsoft.com/en-us/library/bb775146(VS.85).aspx>
89+ * <http://msdn2.microsoft.com/en-us/library/bb775149(VS.85).aspx>
8490
8591## FAQ
8692
8793### Processing user messages in your window
8894
89-write me
95+write me
9096
9197### Processing non-user messages in your window
9298
93-To have a custom processing of messages \<= WM_USER you should use SetWindowLong from the Windows unit. It will return the address of the current WndProc, so you can just have your WndProc like this:
94-
95-``` pascal
99+To have a custom processing of messages <= WM_USER you should use SetWindowLong from the Windows unit. It will return the address of the current WndProc, so you can just have your WndProc like this:
100+```
96101begin
97- if Msg = WM_COPYDATA then
98- ...
99- else CallOldWindowProc;
100-end;
102+ if Msg = WM_COPYDATA then
103+ ...
104+ else CallOldWindowProc;
105+ end;
101106```
102107
103-And you don't lose anything. With a clever code you can even use the same wndproc for any control, just take care to call the correct old wndproc in each case.
104-
105-#### Example
108+And you don't lose anything. With a clever code you can even use the same wndproc for any control, just take care to call the correct old wndproc in each case.
106109
107-By intercepting the WM_NCHITTEST message you can avoid dragging the window.
110+#### Examples
108111
109-Note: The part were the function interacts with "WM_NCHITTEST" has a very strange result in Windows XP. You will be unable to move the window. In Vista on the other hand, you still can. Commenting this section out seems to do no harm, and you are able to move the program's window in Windows XP.
112+By intercepting the WM_NCHITTEST message you can avoid dragging the window.
110113
111-``` pascal
114+Note: The part were the function interacts with "WM_NCHITTEST" has a very strange result in Windows XP. You will be unable to move the window. In Vista on the other hand, you still can. Commenting this section out seems to do no harm, and you are able to move the program's window in Windows XP.
115+```
112116uses
113- ...Windows...
114-...
115-var
116- PrevWndProc: WNDPROC;
117-...
118-function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;
119-begin
120- if uMsg=WM_NCHITTEST then
121- begin
122- result:=Windows.DefWindowProc(Ahwnd, uMsg, WParam, LParam); //not sure about this one
123- if result=windows.HTCAPTION then result:=windows.HTCLIENT;
124- exit;
125- end;
126- result:=CallWindowProc(PrevWndProc,Ahwnd, uMsg, WParam, LParam);
127-end;
117+ ...Windows...
118+ ...
119+ var
120+ PrevWndProc: WNDPROC;
121+ ...
122+ function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;
123+ begin
124+ if uMsg=WM_NCHITTEST then
125+ begin
126+ result:=Windows.DefWindowProc(Ahwnd, uMsg, WParam, LParam); //not sure about this one
127+ if result=windows.HTCAPTION then result:=windows.HTCLIENT;
128+ exit;
129+ end;
130+ result:=CallWindowProc(PrevWndProc,Ahwnd, uMsg, WParam, LParam);
131+ end;
132+
133+ //install our message handler
134+ procedure TForm1.FormCreate(Sender: TObject);
135+ begin
136+ PrevWndProc:=Windows.WNDPROC(SetWindowLongPtr(Self.Handle,GWL_WNDPROC,PtrUInt(@WndCallback)));
137+ end;
138+```
128139
129-//install our message handler
130-procedure TForm1.FormCreate(Sender: TObject);
131-begin
132- PrevWndProc:=Windows.WNDPROC(SetWindowLongPtr(Self.Handle,GWL_WNDPROC,PtrUInt(@WndCallback)));
133-end;
140+When there is no form (for example there is a necessity to receive windows messages in a custom component, things happen differently. The example shows how to detect if a device is connected or disconnected to the computer.
134141```
142+unit MyCustomControl;
143+
144+ {$mode ObjFPC}{$H+}
145+
146+ interface
147+
148+ uses
149+ {$ifdef windows}Windows, jwaWinUser, JwaDbt,{$endif}
150+ Classes, SysUtils, stdctrls, LCLIntf;
151+
152+ type
153+ TMyCustomControl = class(tcombobox)
154+ private
155+ procedure InitResources_1;
156+ procedure InitResources_2;
157+ protected
158+ procedure CreateWnd; override;
159+ procedure WndProcNew(var Message: TMessage);
160+ public
161+ destructor Destroy; override;
162+ end;
163+
164+ DEV_BROADCAST_HDR_DEVICE_TYPE = Cardinal;
165+
166+ DEV_BROADCAST_HDR = record
167+ dbch_size: Cardinal;
168+ dbch_devicetype: DEV_BROADCAST_HDR_DEVICE_TYPE;
169+ dbch_reserved: Cardinal;
170+ end;
171+
172+ DEV_BROADCAST_DEVICEINTERFACE_W = record
173+ dbcc_size: Cardinal;
174+ dbcc_devicetype: Cardinal;
175+ dbcc_reserved: Cardinal;
176+ dbcc_classguid: TGuid;
177+ dbcc_name: array[0..0] of WideChar;
178+ end;
179+
180+ const
181+ DBT_DEVTYP_DEVICEINTERFACE = $5;
182+ DEVICE_NOTIFY_WINDOW_HANDLE = $0;
183+ DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = $4;
184+ //THIS IS A GUI FOR USB
185+ GUID_DEVINTERFACE_USB_DEVICE: TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
186+
187+ var
188+ _dev: Dev_Broadcast_DeviceInterface_W;
189+ DevBlockRem: DEV_BROADCAST_HDR;
190+ NewHandle: HWND;
191+ {$ifdef windows}
192+ FDevNotify: HDEVNOTIFY;
193+ {$endif}
194+
195+ procedure Register;
196+
197+ implementation
198+
199+ {$ifdef windows}
200+ procedure TMyCustomControl.CreateWnd;
201+ begin
202+ inherited CreateWnd;
203+ //These two calls are equivalent like the have constructed here
204+ //USE ONLY ONE OF THEM !!!
205+ //Call this if you want define some type of resources, see documentation
206+ InitResources_1;
207+ //Call this if you want define Hardware resources
208+ // InitResources_2;
209+ end;
210+
211+ procedure TMyCustomControl.InitResources_1;
212+ begin
213+ NewHandle:= LCLIntf.AllocateHwnd(@WndProcNew);
214+ ZeroMemory(@_dev, sizeOf(Dev_Broadcast_DeviceInterface_W));
215+ with _dev do
216+ begin
217+ dbcc_size:=sizeOf(Dev_Broadcast_DeviceInterface_W);
218+ dbcc_devicetype:= DBT_DEVTYP_DEVICEINTERFACE;
219+ dbcc_reserved:=0;
220+ dbcc_classguid:= GUID_DEVINTERFACE_USB_DEVICE;
221+ dbcc_name:='';
222+ end;
223+ //Use "DEVICE_NOTIFY_ALL_INTERFACE_CLASSES" if you want catch all messages from all classes (ignore dbcc_classguid)
224+ FDevNotify:=RegisterDeviceNotification(NewHandle, @_dev, DEVICE_NOTIFY_WINDOW_HANDLE or DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
225+ Win32Check(FDevNotify <> nil);
226+ end;
227+
228+ procedure TMyCustomControl.InitResources_2;
229+ begin
230+ NewHandle := LCLIntf.AllocateHWnd(@WndProcNew);
231+ ZeroMemory(@DevBlockRem, sizeOf(DevBlockRem));
232+ DevBlockRem.dbch_size := sizeof(DEV_BROADCAST_HDR)+sizeof(DEV_BROADCAST_DEVICEINTERFACE_W);
233+ DevBlockRem.dbch_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
234+ DevBlockRem.dbch_reserved := 0;
235+ FDevNotify := nil;
236+ FDevNotify := RegisterDeviceNotification(NewHandle, @DevBlockRem, DEVICE_NOTIFY_WINDOW_HANDLE or DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
237+ Win32Check(FDevNotify <> nil);
238+ end;
239+
240+ destructor TMyCustomControl.Destroy;
241+ begin
242+ if FDevNotify <> nil then
243+ UnregisterDeviceNotification(FDevNotify);
244+ inherited;
245+ end;
246+
247+ procedure TMyCustomControl.WndProcNew(var Message: TMessage);
248+ var
249+ Description: string = '';
250+ begin
251+ case Message.Msg of
252+ WM_DEVICECHANGE: //for example
253+ begin
254+ Description := IntToHex(Message.wParam);
255+ case Message.wParam of
256+ DBT_DEVNODES_CHANGED : Description := Description + ' A device has been added to or removed from the system.';
257+ DBT_QUERYCHANGECONFIG : Description := Description + ' Permission is requested to change the current configuration (dock or undock).';
258+ DBT_CONFIGCHANGED : Description := Description + ' The current configuration has changed, due to a dock or undock.';
259+ DBT_CONFIGCHANGECANCELED : Description := Description + ' A request to change the current configuration (dock or undock) has been canceled.';
260+ DBT_DEVICEARRIVAL : Description := Description + ' A device or piece of media has been inserted and is now available.';
261+ DBT_DEVICEQUERYREMOVE : Description := Description + ' Permission is requested to remove a device or piece of media. Any application can deny this request and cancel the removal.';
262+ DBT_DEVICEQUERYREMOVEFAILED : Description := Description + ' A request to remove a device or piece of media has been canceled.';
263+ DBT_DEVICEREMOVEPENDING : Description := Description + ' A device or piece of media is about to be removed. Cannot be denied.';
264+ DBT_DEVICEREMOVECOMPLETE : Description := Description + ' A device or piece of media has been removed.';
265+ DBT_DEVICETYPESPECIFIC : Description := Description + ' A device-specific event has occurred.';
266+ DBT_CUSTOMEVENT : Description := Description + ' A custom event has occurred.';
267+ DBT_USERDEFINED : Description := Description + ' The meaning of this message is user-defined.';
268+ end; //case
269+
270+ if (Message.wParam and $8000)<> 0 Then { if the upper bit is set then header info follows}
271+ Begin
272+ Description := Description + '; Device Type = ' + IntToStr(PDEV_BROADCAST_HDR(Message.Lparam)^.dbch_deviceType);
273+ Case PDEV_BROADCAST_HDR(Message.Lparam)^.dbch_deviceType of
274+ 1 : Description := Description + ' : OEM, Mouse, Keyboards, optimistically';
275+ 2 : Description := Description + ' : Memory Device';
276+ 3 : Description := Description + ' : '+ String(Pwidechar(@PDEV_BROADCAST_PORT(Message.LParam)^.dbcp_name)); //USB COM ports usually send their names (for example you can get “COM5”)
277+ //Most USB devices send nothing but 5 (keyboards and mice, sound cards, wifi adapters, phones). Displays also send 5.
278+ end;
279+ end;
280+ writeln(Description);
281+ //Message.Result := 0; // Messagge handled
282+ end;
283+ end;
284+ end;
285+ {$endif}
286+
287+ procedure Register;
288+ begin
289+ RegisterComponents('Additional',[TMyCustomControl]);
290+ end;
291+
292+ end.
293+```
135294
295+
296+
297+## Other Interfaces
298+
299+ * [[Lazarus known issues \(things that will never be fixed\|Lazarus known issues (things that will never be fixed)]]> "Lazarus known issues \(things that will never be fixed\)") \- A list of interface compatibility issues
300+ * Win32/64 Interface \- The Windows API (formerly Win32 API) interface for Windows 95/98/Me/2000/XP/Vista/10, but not CE
301+ * [[Windows CE Interface]] \- For Pocket PC and Smartphones
302+ * [[Carbon Interface]] \- The Carbon 32 bit interface for macOS (deprecated; removed from macOS 10.15)
303+ * [[Cocoa Interface]] \- The Cocoa 64 bit interface for macOS
304+ * [[Qt Interface]] \- The Qt4 interface for Unixes, macOS, Windows, and Linux-based PDAs
305+ * [[Qt5 Interface]] \- The Qt5 interface for Unixes, macOS, Windows, and Linux-based PDAs
306+ * [[GTK1 Interface]] \- The gtk1 interface for Unixes, macOS (X11), Windows
307+ * [[GTK2 Interface]] \- The gtk2 interface for Unixes, macOS (X11), Windows
308+ * [[GTK3 Interface]] \- The gtk3 interface for Unixes, macOS (X11), Windows
309+ * [[fpGUI Interface]] \- Based on the fpGUI library, which is a cross-platform toolkit completely written in Object Pascal
310+ * [[Custom Drawn Interface]] \- A cross-platform LCL backend written completely in Object Pascal inside Lazarus. The Lazarus interface to Android.
311+
312+### Platform specific Tips
313+
314+ * [[Android Programming]] \- For Android smartphones and tablets
315+ * [[iPhone/iPod development]] \- About using Objective Pascal to develop iOS applications
316+ * [[FreeBSD Programming Tips]] \- FreeBSD programming tips
317+ * [[Linux Programming Tips]] \- How to execute particular programming tasks in Linux
318+ * [[macOS Programming Tips]] \- Lazarus tips, useful tools, Unix commands, and more...
319+ * [[WinCE Programming Tips]] \- Using the telephone API, sending SMSes, and more...
320+ * [[Windows Programming Tips]] \- Desktop Windows programming tips
321+
322+### Interface Development Articles
323+
324+ * [[Carbon interface internals]] \- If you want to help improving the Carbon interface
325+ * [[Windows CE Development Notes]] \- For Pocket PC and Smartphones
326+ * [[Adding a new interface]] \- How to add a new widget set interface
327+ * [[LCL Defines]] \- Choosing the right options to recompile LCL
328+ * [[LCL Internals]] \- Some info about the inner workings of the LCL
329+ * [[Cocoa Internals]] \- Some info about the inner workings of the Cocoa widgetset
330+
136331---
137-*From the Free Pascal wiki, page "Win32/64 Interface", as it stood on 2020-08-27 after a change by Paskal, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
138-Category: Lazarus
139-Category: Operating Systems and Platforms
140-Category: Windows
141-Category: Windows Widgetsets
332+*From the Free Pascal wiki, page "Win32/64 Interface", as the Internet Archive kept it on 2025-11-27, last changed on 2025-11-12. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history