View Issue Details

IDProjectCategoryView StatusLast Update
0018624LazarusLCLpublic2016-05-11 02:36
ReporterKrzysztof DibowskiAssigned ToOndrej Pokorny 
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
Product Version0.9.31 (SVN)Product Build 
Target VersionFixed in Version 
Summary0018624: TPopupMenu - Doesn't show on form from DLL
DescriptionHi,

I have form in DLL. When I assign TPopupMenu to any control (for example: ListBox), then it doesn't show on that form. Manuall call PopMenu1.Popup(10.10) doesn't work too.
I attached demo:
1. Compile project in "app" folder
2. Compile project in "dll" folder
3. Copy test.dll from "dll" to "app"
4. Run app.exe from "app" folder and click "Show DLL Form". On this form is ListBox with assigned PopupMenu but it doesn't show on right click.

Regards
Additional InformationLazarus 0.9.31 from SVN, revision 29203 (26-01-2011)
FPC 2.4.3
Windows 7 32 bit.
TagsNo tags attached.
Fixed in Revision52296-52298
LazTarget-
WidgetsetWin32/Win64
Attached Files
  • dll_popupmenu.zip (256,342 bytes)
  • popup_appHandle.patch (679 bytes)
    Index: lcl/interfaces/win32/win32wsmenus.pp
    ===================================================================
    --- lcl/interfaces/win32/win32wsmenus.pp	(revision 29236)
    +++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
    @@ -1451,6 +1451,9 @@
     begin
       MenuHandle := APopupMenu.Handle;
       AppHandle := TWin32WidgetSet(WidgetSet).AppHandle;
    +  if AppHandle = HWND(Nil) then
    +    if Assigned(Screen.ActiveCustomForm) then
    +      AppHandle := Screen.ActiveCustomForm.Handle;
       GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
       TrackPopupMenuEx(MenuHandle,
         lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
    
    popup_appHandle.patch (679 bytes)
  • FormInDll.patch (3,762 bytes)
    Index: lcl/forms.pp
    ===================================================================
    --- lcl/forms.pp	(revision 52283)
    +++ lcl/forms.pp	(working copy)
    @@ -975,6 +975,7 @@
         FActiveForm: TForm;
         FCursor: TCursor;
         FCursorMap: TMap;
    +    FOriginCustomForm:TFPList;
         FCustomForms: TFPList;
         FCustomFormsZOrdered: TFPList;
         FDefaultCursor: HCURSOR;
    @@ -985,6 +986,7 @@
         FDataModuleList: TFPList;
         FIconFont: TFont;
         FMenuFont: TFont;
    +    FSynchronizing:boolean;
         FScreenHandlers: array[TScreenNotification] of TMethodList;
         FLastActiveControl: TWinControl;
         FLastActiveCustomForm: TCustomForm;
    @@ -1049,6 +1051,8 @@
       public
         constructor Create(AOwner : TComponent); override;
         destructor Destroy; override;
    +    procedure SynchronizeBegin(Screen:TScreen);
    +    procedure SynchronizeEnd;
         function CustomFormIndex(AForm: TCustomForm): integer;
         function FormIndex(AForm: TForm): integer;
         function CustomFormZIndex(AForm: TCustomForm): integer;
    Index: lcl/include/screen.inc
    ===================================================================
    --- lcl/include/screen.inc	(revision 52283)
    +++ lcl/include/screen.inc	(working copy)
    @@ -66,6 +66,7 @@
       FMonitors := TMonitorList.Create;
       TStringlist(FFonts).Sorted := True;
       FCustomForms := TFPList.Create;
    +  FOriginCustomForm := TFPList.Create;
       FCustomFormsZOrdered := TFPList.Create;
       FFormList := TFPList.Create;
       FDataModuleList := TFPList.Create;
    @@ -99,6 +100,7 @@
       FreeThenNil(FDataModuleList);
       FreeThenNil(FFormList);
       FreeThenNil(FCustomForms);
    +  FreeThenNil(FOriginCustomForm);
       FreeThenNil(FCustomFormsZOrdered);
       FreeThenNil(FSaveFocusedList);
       FreeThenNil(FFonts);
    @@ -108,6 +110,21 @@
       inherited Destroy;
     end;
     
    +procedure TScreen.SynchronizeBegin(Screen:TScreen);
    +var i:integer;
    +begin
    + FSynchronizing:=true;
    + FOriginCustomForm.Assign(FCustomForms);
    + for i:=0 to screen.CustomFormCount-1 do
    +   AddForm(screen.CustomForms[i]);
    + FSynchronizing:=false;
    +end;
    +
    +procedure TScreen.SynchronizeEnd;
    +begin
    + FCustomForms.Assign(FOriginCustomForm);
    +end;
    +
     {------------------------------------------------------------------------------
       function TScreen.CustomFormIndex(AForm: TCustomForm): integer;
      ------------------------------------------------------------------------------}
    @@ -721,7 +738,7 @@
         FFormList.Add(AForm);
         Application.UpdateVisible;
       end;
    -  NotifyScreenFormHandler(snFormAdded,AForm);
    +  if not FSynchronizing then NotifyScreenFormHandler(snFormAdded,AForm);
     end;
     
     {------------------------------------------------------------------------------
    Index: lcl/interfaces/win32/win32wsmenus.pp
    ===================================================================
    --- lcl/interfaces/win32/win32wsmenus.pp	(revision 52283)
    +++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
    @@ -1565,7 +1565,7 @@
     class procedure TWin32WSPopupMenu.Popup(const APopupMenu: TPopupMenu; const X, Y: integer);
     var
       MenuHandle: HMENU;
    -  AppHandle: HWND;
    +  WinHandle: HWND;
     const
       lAlignment: array[TPopupAlignment, Boolean] of DWORD = (
                   { left-to-rght } { right-to-left }
    @@ -1579,11 +1579,12 @@
       );
     begin
       MenuHandle := APopupMenu.Handle;
    -  AppHandle := Win32WidgetSet.AppHandle;
    -  GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
    +  if APopupMenu.Owner=nil then raise exception.create('PopuMenu owner=nil');
    +  WinHandle:=(APopupMenu.Owner as TWinControl).Handle;
    +  GetWin32WindowInfo(WinHandle)^.PopupMenu := APopupMenu;
       TrackPopupMenuEx(MenuHandle,
         lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
    -    X, Y, AppHandle, nil);
    +    X, Y, WinHandle, nil);
     end;
     
     end.
    
    FormInDll.patch (3,762 bytes)
  • TestProjs.zip (137,453 bytes)
  • FormInDll2.patch (3,953 bytes)
    Index: lcl/forms.pp
    ===================================================================
    --- lcl/forms.pp	(revision 52283)
    +++ lcl/forms.pp	(working copy)
    @@ -975,6 +975,7 @@
         FActiveForm: TForm;
         FCursor: TCursor;
         FCursorMap: TMap;
    +    FOriginCustomForm:TFPList;
         FCustomForms: TFPList;
         FCustomFormsZOrdered: TFPList;
         FDefaultCursor: HCURSOR;
    @@ -985,6 +986,7 @@
         FDataModuleList: TFPList;
         FIconFont: TFont;
         FMenuFont: TFont;
    +    FSynchronizing:boolean;
         FScreenHandlers: array[TScreenNotification] of TMethodList;
         FLastActiveControl: TWinControl;
         FLastActiveCustomForm: TCustomForm;
    @@ -1049,6 +1051,8 @@
       public
         constructor Create(AOwner : TComponent); override;
         destructor Destroy; override;
    +    procedure SynchronizeBegin(Screen:TScreen);
    +    procedure SynchronizeEnd;
         function CustomFormIndex(AForm: TCustomForm): integer;
         function FormIndex(AForm: TForm): integer;
         function CustomFormZIndex(AForm: TCustomForm): integer;
    Index: lcl/include/screen.inc
    ===================================================================
    --- lcl/include/screen.inc	(revision 52283)
    +++ lcl/include/screen.inc	(working copy)
    @@ -66,6 +66,7 @@
       FMonitors := TMonitorList.Create;
       TStringlist(FFonts).Sorted := True;
       FCustomForms := TFPList.Create;
    +  FOriginCustomForm := TFPList.Create;
       FCustomFormsZOrdered := TFPList.Create;
       FFormList := TFPList.Create;
       FDataModuleList := TFPList.Create;
    @@ -99,6 +100,7 @@
       FreeThenNil(FDataModuleList);
       FreeThenNil(FFormList);
       FreeThenNil(FCustomForms);
    +  FreeThenNil(FOriginCustomForm);
       FreeThenNil(FCustomFormsZOrdered);
       FreeThenNil(FSaveFocusedList);
       FreeThenNil(FFonts);
    @@ -108,6 +110,29 @@
       inherited Destroy;
     end;
     
    +procedure TScreen.SynchronizeBegin(Screen:TScreen);
    +var i:integer;
    +begin
    + FSynchronizing:=true;
    + FOriginCustomForm.Assign(FCustomForms);
    + for i:=0 to screen.CustomFormCount-1 do
    +   AddForm(screen.CustomForms[i]);
    + FSynchronizing:=false;
    +end;
    +
    +procedure TScreen.SynchronizeEnd;
    +var Form:pointer;
    +begin
    + FSynchronizing:=true;
    + FCustomForms.Clear;
    + FCustomFormsZOrdered.Clear;
    + FFormList.Clear;
    + for Form in FOriginCustomForm do
    +   AddForm(TCustomForm(Form));
    + FOriginCustomForm.Clear;
    + FSynchronizing:=false;
    +end;
    +
     {------------------------------------------------------------------------------
       function TScreen.CustomFormIndex(AForm: TCustomForm): integer;
      ------------------------------------------------------------------------------}
    @@ -721,7 +746,7 @@
         FFormList.Add(AForm);
         Application.UpdateVisible;
       end;
    -  NotifyScreenFormHandler(snFormAdded,AForm);
    +  if not FSynchronizing then NotifyScreenFormHandler(snFormAdded,AForm);
     end;
     
     {------------------------------------------------------------------------------
    Index: lcl/interfaces/win32/win32wsmenus.pp
    ===================================================================
    --- lcl/interfaces/win32/win32wsmenus.pp	(revision 52283)
    +++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
    @@ -1565,7 +1565,7 @@
     class procedure TWin32WSPopupMenu.Popup(const APopupMenu: TPopupMenu; const X, Y: integer);
     var
       MenuHandle: HMENU;
    -  AppHandle: HWND;
    +  WinHandle: HWND;
     const
       lAlignment: array[TPopupAlignment, Boolean] of DWORD = (
                   { left-to-rght } { right-to-left }
    @@ -1579,11 +1579,12 @@
       );
     begin
       MenuHandle := APopupMenu.Handle;
    -  AppHandle := Win32WidgetSet.AppHandle;
    -  GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
    +  if APopupMenu.Owner=nil then raise exception.create('PopuMenu owner=nil');
    +  WinHandle:=(APopupMenu.Owner as TWinControl).Handle;
    +  GetWin32WindowInfo(WinHandle)^.PopupMenu := APopupMenu;
       TrackPopupMenuEx(MenuHandle,
         lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
    -    X, Y, AppHandle, nil);
    +    X, Y, WinHandle, nil);
     end;
     
     end.
    
    FormInDll2.patch (3,953 bytes)
  • FormInDll3.patch (3,990 bytes)
    Index: lcl/forms.pp
    ===================================================================
    --- lcl/forms.pp	(revision 52283)
    +++ lcl/forms.pp	(working copy)
    @@ -975,6 +975,7 @@
         FActiveForm: TForm;
         FCursor: TCursor;
         FCursorMap: TMap;
    +    FOriginCustomForm:TFPList;
         FCustomForms: TFPList;
         FCustomFormsZOrdered: TFPList;
         FDefaultCursor: HCURSOR;
    @@ -985,6 +986,7 @@
         FDataModuleList: TFPList;
         FIconFont: TFont;
         FMenuFont: TFont;
    +    FSynchronizing:boolean;
         FScreenHandlers: array[TScreenNotification] of TMethodList;
         FLastActiveControl: TWinControl;
         FLastActiveCustomForm: TCustomForm;
    @@ -1049,6 +1051,8 @@
       public
         constructor Create(AOwner : TComponent); override;
         destructor Destroy; override;
    +    procedure SynchronizeBegin(Screen:TScreen);
    +    procedure SynchronizeEnd;
         function CustomFormIndex(AForm: TCustomForm): integer;
         function FormIndex(AForm: TForm): integer;
         function CustomFormZIndex(AForm: TCustomForm): integer;
    Index: lcl/include/screen.inc
    ===================================================================
    --- lcl/include/screen.inc	(revision 52283)
    +++ lcl/include/screen.inc	(working copy)
    @@ -66,6 +66,7 @@
       FMonitors := TMonitorList.Create;
       TStringlist(FFonts).Sorted := True;
       FCustomForms := TFPList.Create;
    +  FOriginCustomForm := TFPList.Create;
       FCustomFormsZOrdered := TFPList.Create;
       FFormList := TFPList.Create;
       FDataModuleList := TFPList.Create;
    @@ -99,6 +100,7 @@
       FreeThenNil(FDataModuleList);
       FreeThenNil(FFormList);
       FreeThenNil(FCustomForms);
    +  FreeThenNil(FOriginCustomForm);
       FreeThenNil(FCustomFormsZOrdered);
       FreeThenNil(FSaveFocusedList);
       FreeThenNil(FFonts);
    @@ -108,6 +110,29 @@
       inherited Destroy;
     end;
     
    +procedure TScreen.SynchronizeBegin(Screen:TScreen);
    +var i:integer;
    +begin
    + FSynchronizing:=true;
    + FOriginCustomForm.Assign(FCustomForms);
    + for i:=0 to screen.CustomFormCount-1 do
    +   AddForm(screen.CustomForms[i]);
    + FSynchronizing:=false;
    +end;
    +
    +procedure TScreen.SynchronizeEnd;
    +var Form:pointer;
    +begin
    + FSynchronizing:=true;
    + FCustomForms.Clear;
    + FCustomFormsZOrdered.Clear;
    + FFormList.Clear;
    + for Form in FOriginCustomForm do
    +   AddForm(TCustomForm(Form));
    + FOriginCustomForm.Clear;
    + FSynchronizing:=false;
    +end;
    +
     {------------------------------------------------------------------------------
       function TScreen.CustomFormIndex(AForm: TCustomForm): integer;
      ------------------------------------------------------------------------------}
    @@ -721,7 +746,7 @@
         FFormList.Add(AForm);
         Application.UpdateVisible;
       end;
    -  NotifyScreenFormHandler(snFormAdded,AForm);
    +  if not FSynchronizing then NotifyScreenFormHandler(snFormAdded,AForm);
     end;
     
     {------------------------------------------------------------------------------
    Index: lcl/interfaces/win32/win32wsmenus.pp
    ===================================================================
    --- lcl/interfaces/win32/win32wsmenus.pp	(revision 52283)
    +++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
    @@ -1565,7 +1565,7 @@
     class procedure TWin32WSPopupMenu.Popup(const APopupMenu: TPopupMenu; const X, Y: integer);
     var
       MenuHandle: HMENU;
    -  AppHandle: HWND;
    +  WinHandle: HWND;
     const
       lAlignment: array[TPopupAlignment, Boolean] of DWORD = (
                   { left-to-rght } { right-to-left }
    @@ -1579,11 +1579,12 @@
       );
     begin
       MenuHandle := APopupMenu.Handle;
    -  AppHandle := Win32WidgetSet.AppHandle;
    -  GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
    +  if APopupMenu.Owner is TWinControl then WinHandle:=TWinControl(APopupMenu.Owner).Handle
    +                                     else WinHandle:=Win32WidgetSet.AppHandle;
    +  GetWin32WindowInfo(WinHandle)^.PopupMenu := APopupMenu;
       TrackPopupMenuEx(MenuHandle,
         lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
    -    X, Y, AppHandle, nil);
    +    X, Y, WinHandle, nil);
     end;
     
     end.
    
    FormInDll3.patch (3,990 bytes)

Relationships

related to 0007181 resolvedBart Broersma Problems using LCL in DLL 
related to 0015126 resolvedOndrej Pokorny Reparenting forms within a library 
related to 0022881 resolvedVincent Snijders Combobox loses inheritance information 

Activities

2011-01-28 13:02

 

dll_popupmenu.zip (256,342 bytes)

Tomasz Wieckowski

2011-01-28 15:02

reporter   ~0045544

I can propose a patch for this bug.

2011-01-28 15:03

 

popup_appHandle.patch (679 bytes)
Index: lcl/interfaces/win32/win32wsmenus.pp
===================================================================
--- lcl/interfaces/win32/win32wsmenus.pp	(revision 29236)
+++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
@@ -1451,6 +1451,9 @@
 begin
   MenuHandle := APopupMenu.Handle;
   AppHandle := TWin32WidgetSet(WidgetSet).AppHandle;
+  if AppHandle = HWND(Nil) then
+    if Assigned(Screen.ActiveCustomForm) then
+      AppHandle := Screen.ActiveCustomForm.Handle;
   GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
   TrackPopupMenuEx(MenuHandle,
     lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
popup_appHandle.patch (679 bytes)

Tomasz Wieckowski

2011-01-28 15:07

reporter   ~0045545

Attached.

Krzysztof Dibowski

2011-01-29 15:21

reporter   ~0045572

It works. Thanks! Can someone add this patch?

Juha Manninen

2011-11-20 12:35

developer   ~0054298

Can the patch be applied or does it require some bigger changes in DLL handling?

Zeljan Rikalo

2011-11-20 14:43

developer   ~0054303

hmmm...setting AppHandle just like that, I don't like it

Zeljan Rikalo

2011-11-22 08:14

developer   ~0054366

I would like that Paul or Vincent review this patch.

Zeljan Rikalo

2012-01-06 20:08

developer   ~0055518

Last edited: 2012-01-06 20:10

Finally I got to work everything with qtlcl (tested under qt-linux and qt-win32).
Forms in .so lib (dll) works w/o problems. Didn't commit yet changes to qt because waiting Den's feedback about strange thing with initialization section
of qt45.pas (anyway changes are pretty small :) ).
Anyway, point is that: library must be attached into running application event loop, so:
1.Widgetset SHOULD NOT create new instance of application (eg. QApplication_create() under qt).
2.Widgetset SHOULD NOT call application quit (eg. QApplication_quit()).
3.When we talk about lib, event filters should be attached to already running
application instance, but also they shuold be freed before library is unloaded.

UPDATE: calling such qtlcl library from gtk2 creates QApplication object - so it works w/o problems :)

