unit WinAllocation; // FPC misses AllocateHWnd and DeallocateHWnd which is used by several // libraries such as Midi... or DirWatch. // Since FPC 2.2.2 there are dummies in Classes that just raise RunTime exceptions. // To avoid those exceptions, include this unit AFTER Classes. // Maybe the dummies will be replaced by functional routines in the future.WinAllocation // // THESE FUNCTIONS ARE ONLY FOR COMPATIBILITY WITH SOME EXTERNAL WIN32 LIBS. // DO NOT USE THEM IN USDX CODE. // interface {$IFDEF FPC} {$MODE Delphi} {$ENDIF} uses Classes, Windows; function AllocateHWnd(Method: TWndMethod): HWND; procedure DeallocateHWnd(hWnd: HWND); implementation function AllocateHWndCallback(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var Msg: TMessage; MethodPtr: ^TWndMethod; begin FillChar(Msg, SizeOf(Msg), 0); Msg.msg := uMsg; Msg.wParam := wParam; Msg.lParam := lParam; MethodPtr := Pointer(GetWindowLongPtr(hwnd, GWL_USERDATA)); if Assigned(MethodPtr) then MethodPtr^(Msg); Result := DefWindowProc(hwnd, uMsg, wParam, lParam); end; function AllocateHWnd(Method: TWndMethod): HWND; var ClassExists: Boolean; WndClass, OldClass: TWndClass; MethodPtr: ^TMethod; begin Result := 0; // setup class-info FillChar(WndClass, SizeOf(TWndClass), 0); WndClass.hInstance := HInstance; // Important: do not enable AllocateHWndCallback before the msg-handler method is assigned, // otherwise race-conditions might occur WndClass.lpfnWndProc := @DefWindowProc; WndClass.lpszClassName:= 'USDXUtilWindowClass'; // check if class is already registered ClassExists := GetClassInfo(HInstance, WndClass.lpszClassName, OldClass); // create window-class shared by all windows created by AllocateHWnd() if (not ClassExists) or (@OldClass.lpfnWndProc <> @DefWindowProc) then begin if ClassExists then UnregisterClass(WndClass.lpszClassName, HInstance); if (RegisterClass(WndClass) = 0) then Exit; end; // create window Result := CreateWindowEx(WS_EX_TOOLWINDOW, WndClass.lpszClassName, '', DWORD(WS_POPUP), 0, 0, 0, 0, 0, 0, HInstance, nil); if (Result = 0) then Exit; // assign individual callback procedure to the window if Assigned(Method) then begin // TMethod contains two pointers but we can pass just one as USERDATA GetMem(MethodPtr, SizeOf(TMethod)); MethodPtr^ := TMethod(Method); SetWindowLongPtr(Result, GWL_USERDATA, LONG_PTR(MethodPtr)); end; // now enable AllocateHWndCallback for this window SetWindowLongPtr(Result, GWL_WNDPROC, LONG_PTR(@AllocateHWndCallback)); end; procedure DeallocateHWnd(hWnd: HWND); var MethodPtr: ^TMethod; begin if (hWnd <> 0) then begin MethodPtr := Pointer(GetWindowLongPtr(hWnd, GWL_USERDATA)); DestroyWindow(hWnd); if Assigned(MethodPtr) then FreeMem(MethodPtr); end; end; end.