VCL/LCL – a form in DLL – no Application taskbar window, cannot minimize the main form - lazarus

I have one problem, and I tried to search a solution but can't achieve what I want. Sorry if that is actually simple, please just point me to correct way of how to do it.
So! I have a C program that is a loader. It must call my DLL written in Delphi or Lazarus (Free Pascal). The DLL is actually a standalone GUI application: during debugging I conditionally compile it as EXE and it working.
My build script compiles it as DLL with one entry point that must execute it just as it works standalone. I expect exactly the same behavior, but I can do some things different (especially setting the Application icon) if needed.
Loader is a console-style program but compiled without a console – no windows, no anything. It just loads DLL and calls a function.
Problem is that when I build even empty default project with one form as an EXE – it will actually have "master" Application (.Handle <> 0) window in taskbar. So I can set its title independently from main form caption.
But when the same thing is inside a DLL – there is no Application window (.Handle = 0), the title will be the form caption, but the most important bug: a form cannot be minimized!
In Delphi 7 it goes background under other windows (but taskbar thing stays!); in Lazarus it just minimizes to nowhere (hided, no way to restore anymore); both without any minimizing animation.
Other than that, my application seems to behave normally. This is only issue I have.
OK, I know that forms in libraries is a bad thing to do, but:
I’m fine to instantiate "another" VCL completely independent from host’s instance, maybe even in different thread.
There is no VCL in my particular host application! For me, it must work exactly as it will in EXE alone…
I searched something about Application.Handle in DLL, and now understand than I need to pass a handle to host’s Application object, so DLL will be joined with others host forms, but I have none! It’s even not Delphi… (and Application:=TApplication.Create(nil); didn’t help either)
Anything of following will probably help me:
A) How to instruct VCL to create a normal Application object for me? How it does it when in EXE, maybe I can copy that code?
B) How to create a suitable master window from C (proper styles, etc.) to pass it’s handle to DLL? Also, I believe, in Free Pascal there is no direct access to TApplication handle value, so I couldn’t probably assign it.
C) How to live without a taskbar window, but have my form (good news: my program has only one form!) to minimize correctly (or just somehow…)?
I now you all love to see some code, so here it is:
// default empty project code, produces valid working EXE:
program Project1;
uses Forms, Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
+
// that's how I tried to put it in a DLL:
library Project1;
uses Forms, Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
function entry(a, b, c, d: Integer): Integer; stdcall;
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
Result := 0;
end;
exports
entry;
begin
end.
I specially crafted entry() function to be callable with rundll32, just for testing.
Also, I tried to put the body directly to "begin end." initialization section – same wrong behavior.
// To call a DLL, this can be used:
program Project1;
function entry(a, b, c, d: Integer): Integer; stdcall; external 'Project1.dll';
begin
entry(0, 0, 0, 0);
end.
Also, CMD-command "rundll32 project1.dll entry" will run it instantly. (Yeah, that way I might get a handle that Rundll gives me, but it isn’t what I want anyway.)
Last notes: (a) the DLL must be compiled in Lazarus; actually first thing I thought that it is a bug in LCL, but now when tested in Delphi7 I see the same; and since Delphi case is more simpler and robust, I decided to put here that; (b) my C loader doesn’t call LoadLibrary, it uses TFakeDLL hack (that OBJ file was tweaked to work without Delphi wrapper) and loads my DLL from memory (so I don’t have a handle to DLL itself), but otherwise their behavior is the same.

Okay, thanks to #Sertac Akyuz, I tried with .ShowModal:
// working Delphi solution:
library Project1;
uses Forms, Dialogs, SysUtils, Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
function entry(a, b, c, d: Integer): Integer; stdcall;
begin
Result := 0;
Application.Initialize;
Form1 := TForm1.Create(nil);
try
Form1.ShowModal;
except
on e: Exception do
ShowMessage(e.message);
end;
Form1.Free;
end;
exports
entry;
begin
end.
There is still no Application window (taskbar title equal to form caption), but now my form can be successfully minimized (with system animation). Note that for EXE compilation I have to go default way with Application, because when I tried to create the form like this – it started to minimize to desktop (iconify) instead of the taskbar.
It works perfect in empty default Lazarus project too. But when I tried to implement it to my production program, it gave me "Disk Full" exception at .ShowModal!
That thing was frustrating me little earlier (and that’s why I got rid of modality altogether, tried it no more), but now I was determined enough to get the bottom of this.
And I found the problem! My build script doesn’t pass "-WG" ("Specify graphic type application") compiler option. Looks like something in LCL was using console-alike mode, and modality loop failed for some reason.
Then, I had another very confusing issue that I want to share. My form’s OnCreate was rather big and complex (even starting other threads), and some internal function give me access violation when tried to do some stuff with one of controls on the form. It looked like the control is not constructed yet, or the form itself…
Turns out that the actual call Form1:=TForm1.Create(nil); obviously will leave the global variable "Form1" unassigned during FormCreate event. The fix was simple: to add Form1:=Self; in the beginning of TForm1.FormCreate(Sender: TObject);
Now everything is working without any problems. I can even use other forms with a normal Form2.Show(); if I firstly add them to my entry() function, like Form2:=TForm2.Create(Form1);
(edit: minor note, if you would use Lazarus and try to run entry() function from any different thread than one that loaded DLL library itself – then you should put MainThreadID:=GetCurrentThreadId(); just above Application.Initialize;)
Yay, this question is solved!