Zeljan Rikalo

2012-01-09 17:07

developer   ~0055628

In the meantime I've fixed gtk2 behaviour and now I can say that qt (linux,win), gtk2 (linux) and win32 works fine ... didn't yet tested carbon and qt-carbon.

errno

2016-05-08 22:23

reporter  

FormInDll.patch (3,762 bytes)
Index: lcl/forms.pp
===================================================================
--- lcl/forms.pp	(revision 52283)
+++ lcl/forms.pp	(working copy)
@@ -975,6 +975,7 @@
     FActiveForm: TForm;
     FCursor: TCursor;
     FCursorMap: TMap;
+    FOriginCustomForm:TFPList;
     FCustomForms: TFPList;
     FCustomFormsZOrdered: TFPList;
     FDefaultCursor: HCURSOR;
@@ -985,6 +986,7 @@
     FDataModuleList: TFPList;
     FIconFont: TFont;
     FMenuFont: TFont;
+    FSynchronizing:boolean;
     FScreenHandlers: array[TScreenNotification] of TMethodList;
     FLastActiveControl: TWinControl;
     FLastActiveCustomForm: TCustomForm;
@@ -1049,6 +1051,8 @@
   public
     constructor Create(AOwner : TComponent); override;
     destructor Destroy; override;
+    procedure SynchronizeBegin(Screen:TScreen);
+    procedure SynchronizeEnd;
     function CustomFormIndex(AForm: TCustomForm): integer;
     function FormIndex(AForm: TForm): integer;
     function CustomFormZIndex(AForm: TCustomForm): integer;
