I have a dll that is injected in a process and this dll contains a Form where i want use MessageBox() (or some other type of dialog) to alert the user about some operations.
Eg:
Application.MessageBox('successful operation!','Information',mb_Ok+mb_IconInformation);
Happens that everytime that this is showed, also is showed the icon of target application in Windows taskbar, and i not want this.
Then i want display these messages without show application icon in taskbar.
How make this?
In Delphi 7, Application.MessageBox() calls the Win32 API MessageBox() function specifying the Application.Handle as the owner window 1.
Inside a DLL, Application.Handle is 0 by default, so your MessageBox dialog is being displayed without an owner window assigned to it. That explains why it is able to appear on the Taskbar, as only a top-level unowned window (with the APP_EX_APPWINDOW extended style) can appear there.
So, the simplest solution is to call the Win32 API MessageBox() function yourself, specifying an owner HWND that belongs to the app you have injected your DLL into. Or, if you want to keep using Application.MessageBox(), assign such an HWND to the Application.Handle property after the DLL has been injected.
But either way, make sure the thread that is calling MessageBox() is attached to the message queue of the chosen owner HWND. If you are calling MessageBox() in a separate thread, use AttachThreadInput() to make that attachment before calling MessageBox(), and again to remove the attachment after MessageBox() exits.
1: In later Delphi versions, Application.MessageBox uses the Application.OnGetActiveFormHandle event, the Win32 GetActiveWindow() function, and the Win32 GetLastActivePopup() function (in that order) to find a suitable owner window before resorting to using the Application.Handle.
Related
I am using Delphi XE6 and VCL styles. I have main application and dlls. My main application has enabled runtime themes and I am using vcl style files. I did quite similar thing to my DLLs. I enabled runtime themes and added VCL.Themes, VCL.Styles under uses and resource file with VCL style file within it. When DLL is loaded I load VCL style from resources and set it for DLL gui. Main app and DLL are not built with runtime packages.
Now I have main app GUI styled with own style and DLL gui styled with own style too. This seems to work fine until...
When I click on button in my main app which event opens TPopupMenu it's styled with same style as DLL GUI instead of main app style. If I navigate through menu I get AV too and program crashes. Take a look at the attached image.
What am I doing wrong? The only workaround I currently see would be to make my own customized TPopupMenu derived from some other control.
As I promised I prepared simple demo program which is similar to my application. It consists of host application with own style and DLL with style added to resource. Run it and click on button Popup then try select something from popup. It will crash and stop in some StdWindowProc or something like that. Also if you go to window system menu (left top corner) when you try to select something from that menu you will notice that system menu is styled as DLL gui and crashes too. Link to rar file: dropbox.com/sh/f2jmbsmw18akpyg/AAA6SWdBmVhf6n6K-mvYLLmua?dl=0
Thanks for your help.
This is a fundamental problem with VCL styles and the way that they style menus. The styling is implemented with a process wide hook. Specifically a CBT hook installed by a call to SetWindowsHookEx from TCustomStyleEngine.CreateSysHook in the Vcl.Themes unit. In fact, the hook applies just to the GUI thread, but that is process wide in the sense that there is exactly one GUI thread in the process.
Since you have multiple instances of the VCL in your application (one in the DLL and one in the application), two hooks are installed. That is one too many. The hook installed most recently (the DLL as it happens) wins, and that's why the DLL menu styling infects your executable. And why you encounter an access violation. The DLL is trying to operate on a menu that belongs to the executable. And so, in spite of your best efforts, you've ended up with the DLL code accessing VCL objects from the host executable.
There's no simple way to work around this and support styles fully in both modules. What we have here is a fundamental consequence of the design. The system was not designed to support multiple VCL instances. If you wish to use VCL styles in multiple modules, then the designers expect you to use runtime packages.
I suppose that you might be able to get some traction by operating the DLL out of a completely different thread. That would involve loading the DLL from that different thread so that the VCL is initialized in the thread. And all calls to the DLL would have to be from that thread. And you'd need to run a message loop in that thread. It's possible that you might be able to make that work, but I doubt it. Even with all the provisos mentioned you still have to handle the fact that you have two GUI threads which presents all sorts of issues with the input queue handling.
Perhaps another approach would be to uninstall the hook from the DLL. So long as your DLL is not showing menus then you may well be able to get away with uninstalling that hook. It would disable styling for menus shown by the DLL, but perhaps that's acceptable.
This version of your DLL (after I simplified it somewhat also) uninstalls the hook.
library VCLStyleDLL;
{$R 'Style.res' 'Style.rc'}
uses
VCL.Styles,
VCL.Themes,
VCL.SysStyles; // to gain access to TSysPopupStyleHook
{$R *.res}
begin
TStyleManager.TrySetStyle('Glossy', false);
TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
end.
With this version of the DLL, the host executable does not suffer the problems your describe in your question.
As David says this is caused because each VCL instance install a hook to detect when a popup menu (#32768) is created. So there is two hook instances working at the same time.
As workaround you can disable the popupmenu style hook in the dll (or in the app) using the UnRegisterSysStyleHook function defined in the Vcl.SysStyles unit.
TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
I am using Delphi XE6 and VCL styles. I have main application and dlls. My main application has enabled runtime themes and I am using vcl style files. I did quite similar thing to my DLLs. I enabled runtime themes and added VCL.Themes, VCL.Styles under uses and resource file with VCL style file within it. When DLL is loaded I load VCL style from resources and set it for DLL gui. Main app and DLL are not built with runtime packages.
Now I have main app GUI styled with own style and DLL gui styled with own style too. This seems to work fine until...
When I click on button in my main app which event opens TPopupMenu it's styled with same style as DLL GUI instead of main app style. If I navigate through menu I get AV too and program crashes. Take a look at the attached image.
What am I doing wrong? The only workaround I currently see would be to make my own customized TPopupMenu derived from some other control.
As I promised I prepared simple demo program which is similar to my application. It consists of host application with own style and DLL with style added to resource. Run it and click on button Popup then try select something from popup. It will crash and stop in some StdWindowProc or something like that. Also if you go to window system menu (left top corner) when you try to select something from that menu you will notice that system menu is styled as DLL gui and crashes too. Link to rar file: dropbox.com/sh/f2jmbsmw18akpyg/AAA6SWdBmVhf6n6K-mvYLLmua?dl=0
Thanks for your help.
This is a fundamental problem with VCL styles and the way that they style menus. The styling is implemented with a process wide hook. Specifically a CBT hook installed by a call to SetWindowsHookEx from TCustomStyleEngine.CreateSysHook in the Vcl.Themes unit. In fact, the hook applies just to the GUI thread, but that is process wide in the sense that there is exactly one GUI thread in the process.
Since you have multiple instances of the VCL in your application (one in the DLL and one in the application), two hooks are installed. That is one too many. The hook installed most recently (the DLL as it happens) wins, and that's why the DLL menu styling infects your executable. And why you encounter an access violation. The DLL is trying to operate on a menu that belongs to the executable. And so, in spite of your best efforts, you've ended up with the DLL code accessing VCL objects from the host executable.
There's no simple way to work around this and support styles fully in both modules. What we have here is a fundamental consequence of the design. The system was not designed to support multiple VCL instances. If you wish to use VCL styles in multiple modules, then the designers expect you to use runtime packages.
I suppose that you might be able to get some traction by operating the DLL out of a completely different thread. That would involve loading the DLL from that different thread so that the VCL is initialized in the thread. And all calls to the DLL would have to be from that thread. And you'd need to run a message loop in that thread. It's possible that you might be able to make that work, but I doubt it. Even with all the provisos mentioned you still have to handle the fact that you have two GUI threads which presents all sorts of issues with the input queue handling.
Perhaps another approach would be to uninstall the hook from the DLL. So long as your DLL is not showing menus then you may well be able to get away with uninstalling that hook. It would disable styling for menus shown by the DLL, but perhaps that's acceptable.
This version of your DLL (after I simplified it somewhat also) uninstalls the hook.
library VCLStyleDLL;
{$R 'Style.res' 'Style.rc'}
uses
VCL.Styles,
VCL.Themes,
VCL.SysStyles; // to gain access to TSysPopupStyleHook
{$R *.res}
begin
TStyleManager.TrySetStyle('Glossy', false);
TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
end.
With this version of the DLL, the host executable does not suffer the problems your describe in your question.
As David says this is caused because each VCL instance install a hook to detect when a popup menu (#32768) is created. So there is two hook instances working at the same time.
As workaround you can disable the popupmenu style hook in the dll (or in the app) using the UnRegisterSysStyleHook function defined in the Vcl.SysStyles unit.
TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);
Delphi7 (cannot use latest). I want to replace (easy way, not making my form) MessageDlg calls with Vista style dialogs (must still work on old OS!). I need buttons Yes/No/YesToAll/NoToAll in this.
How to do it?
MessageBox isn't a way: I need all 4 buttons Yes/No/YesToAll/NoToAll in one form, or maybe checkbox instead of ToAll btns.
On Vista you use the native task dialog, TaskDialogIndirect. This has all the functionality you need. You'll need to translate the headers to Pascal, but if you don't fancy doing that yourself then you can use the JEDI header translations, for instance.
On XP and older there is no task dialog. There is no native system dialog with the functionality that you desire. Therefore you need to implement the dialog yourself. Create a Delphi TForm descendent. Add the necessary text, buttons, styling etc. Show it with ShowModal.
One of the issues with all this is that TaskDialogIndirect must be bound at runtime with GetProcAddress. In fact, use GetProcAddress to determine whether TaskDialogIndirect is available, and if not fall back to the XP code path.
If you don't want to build this yourself you can use one of the many extant libraries that offer such functionality. For instance: http://blog.synopse.info/post/2011/03/05/Open-Source-SynTaskDialog-unit-for-XP,Vista,Seven
i am developing an App for windows that will start some third party executable files such as cmd, paint, notepad etc using CreateProcess function. I want the functionality to hide and show the window of these EXE programs using HWND or suggest any other solution...
CreateProcess() does not return the HWND of the new process so you will have to find it manually. Use EnumWindows() and GetWindowThreadProcessId() to find HWNDs whose process/thread IDs match the same IDs that CreateProcess() returns in the PROCESS_INFORMATION struct. Once you have the HWNDs, you can use ShowWindow() to show/hide them as needed.
I'm trying to assign a ParentWindow, to a control created in a dll. The control is an editor, I need to process a text file, but this control requires a ParentWindow.
How can I solve this problem, if I create this control in a dll?
I'm using Delphi 5.
also create the TForm (maybe not Visible) inside the dll then the control and add it to the form
This is a common question, and the correct answer is "Don't do that".
The first question I have is "why do you feel the need to create a control in a DLL?" Why not just create it in code or include the control itself in your EXE?
Second, if you want to add a control to a separate binary, but it in a Package. Packages are designed specifically to make exporting controls simple and easy.
You need to get the parent window from somewhere! Typically the host application that loads and calls the DLL would supply a window handle. It looks like your DLL provides a custom control for an application, so of course the application needs to supply a parent window handle.
Also, you typically need a window handle to the entire application as well, which you set as Application.Handle before you do anything else in your DLL.
ok, thaks for your answers, i already solved (a few minutes before first answer).
first, i need explain why i don't embed, and that is because costumer ask me that way.
the solution is send my form handle to my dll as an argument, after testing that way, i got no errors...
only modificate the prototype of my procedure, to recieve a HWND as an argument, to ParentWindow prop of my control (created in memory).
that's all.