Related

Communication with two application on Windows with DELPHI

I have two applications and would like the two to communicate texting when a release exception.
The problem is as follows:
in an application I use the function
Application.Handle
to grab the handle of the application.
And in my client I use:
ServerApplicationHandle: = FindWindow ('TForm1', 'Form1');
To know which application should I send the message, but both return different numbers, they would know tell me why?
As already explained (Main)Form and Application are two different things.
Since Delphi 2007 there is another behavior to note.
In dependency of Application.MainformOnTaskbar you are able (or not) to get the handle via Findwindow.
A little snipplet to show the different behavior
var
FW_ah, FW_mfh, ah, mfh: THandle;
Procedure Display(OnTask: Boolean);
begin
Application.MainFormOnTaskbar := OnTask;
ah := Application.Handle;
mfh := MainForm.Handle;
FW_ah := FindWindow(PChar(Application.ClassName), PChar(Application.Title));
FW_mfh := FindWindow(PChar(ClassName), PChar(Caption));
Showmessage(Format('ah: %d FW_ah: %d - mfh: %d FW_mfh: %d', [ah, FW_ah, mfh, FW_mfh]));
end;
begin
Display(true);
Display(false);
end;
Application.Handle is the window handle for the hidden window associated with the global Application object.
FindWindow('TForm1', 'Form1') will return the window handle of a top-level form in your application.
These are indeed not the same thing. You could, I suppose, use Form1.Handle instead of Application.Handle. However, you would need to be wary of window re-creation.
Frankly this doesn't sound like the best way to do inter-process communication. Perhaps you might consider sockets or named pipes.

Identify and intercept function call