Index: lcl/include/screen.inc
===================================================================
--- lcl/include/screen.inc	(revision 52283)
+++ lcl/include/screen.inc	(working copy)
@@ -66,6 +66,7 @@
   FMonitors := TMonitorList.Create;
   TStringlist(FFonts).Sorted := True;
   FCustomForms := TFPList.Create;
+  FOriginCustomForm := TFPList.Create;
   FCustomFormsZOrdered := TFPList.Create;
   FFormList := TFPList.Create;
   FDataModuleList := TFPList.Create;
@@ -99,6 +100,7 @@
   FreeThenNil(FDataModuleList);
   FreeThenNil(FFormList);
   FreeThenNil(FCustomForms);
+  FreeThenNil(FOriginCustomForm);
   FreeThenNil(FCustomFormsZOrdered);
   FreeThenNil(FSaveFocusedList);
   FreeThenNil(FFonts);
@@ -108,6 +110,21 @@
   inherited Destroy;
 end;
 
+procedure TScreen.SynchronizeBegin(Screen:TScreen);
+var i:integer;
+begin
+ FSynchronizing:=true;
+ FOriginCustomForm.Assign(FCustomForms);
+ for i:=0 to screen.CustomFormCount-1 do
+   AddForm(screen.CustomForms[i]);
+ FSynchronizing:=false;
+end;
+
+procedure TScreen.SynchronizeEnd;
+begin
+ FCustomForms.Assign(FOriginCustomForm);
+end;
+
 {------------------------------------------------------------------------------
   function TScreen.CustomFormIndex(AForm: TCustomForm): integer;
  ------------------------------------------------------------------------------}
@@ -721,7 +738,7 @@
     FFormList.Add(AForm);
     Application.UpdateVisible;
   end;
-  NotifyScreenFormHandler(snFormAdded,AForm);
+  if not FSynchronizing then NotifyScreenFormHandler(snFormAdded,AForm);
 end;
 
 {------------------------------------------------------------------------------
Index: lcl/interfaces/win32/win32wsmenus.pp
===================================================================
--- lcl/interfaces/win32/win32wsmenus.pp	(revision 52283)
+++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
@@ -1565,7 +1565,7 @@
 class procedure TWin32WSPopupMenu.Popup(const APopupMenu: TPopupMenu; const X, Y: integer);
 var
   MenuHandle: HMENU;
-  AppHandle: HWND;
+  WinHandle: HWND;
 const
   lAlignment: array[TPopupAlignment, Boolean] of DWORD = (
               { left-to-rght } { right-to-left }
@@ -1579,11 +1579,12 @@
   );
 begin
   MenuHandle := APopupMenu.Handle;
-  AppHandle := Win32WidgetSet.AppHandle;
-  GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
+  if APopupMenu.Owner=nil then raise exception.create('PopuMenu owner=nil');
+  WinHandle:=(APopupMenu.Owner as TWinControl).Handle;
+  GetWin32WindowInfo(WinHandle)^.PopupMenu := APopupMenu;
   TrackPopupMenuEx(MenuHandle,
     lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
-    X, Y, AppHandle, nil);
+    X, Y, WinHandle, nil);
 end;
 
 end.