I'm developing a launcher for a game.
Want to intercept game's call for a function that prints text.
I don't know whether the code that contains this function is dynamically linked or statically. So I dont even know the function name.
I did intercepted some windows-api calls of this game through microsoft Detours, Ninject and some others.
But this one is not in import table either.
What should I do to catch this function call? What profiler should be used? IDA? How this could be done?
EDIT:
Finally found function address. Thanks, Skino!
Tried to hook it with Detours, injected dll. Injected DllMain:
typedef int (WINAPI *PrintTextType)(char *, int, float , int);
static PrintTextType PrintText_Origin = NULL;
int WINAPI PrintText_Hooked(char * a, int b, float c, int d)
{
return PrintText_Origin(a, b, c , d);
}
HMODULE game_dll_base;
/* game_dll_base initialization goes here */
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if(fdwReason==DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hinstDLL);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
PrintText_Origin = (PrintTextType)((DWORD)game_dll_base + 0x6049B0);
DetourAttach((PVOID *)&PrintText_Origin , PrintText_Hooked);
DetourTransactionCommit();
}
}
It hooks as expected. Parameter a has text that should be displayed. But when calling original function return PrintText_Origin (a, b, c , d); application crashes(http://i46.tinypic.com/ohabm.png, http://i46.tinypic.com/dfeh4.png)
Original function disassembly:
http://pastebin.com/1Ydg7NED
After Detours:
http://pastebin.com/eM3L8EJh
EDIT2:
After Detours:
http://pastebin.com/GuJXtyad
PrintText_Hooked disassembly http://pastebin.com/FPRMK5qt w3_loader.dll is the injected dll
Im bad at ASM, please tell what can be wrong ?
Want to intercept game's call for a function that prints text.
You can use a debugger for the investigative phase. Either IDA, or even Visual Studio (in combination with e.g. HxD), should do. It should be relatively easy to identify the function using the steps below:
Identify a particular fragment of text whose printing you want to trace (e.g. Hello World!)
Break the game execution at any point before the game normally prints the fragment you identified above
Search for that fragment of text† (look for either Unicode or ANSI) in the game's memory. IDA will allow you to do that IIRC, as will the free HxD (Extras > Open RAM...)
Once the address of the fragment has been identified, set a break-on-access/read data breakpoint so the debugger will give you control the moment the game attempts to read said fragment (while or immediately prior to displaying it)
Resume execution, wait for the data breakpoint to trigger
Inspect the stack trace and look for a suitable candidate for hooking
Step through from the moment the fragment is read from memory until it is printed if you want to explore additional potential hook points
†provided text is not kept compressed (or, for whatever reason, encrypted) until the very last moment
Once you are done with the investigative phase and you have identified where you'd like to inject your hook, you have two options when writing your launcher:
If, based on the above exercise, you were able to identify an export/import after all, then use any API hooking techniques
EDIT Use Microsoft Detours, making sure that you first correctly identify the calling convention (cdecl, fastcall, stdcall) of the function you are trying to detour, and use that calling convention for both the prototype of the original as well as for the implementation of the dummy. See examples.
If not, you will have to
use the Debugging API to programatically load the game
compute the hook address based on your investigative phase (either as a hard-coded offset from the module base, or by looking for the instruction bytes around the hook site‡)
set a breakpoint
resume the process
wait for the breakpoint to trigger, do whatever you have to do
resume execution, wait for the next trigger etc. again, all done programatically by your launcher via the Debugging API.
‡to be able to continue to work with eventual patch releases of the game
At this stage it sounds like you don't have a notion of what library function you're trying to hook, and you've stated it's not (obviously at least) an imported external function in the import table which probably means that the function responsible for generating the text is likely located inside the .text of the application you are disassembling directly or loaded dynamically, the text generation (especially in a game) is likely a part of the application.
In my experience, this simplest way to find code that is difficult to trace such as this is by stopping the application shortly during or before/after text is displayed and using IDA's fabulous call-graph functionality to establish what is responsible for writing it out (use watches and breakpoints liberally!)
Look carefully to calls to CreateRemoteThread or any other commonly used dynamic loading mechanism if you have reason to believe this functionality might be provided by an exported function that isn't showing up in the import table.
I strongly advice against it but for the sake of completeness, you could also hook NtSetInformationThread in the system service dispatch table. here's a good dump of the table for different Windows versions here. If you want to get the index in the table yourself you can just disassemble the NtSetInformationThread export from ntdll.dll.

Delphi DllMain DLL_PROCESS_DETACH called before DLL_PROCESS_ATTACH

I'm having a lot of trouble dealing with a DLL I've written in Delphi. I've set up a DllMain function using the following code in the library:
begin
DllProc := DllMain;
end.
My DllMain procedure looks like this:
procedure DllMain(reason: Integer);
begin
if reason = DLL_PROCESS_DETACH then
OutputDebugString('DLL PROCESS DETACH')
else if reason = DLL_PROCESS_ATTACH then
OutputDebugString('DLL PROCESS ATTACH')
else if reason = DLL_THREAD_ATTACH then
OutputDebugString('DLL THREAD ATTACH')
else if reason = DLL_THREAD_DETACH then
OutputDebugString('DLL THREAD DETACH')
else
OutputDebugString('DllMain');
end;
What I'm finding is that DETACH seems to be called (twice?!) by a caller (that I don't control) before ATTACH is ever called. Is that even possible, or am I misunderstanding how this is supposed to work? My expectation would be that every ATTACH call would be met with a matching DETACH call, but that doesn't appear to be the case.
What's goin' on here?!
Unfortunately when begin is executed in your dll code, the OS has already called DllMain in your library. So when your DllProc := DllMain; statement executes it is already too late. The Delphi compiler does not allow user code to execute when the dll is attached to a process. The suggested workaround (if you can call that a workaround) is to call your own DllMain function yourself in a unit initalization section or in the library code:
begin
DllProc := DllMain;
DllMain(DLL_PROCESS_ATTACH);
end;
The relevant documentation:
Note: DLL_PROCESS_ATTACH is passed to the procedure only if the DLL's initialization code calls the procedure and specifies DLL_PROCESS_ATTACH as a parameter.
What I'm finding is that DETACH seems to be called (twice?!) by a caller (that I don't control) before ATTACH is ever called.
According to "Programming Windows 5th edition" by Petzold.
DLL_PROCESS_ATTACH gets called when the application starts and
DLL_THREAD_ATTACH when a new thread inside an attached application is started.
DLL_PROCESS_DETACH gets called when an application attached to your application quits.
DLL_THREAD_DETACH gets called when a thread inside an attached application quits.
Note that it is possible for DLL_THREAD_DETACH to be called without a corresponsing earlier DLL_THREAD_ATTACH.
This occurs when the thread was started prior to the application linking to the dll.
This mainly occurs when an application manually loads the dll using LoadLibrary instead of statically linking at compile time.

Use RegNotifyChangeKeyValue to monitor changes to a 64-bit key