FormInDll.patch (3,762 bytes)

errno

2016-05-08 22:24

reporter  

TestProjs.zip (137,453 bytes)

errno

2016-05-08 22:27

reporter   ~0092456

Last edited: 2016-05-10 10:37

View 5 revisions

the problem still exist in lazarus 1.7

here is a patch for lazarus 1.7 FormInDll.patch (SVN revision 52283) that should improve or resolve the problem .


-- I modify lcl/interfaces/win32/win32wsmenus as above without changing WidgetSet.apphandle .
-- I add two procedure to synchronise (synchronizeBegin and SynchronizeEnd) the screen variable in library and application . it is necessary for managing modal forms in dlls as the screen variable holds a list of forms to be enabled and disabled while using modal forms .

I joined an example in TestProjs.zip to show you how to use these two procedures . they can be used when the application and the dynamic library are both compiled with lazarus , because i pass the variable Screen pointer directly to the library and it is compatible only in that case .

Zeljan Rikalo

2016-05-10 12:21

developer   ~0092486

Probably Ondrey should look into this win32 specific stuff.

errno

2016-05-10 15:23

reporter  

FormInDll2.patch (3,953 bytes)
Index: lcl/forms.pp
===================================================================
--- lcl/forms.pp	(revision 52283)
+++ lcl/forms.pp	(working copy)
@@ -975,6 +975,7 @@
     FActiveForm: TForm;
     FCursor: TCursor;
     FCursorMap: TMap;
+    FOriginCustomForm:TFPList;
     FCustomForms: TFPList;
     FCustomFormsZOrdered: TFPList;
     FDefaultCursor: HCURSOR;
@@ -985,6 +986,7 @@
     FDataModuleList: TFPList;
     FIconFont: TFont;
     FMenuFont: TFont;
+    FSynchronizing:boolean;
     FScreenHandlers: array[TScreenNotification] of TMethodList;
     FLastActiveControl: TWinControl;
     FLastActiveCustomForm: TCustomForm;
@@ -1049,6 +1051,8 @@
   public
     constructor Create(AOwner : TComponent); override;
     destructor Destroy; override;
+    procedure SynchronizeBegin(Screen:TScreen);
+    procedure SynchronizeEnd;
     function CustomFormIndex(AForm: TCustomForm): integer;
     function FormIndex(AForm: TForm): integer;
     function CustomFormZIndex(AForm: TCustomForm): integer;
Index: lcl/include/screen.inc
===================================================================
--- lcl/include/screen.inc	(revision 52283)
+++ lcl/include/screen.inc	(working copy)
@@ -66,6 +66,7 @@
   FMonitors := TMonitorList.Create;
   TStringlist(FFonts).Sorted := True;
   FCustomForms := TFPList.Create;
+  FOriginCustomForm := TFPList.Create;
   FCustomFormsZOrdered := TFPList.Create;
   FFormList := TFPList.Create;
   FDataModuleList := TFPList.Create;
@@ -99,6 +100,7 @@
   FreeThenNil(FDataModuleList);
   FreeThenNil(FFormList);
   FreeThenNil(FCustomForms);
+  FreeThenNil(FOriginCustomForm);
   FreeThenNil(FCustomFormsZOrdered);
   FreeThenNil(FSaveFocusedList);
   FreeThenNil(FFonts);
@@ -108,6 +110,29 @@
   inherited Destroy;
 end;
 
+procedure TScreen.SynchronizeBegin(Screen:TScreen);
+var i:integer;
+begin
+ FSynchronizing:=true;
+ FOriginCustomForm.Assign(FCustomForms);
+ for i:=0 to screen.CustomFormCount-1 do
+   AddForm(screen.CustomForms[i]);
+ FSynchronizing:=false;
+end;
+
+procedure TScreen.SynchronizeEnd;
+var Form:pointer;
+begin
+ FSynchronizing:=true;
+ FCustomForms.Clear;
+ FCustomFormsZOrdered.Clear;
+ FFormList.Clear;
+ for Form in FOriginCustomForm do
+   AddForm(TCustomForm(Form));
+ FOriginCustomForm.Clear;
+ FSynchronizing:=false;
+end;
+
 {------------------------------------------------------------------------------
   function TScreen.CustomFormIndex(AForm: TCustomForm): integer;
  ------------------------------------------------------------------------------}
@@ -721,7 +746,7 @@
     FFormList.Add(AForm);
     Application.UpdateVisible;
   end;
-  NotifyScreenFormHandler(snFormAdded,AForm);
+  if not FSynchronizing then NotifyScreenFormHandler(snFormAdded,AForm);
 end;
 
 {------------------------------------------------------------------------------
Index: lcl/interfaces/win32/win32wsmenus.pp
===================================================================
--- lcl/interfaces/win32/win32wsmenus.pp	(revision 52283)
+++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
@@ -1565,7 +1565,7 @@
 class procedure TWin32WSPopupMenu.Popup(const APopupMenu: TPopupMenu; const X, Y: integer);
 var
   MenuHandle: HMENU;
-  AppHandle: HWND;
+  WinHandle: HWND;
 const
   lAlignment: array[TPopupAlignment, Boolean] of DWORD = (
               { left-to-rght } { right-to-left }
@@ -1579,11 +1579,12 @@
   );
 begin
   MenuHandle := APopupMenu.Handle;
-  AppHandle := Win32WidgetSet.AppHandle;
-  GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
+  if APopupMenu.Owner=nil then raise exception.create('PopuMenu owner=nil');
+  WinHandle:=(APopupMenu.Owner as TWinControl).Handle;
+  GetWin32WindowInfo(WinHandle)^.PopupMenu := APopupMenu;
   TrackPopupMenuEx(MenuHandle,
     lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
-    X, Y, AppHandle, nil);
+    X, Y, WinHandle, nil);
 end;
 
 end.
FormInDll2.patch (3,953 bytes)

errno

2016-05-10 15:26

reporter   ~0092494

Attached FormInDll2.patch , 2nd version of the patch
I just made minor changes to SynchronizeEnd .

errno

2016-05-10 17:26

reporter  

FormInDll3.patch (3,990 bytes)
Index: lcl/forms.pp
===================================================================
--- lcl/forms.pp	(revision 52283)
+++ lcl/forms.pp	(working copy)
@@ -975,6 +975,7 @@
     FActiveForm: TForm;
     FCursor: TCursor;
     FCursorMap: TMap;