I'm trying to use RegNotifyChangeKeyValue to monitor changes of a 64-bit registry key.
To open this key from a 32-bit application, we must add the access flag KEY_WOW64_64KEY.
Unfortunately I can't seem to be able to monitor changes to this key, only it's 32-bit counterpart.
I'm including a demo project along with the unit I'm using to implement registry monitoring. Download it here: RegMonitor
Steps to reproduce the problem:
Compile the program. Run it as administrator. Click the Start button.
Open regedit and navigate to
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
Add a new value there. RegMonitor will not detect any change.
Navigate to
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run
Add a new value there. RegMonitor will detect this change.
I've added the KEY_WOW64_64KEY access flag when opening the registry, but it still does not notify of any changes to correct key, only the Wow6432Node redirect.
Any idea if it's possible to use RegNotifyChangeKeyValue to monitor such key?
The following minimal example detects changes in the 64 bit view of the registry, from a 32 bit process. I don't know what's different about your program, but this code proves that a 32 bit program can indeed detect changes in both views.
I know this doesn't solve you problem, but I hope it helps steer you in the right direction.
program RegMonitor;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
procedure Main;
const
dwFilter: DWORD =
REG_NOTIFY_CHANGE_NAME or
REG_NOTIFY_CHANGE_ATTRIBUTES or
REG_NOTIFY_CHANGE_LAST_SET or
REG_NOTIFY_CHANGE_SECURITY;
var
Error: Integer;
key: HKEY;
begin
Error := RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
'Software\Microsoft\Windows\CurrentVersion\RunOnce',
0,
KEY_NOTIFY or KEY_WOW64_64KEY,
key
);
if Error<>ERROR_SUCCESS then
RaiseLastOSError(Error);
try
Error := RegNotifyChangeKeyValue(
key,
True,
dwFilter,
0,
False
);
if Error<>ERROR_SUCCESS then
RaiseLastOSError(Error);
Writeln('Change detected');
Readln;
finally
RegCloseKey(key);
end;
end;
begin
Main;
end.
Now, as for your program, it looks like there are lots of problems with it. But the fundamental problem, the one that means you are not notified of changes, is that your event is created incorrectly. You create it like this:
CreateEvent(Nil, True, False, 'RegistryChangeMonitorEvent')
but you need to create it like this
CreateEvent(nil, True, False, nil)
I've not delved into what the requirements are for this event, the documentation does not offer any clues. All I did was look for differences between your code and the code in the MSDN example.
Make that change to the event creation and you have enough to start receiving notifications. However, when I did that change, your program still did not work and failed with an AV. One of your objects was not created. However, I think those are pretty routine bugs that you can sort out for yourself.
I wonder why you are using KEY_ALL_ACCESS. Why don't you use KEY_NOTIFY when you open the key to be passed to RegNotifyChangeKeyValue? And when you try to build a report of what has changed in a key, why don't you use KEY_READ? Since you are not attempting to write ever, KEY_ALL_ACCESS is not appropriate. If you make these changes then you won't need to run as admin.

SCardEstablishContext hangs as a service

Why might SCardEstablishContext hang, never to return, when called from a service?
I have code that works fine on lots of Windows installations. It accesses a Cherry keyboard's Smart Card reader (6x44) to read data on a smart card. It works fine on most PCs it has been tried on. However, on some PCs, running in Spain with Spanish Windows, the SCardEstablishContext function never returns. I cannot work out why this might be. I have logging either side of it, but the log entry after it does not appear. I cannot then shut it down (the worker thread is getting stuck), and have to kill it.
Exactly the same thread code works fine if run from an application, and not a service. Giving the service login settings of a user instead of system makes no difference.
I've installed Spanish XP on a machine here, but it works just fine. The far end has the same Winscard.dll version as I have here (both at XP SP3 status). No errors are shown in the event log.
How might I work out what is going wrong, and what might be fixing it? (Delphi code below)
// based on code by Norbert Huettisch
function TPCSCConnector.Init: boolean;
var
RetVar: LongInt;
ReaderList: string;
ReaderListSize: integer;
v: array[0..MAXIMUM_SMARTCARD_READERS] of string;
i: integer;
begin
Result := false;
FNumReaders := 0;
{$IFDEF MJ_ONLY}
LogReport(leInformation, 'About to call SCardEstablishContext');
{$ENDIF}
RetVar := SCardEstablishContext(SCARD_SCOPE_USER, nil, nil, #FContext);
{$IFDEF MJ_ONLY}
// never gets to report this (and logging known good etc)
LogReport(leInformation, 'SCardEstablishContext result = ' + IntToStr(RetVar));
{$ENDIF}
if RetVar = SCARD_S_SUCCESS then
begin
There may be different reasons why the API function appears to hang, like a deadlock, or an invisible message box or dialog waiting for user input. You should try to get a stacktrace using WinDbg.
You should also make sure that you are trying to reproduce the bug in the same environment. Important points might be whether Fast User Switching is active and whether other users are logged on, also that there are the same device drivers and services running.

Resources