+    FOriginCustomForm:TFPList;
     FCustomForms: TFPList;
     FCustomFormsZOrdered: TFPList;
     FDefaultCursor: HCURSOR;
@@ -985,6 +986,7 @@
     FDataModuleList: TFPList;
     FIconFont: TFont;
     FMenuFont: TFont;
+    FSynchronizing:boolean;
     FScreenHandlers: array[TScreenNotification] of TMethodList;
     FLastActiveControl: TWinControl;
     FLastActiveCustomForm: TCustomForm;
@@ -1049,6 +1051,8 @@
   public
     constructor Create(AOwner : TComponent); override;
     destructor Destroy; override;
+    procedure SynchronizeBegin(Screen:TScreen);
+    procedure SynchronizeEnd;
     function CustomFormIndex(AForm: TCustomForm): integer;
     function FormIndex(AForm: TForm): integer;
     function CustomFormZIndex(AForm: TCustomForm): integer;
Index: lcl/include/screen.inc
===================================================================
--- lcl/include/screen.inc	(revision 52283)
+++ lcl/include/screen.inc	(working copy)
@@ -66,6 +66,7 @@
   FMonitors := TMonitorList.Create;
   TStringlist(FFonts).Sorted := True;
   FCustomForms := TFPList.Create;
+  FOriginCustomForm := TFPList.Create;
   FCustomFormsZOrdered := TFPList.Create;
   FFormList := TFPList.Create;
   FDataModuleList := TFPList.Create;
@@ -99,6 +100,7 @@
   FreeThenNil(FDataModuleList);
   FreeThenNil(FFormList);
   FreeThenNil(FCustomForms);
+  FreeThenNil(FOriginCustomForm);
   FreeThenNil(FCustomFormsZOrdered);
   FreeThenNil(FSaveFocusedList);
   FreeThenNil(FFonts);
@@ -108,6 +110,29 @@
   inherited Destroy;
 end;
 
+procedure TScreen.SynchronizeBegin(Screen:TScreen);
+var i:integer;
+begin
+ FSynchronizing:=true;
+ FOriginCustomForm.Assign(FCustomForms);
+ for i:=0 to screen.CustomFormCount-1 do
+   AddForm(screen.CustomForms[i]);
+ FSynchronizing:=false;
+end;
+
+procedure TScreen.SynchronizeEnd;
+var Form:pointer;
+begin
+ FSynchronizing:=true;
+ FCustomForms.Clear;
+ FCustomFormsZOrdered.Clear;
+ FFormList.Clear;
+ for Form in FOriginCustomForm do
+   AddForm(TCustomForm(Form));
+ FOriginCustomForm.Clear;
+ FSynchronizing:=false;
+end;
+
 {------------------------------------------------------------------------------
   function TScreen.CustomFormIndex(AForm: TCustomForm): integer;
  ------------------------------------------------------------------------------}
@@ -721,7 +746,7 @@
     FFormList.Add(AForm);
     Application.UpdateVisible;
   end;
-  NotifyScreenFormHandler(snFormAdded,AForm);
+  if not FSynchronizing then NotifyScreenFormHandler(snFormAdded,AForm);
 end;
 
 {------------------------------------------------------------------------------
Index: lcl/interfaces/win32/win32wsmenus.pp
===================================================================
--- lcl/interfaces/win32/win32wsmenus.pp	(revision 52283)
+++ lcl/interfaces/win32/win32wsmenus.pp	(working copy)
@@ -1565,7 +1565,7 @@
 class procedure TWin32WSPopupMenu.Popup(const APopupMenu: TPopupMenu; const X, Y: integer);
 var
   MenuHandle: HMENU;
-  AppHandle: HWND;
+  WinHandle: HWND;
 const
   lAlignment: array[TPopupAlignment, Boolean] of DWORD = (
               { left-to-rght } { right-to-left }
@@ -1579,11 +1579,12 @@
   );
 begin
   MenuHandle := APopupMenu.Handle;
-  AppHandle := Win32WidgetSet.AppHandle;
-  GetWin32WindowInfo(AppHandle)^.PopupMenu := APopupMenu;
+  if APopupMenu.Owner is TWinControl then WinHandle:=TWinControl(APopupMenu.Owner).Handle
+                                     else WinHandle:=Win32WidgetSet.AppHandle;
+  GetWin32WindowInfo(WinHandle)^.PopupMenu := APopupMenu;
   TrackPopupMenuEx(MenuHandle,
     lAlignment[APopupMenu.Alignment, APopupMenu.IsRightToLeft] or lTrackButtons[APopupMenu.TrackButton],
-    X, Y, AppHandle, nil);
+    X, Y, WinHandle, nil);
 end;
 
 end.
FormInDll3.patch (3,990 bytes)

errno

2016-05-10 17:28

reporter   ~0092496

Last edited: 2016-05-10 17:55

View 3 revisions

Attached FormInDll3.patch , 3nd version of the patch

i have fixed some issues when PopupMenu.owner=nil or is not a window .

Ondrej Pokorny

2016-05-10 22:02

reporter   ~0092504

You may never share objects between the main application and the DLL unless you can be 100% that they share the same interfaces. This is not the case of LCL classes/objects. (E.g. your DLL has been generated with a different Lazarus version.) Therefore SynchronizeBegin/SynchronizeEnd cannot be used.

I adapted the popup menu patch from Tomasz Wieckowski.

Use this code to show a modal form from the DLL (change your code):

procedure ShowModalForm(ParentWindow: HWND);
begin
  Form1Dll:=TForm1Dll.Create(nil);
  Form1Dll.ParentFormHandle := ParentWindow;
  Form1Dll.ShowModal;
end;

 TForm1dll = class(TForm)
 public
   ParentFormHandle: HWND;
   procedure CreateParams(var Params: TCreateParams); override;
 end;

procedure TForm1dll.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  if ParentFormHandle<>0 then
    Params.WndParent := ParentFormHandle;
end;

procedure TForm1.Button1Click(Sender:TObject);
var
  DisabledList: TList;
begin
  DisabledList := Screen.DisableForms(nil, nil);
  try
    try
      ShowModalForm(Self.Handle);
    finally
      Screen.EnableForms(DisabledList);
    end;
  finally
    DisabledList.Free;
  end;
end;

I'll create a wiki page to show how to do that and add a link here.

Ondrej Pokorny

2016-05-10 22:27

reporter   ~0092506

See here: http://wiki.freepascal.org/Form_in_DLL

errno

2016-05-11 01:32

reporter   ~0092514

ok I just noticed you apply a patch on the SVN version.

Issue History

Date Modified Username Field Change
2011-01-28 12:59 Krzysztof Dibowski New Issue
2011-01-28 12:59 Krzysztof Dibowski Widgetset => Win32/Win64
2011-01-28 13:02 Krzysztof Dibowski File Added: dll_popupmenu.zip
2011-01-28 13:11 Vincent Snijders LazTarget => post 1.2
2011-01-28 13:11 Vincent Snijders Status new => acknowledged
2011-01-28 15:02 Tomasz Wieckowski Note Added: 0045544
2011-01-28 15:03 Tomasz Wieckowski File Added: popup_appHandle.patch
2011-01-28 15:07 Tomasz Wieckowski Note Added: 0045545
2011-01-29 15:21 Krzysztof Dibowski Note Added: 0045572
2011-11-19 01:59 Juha Manninen Relationship added related to 0015126
2011-11-20 12:33 Juha Manninen Relationship added related to 0007181
2011-11-20 12:35 Juha Manninen Note Added: 0054298
2011-11-20 14:43 Zeljan Rikalo Note Added: 0054303
2011-11-22 08:14 Zeljan Rikalo Note Added: 0054366
2012-01-06 20:08 Zeljan Rikalo Note Added: 0055518
2012-01-06 20:08 Zeljan Rikalo Status acknowledged => feedback
2012-01-06 20:10 Zeljan Rikalo Note Edited: 0055518
2012-01-09 17:07 Zeljan Rikalo Note Added: 0055628
2012-03-15 13:09 Vincent Snijders Status feedback => acknowledged
2012-09-14 19:57 Juha Manninen Relationship added related to 0022881
2013-09-03 12:07 Martin Friebe LazTarget post 1.2 => 1.4
2014-09-10 19:28 Juha Manninen LazTarget 1.4 => -
2016-05-08 22:23 errno File Added: FormInDll.patch
2016-05-08 22:24 errno File Added: TestProjs.zip
2016-05-08 22:27 errno Note Added: 0092456
2016-05-08 22:30 errno Note Edited: 0092456 View Revisions
2016-05-08 22:39 errno Note Edited: 0092456 View Revisions
2016-05-08 22:39 errno Note Edited: 0092456 View Revisions
2016-05-10 10:37 errno Note Edited: 0092456 View Revisions
2016-05-10 12:21 Zeljan Rikalo Note Added: 0092486
2016-05-10 15:23 errno File Added: FormInDll2.patch
2016-05-10 15:26 errno Note Added: 0092494
2016-05-10 17:26 errno File Added: FormInDll3.patch
2016-05-10 17:28 errno Note Added: 0092496
2016-05-10 17:30 errno Note Edited: 0092496 View Revisions
2016-05-10 17:55 errno Note Edited: 0092496 View Revisions
2016-05-10 22:02 Ondrej Pokorny Fixed in Revision => 52296-52298
2016-05-10 22:02 Ondrej Pokorny Note Added: 0092504
2016-05-10 22:02 Ondrej Pokorny Status acknowledged => resolved
2016-05-10 22:02 Ondrej Pokorny Resolution open => fixed
2016-05-10 22:02 Ondrej Pokorny Assigned To => Ondrej Pokorny
2016-05-10 22:27 Ondrej Pokorny Note Added: 0092506
2016-05-11 01:32 errno Note Added: 0092514