Delphi Keyboard Hook - delphi

I'm having an interesting problem implementing a global keyboard hook.
I wrote a dll which is used to set the hook and then an application (Delphi) which loads the dll and processes the results of the hook. This was done this afternoon on my PC at work and after some testing I figured it was working 100%.
I've just tested the same app and dll here at home and I'm not getting any errors, but the application does not appear to be getting any data either.
Both machines are WinXP, although my work machine is SP2 and this one is SP3.
Has there been some change in the Win32 API which would cause this to malfunction, or could the problem be related to some A/V / Spyware / MS Update that has been released recently?
I'm hoping somebody here will know of an obvious reason that this may happen before I spend hours debugging.
Thanks!

Actually some A/Vs don't like homemade hooks. I've got the same problem with my mouse hooker on some machines, and it doesn't depend on service pack version.

Yeah, I could. I haven't installed Delphi on this machine, but I think I might have to. I'm going for the low hanging fruit here. If there's an obvious answer, there's no need to go through all the trouble of debugging and hoping to find what might be the problem.
My first suspicion is that there's been a change in the API somewhere.
As I mentioned, this app works absolutely perfectly on my work machine.

Do you have a debugger on your home computer? Do you receive any messages via the hook at all?
Can it be that some other application is hooking, and don't pass the message on down the hook-chain?
BTW: I love virtual machines for this kind of testing. Keep a clean XP install. Install SP2, and test your application. Roll back to clean install again, and install SP3. Try your application again. This way you will know if its SP3, since there is nothing else to mess things up. I like to keep a set of snapshots around with different configurations.

Which kind of hook are you using? I once used the WH_CBT-type and encountered problems when certain other applications where running. One case I could trace back to Trillian, which seems to do also some kind of hooking (and maybe screws up).
Apart from that I am currently working on an application that uses the WH_KEYBOARD-hook and this works on SP2 and SP3 equally well. The MSDN also doesn't mention any service-pack related changes.
What you can do to trace the bug on your home machine:
make sure to check all result values of all system api calls (and use GetLastError in case of error)
provide some kind of debug output in case of error (e.g. as message box or to a text file)
optional: log some status messages so you know whats going on internally

One alternative is to use a low level keyboardhook. (Just a different param to SetWindowsHookEx). The hook is processed in the message loop of the registering thread, and thus does not need to inject a dll everywhere. And for some odd reason VirusScanners/Firewalls interfere much less with it. They often silently block dllinjection or normal keyboardhooks. Also removes the need to share the hHook across processes if you want it to work in older windows versions.
And if you abuse a keyboardhook to implement global hotkeys(Have seen that a lot) use RegisterHotkey/http://msdn.microsoft.com/en-us/library/ms646309.aspx) instead.

Related

Formerly working Matlab Compiler-based DLL suddenly cannot initialize

Update: It turned out that there was something with installing Delphi 10.4 CE that broke my app (thanks, DelphiCoder!); specifically, it was something in the Windows Registry that was broken. After using ProcessMonitor to ensure no Delphi 10.4 (aka 21.0) was being invoked, I ended up cleaning out the registry of all 10.4 references, rebuilding completely (not clear if this was needed or not), and lo and behold, it works again! I'm adding this update in case someone in a similar situation finds this question - remember to back up your registry first and be careful!
Original Post: I created several DLLs with Matlab Compiler 10 years ago, with C wrappers, to make them available with Delphi. Once I got them working, they always worked - until today! The code in the C wrapper initialization function in question is in the code box below; the "Could not initialize library" is printed to the console when I run my Delphi app.
mclmcrInitialize();
if (!mclInitializeApplication(NULL, 0)) {
fprintf(stderr, "Could not initialize application\n");
}
if (!libMyDllInitialize()) {
fprintf(stderr, "Could not initialize library\n");
}
The problem is that this has never happened before, over all the probably 10 years since we first wrote these! My machine has the correct version of the 32-bit 2021a MCR installed, as it has for several years; I've installed this on numerous machines from Windows XP up to Windows 10, The DLLs were last built 5 - 7 years ago; anyway, I don't have access to the Matlab compiler anymore. The only thing that has changed is my app, but not anywhere near where this DLL initialization code is called; also, when the problem first happened, my app was working, then didn't -without any changes. Finally, I went back a few days and rebuilt my app, and it still fails.
So I am really stuck, and need some advanced help in debugging DLL startup issues on Windows. I tried looking in the Windows Event Logger, but nothing appears to show up there. Logs to check? A setting in the Registry that somehow got hosed? Wrong phase of the moon? How does one debug loading/initializing a formerly working DLL when forced to treat it as a black box? Help!
How does one debug loading/initializing a formerly working DLL [...]?
I think there is no definitive answer to your question.
This is how we have gone about debugging the loading/initializing of DLLs and applications and may help you:
We regularly work with systems where we have no source code for the DLLs (and often we don't have any source code for the applications either). We experience DLL conflicts quite regularly. When testing why applications don't start as expected we have found the use of Sysinternal's Process Monitor by Mark Russinovich invaluable.
This will show you system level activity. You can filter for your process and then you will see all file, registry, thread and network activity (although thread and network are quite limited). If the DLL has dependencies then the system tries to find those and so you will be able to discover all dependent DLLs and COM interfaces (by seeing the registry lookups for that interface) that it's looking for. Process Monitor will show if the resource is not found or if access is denied.
Slightly more difficult to discover is if one of the dependencies exists but the export table has changed (so the functions have different signatures or export ordinals). There are ways to check that (by looking at the export and import tables) but generally (if you have access to a working environment) it's enough to check the filesize, timestamp (and the VERSIONINFO resource if there is one) between DLLs.

Building VB6 projects without registering

We have an old VB6 project that uses ActiveX controls, some of which we build and others we get from third-party vendors.
Currently, we use a .csproj project which does the following,
Execute regsvr32 to register the OCXs
Execute vb6 to build the VB6 project
Execute regsvr32 to unregister the OCXs
This registering/unregistering is ugly and is a bit of a pain for local developer builds with UAC enabled. Is it at all possible to build a VB6 project without having to register any controls?
I apologize if this has already been asked before. The only similar questions I was able to find were about how to build VB6 projects, and answers to these mention the same solution of register, build, unregister.
It sounds like these people are merely working on clients of these OCXs rather than modifying and recompiling the OCXs themselves.
If so, you should be administering the installation of these libraries just as you administer the VB6 development system itself. This means each workstation needs to have the control suites you are using installed once (well, and maintained when new releases are placed into use). Installers for developer libraries deploy things like .DEP files as well as design-time license key registry entries, so using regsvr32 shouldn't be considered a viable strategy anyway.
If you set the developer workstations up properly and maintain them there isn't any reason to be registering and unregistering such things.
It means the original developers probably did not set the "binary compatibility" correctly. Which means the VB6 dll's get a "new com guid" every time they are built.
Which means your original VB6 developers were probably a bunch of hacks.
You can read the section here on Binary Compatibility.
http://support.microsoft.com/kb/161137
Get in a time machine and go back and punch the person in the face who said "We don't need
to work out the binary compatibility issues now, we'll just unregister and re-register the components... Easy Peezey!"................
If I'm wrong, please let me know. But every time I've seen "unregister the com" and "re-register the com".........it goes back to that brainiac decision.
Here is a longer discussion on it:
http://www.techrepublic.com/article/demystifying-version-compatibility-settings-in-visual-basic/5030274
EDIT:
If the ocx's are not changing........then you should only have to register them once on the build machine once.
The direct answer is no, it is not possible to compile a VB6 project with OCX dependencies without those dependencies being registered.
Furthermore, the act of compilation itself involves VB6 attempting to register what it has just built (unless you are compiling to an EXE). This generally requires the VB6 IDE and/or its compiler to run with "admin" permissions. Therefore the permissions are a hard to avoid issue regardless.
I believe these issues can be obfuscated by the fact that VB6 itself (the IDE and/or the runtime) will sometimes try to automatically register certain things for you, but will keep silent when it does so.
You should probably create a different process to setup a development PC from the build process you use from deployment. This may "feel" wrong especially if you have experience with other programming environments, but I would stress that VB6 can be very painful & problematic to work with and so pragmatism is generally in order.
On the development PCs: Setup all the unchanging dependencies once (and document them) and then leave them alone (as noted in another answer.) When weird dependency problems occur, verify the PC is setup correctly before doing anything else.
If you have all the sources to your dependencies, then I would consider if you can actually run them all in a VB6 project group (VBG) and not compile them at all. (A VBG is akin to a .NET solution though far less powerful.) I do this often and it cuts out a lot of wasted time. Developers don't necessarily need code compiled to EXE / DLL / OCX - they often just need to be able to run it in the IDE.
On the build PC: If you can always start with a clean environment, like in a virtual machine, then I think its actually a good idea to register everything from scratch in an automated fashion as this helps to verify nothing is missing or mismatched. Re-using the same build environment without doing this can mask problems when some dependency has changed in source control but still exists on the build machine. On a VM generally permissions aren't a limiting factor.
Notes:
If you are building an EXE, VB6 does not require any elevated permissions, as far as I can recall.
Running code in the VB6 IDE does not either.
[Caveat 1]:
It may technically be possible to create a side-by-side application manifest file for VB6.exe itself and include in that manifest whatever dependencies you need, thereby avoiding having to register them.
But this would fall well outside of the normal ways to use VB6 tools - its a hack - and possibly is not worth the potentially large effort. I don't think I've ever seen a working example and so I don't recommend this as a practical solution, but mention it for completeness.
Maybe in some locked-down corporate IT scenario this could pay off... maybe. In that scenario doing dev work in a VM might be a better option though.

VS2008/2010 debugger changes application behavior

I have a very simple Delphi 2010 dll that I load from a Visiual Studio 2008 C ATL console application (MVF GUI app does not work either). When I debug the console app from the IDE directly - no break points - the output from the application is not correct but when I run the app directly or if I attach to the process with the debugger then it works 100%. Debugging the same dll from a Delphi console app (i.e. running it from the IDE) also works.
The VS debugger seems to break the app depending on how you run it. VS2010 does the same!
I have made 100% sure - several times! - that the data types and calling convention of the dll exports and those in the console app match. I can go into more detail but I don't want to confuse the matter with what may be irrelevant information. Please tell me if I have to go into the specifics of the code if what I have offered is not enough.
Has anyone experienced this sort of thing and know how to fix it?
I've got similar problem once (different behavior in IDE/debugger and in standalone application). It turned out, that I've checked the value of unset variable. Debugger allocated it (always!) in previously used block of memory, such that the value was not empty and the application worked correctly (because only the conditional block was erroneous). However, OS sometimes put the application in empty memory block (filled with 0s), the condition failed and application crashed.
Maybe this is the issue? Try using OutputDebugString()'s to track down values of variables during the library runtime. Without some source code I believe, that it's not easy to say, what might be the reason.
Best regards -- Spook.

How can I load a package and keep the debugger working?

I'm using TJvPluginManager in the JVCL to create and load BPL-based plugins for my program. Problem is, one of the plugins isn't loading properly, and I can't debug it. Every time I try to trace into the loading sequence, it gets as far as the LoadLibrary API call, and then the debugger seems to forget what it's there for. It completely loses the ability to associate program code with source lines, give meaningful data in a call stack, or display local variables. It will still stop at breakpoints, but it breaks to the CPU window, with all the inline source code stripped out.
This happens on Delphi 2007 and 2009, and it's driving me nuts. Does anyone know how to load a plugin without it breaking the debugger? Does anyone even know why it's breaking it in the first place?
NOTE: I'm not looking for alternative methods of debugging. I know all about tracing and logging and all the rest. What I want is to understand what's going wrong and how to fix it. Surely I'm not the only person who's ever used TJvPluginManager?
Not quite the answer to your question: Have you tried to debug the package project, by setting the host application and putting a breakpoint into the package's startup code?
I've found Ray Kanopka's (Raize) CodeSite to be invaluable for debugging in situations where the integrated debugger is acting up. Thinking about the things I want to monitor using CodeSite actually helps me focus on what's important - it enforces good habits.
Another alternative to Codesite is Overseer which is part of the nexus project, but stands alone so does not require you to use their framework. Codesite is by far the better option, but in a pinch Overseer would work just as well.
I found that using packages for plugins can be problematic and many years ago switched to a completely COM based implementation for plugins and never had any problems. The other advantage to COM based plugins, they don't require Delphi to write, do not need to be recompiled when the main app switches to a new version of the compiler (my plugins compiled with Delphi 5 still run fine against the main application compiled in Delphi 2009!) and they are easier to write test applications to assist in debugging.
The only side effect I notice, is that shared code ends up in both executables and the plugins require registration into the registry.
Hmmmm... This is a stupid question, but I have to ask: the initialization function have the EXACT declaration syntax like the other plugins that work ?(from your question, I deducted you made some others that work)
Check your dependencies. Make sure each unit is compiled into one package only. Whenever a package needs to reference a unit from another package, use the requires clause to do so. Watch for compiler warnings about implicitly linked units.

Delphi debugger?

I'm finishing an internship at a company and have just been thrown onto this project for the last month where the program is built upon an engine that they "failed" to buy the source code for. Now I've been given the task of finding out why it is failing, on only certain conditions and customer feedback hasn't been great. The main developer for the project is also out on leave for several months.
I have the engine install and know the language it was written in (delphi6?).
note which I have never had to use
I have our products msi.
I'm expected to go through the regular app and pinpoint the problem. I suspect it is something to do with fields not being re-initialized properly.
Is there a way to attach a debugger to the exe to see callstacks and all that hotness?
Any help that would avoid countless use cases would be received gratefully.
You can attach the Delphi debugger to any running process (like all other win32 debuggers out there) but I don't think the experience will be near what you expect. Delphi produces really tight executables which means the info for building human readable callstacks or any kind of "hotness" are simply not there.
Your only chance is in that if your application is a Debug release. In that case, Delphi debugger should help more than a generic debugger.
You might also want to have a look at this thread - Is there a program to decompile Delphi?
In Delphi 2006 (not sure about 6) you can attach the debugger to a running process.
You only get assembler instructions, registers, flags, memory dump and stack (hex). Hope that is enough.
Nice, I tried to attach to the ide/debugger and they disallowed that ;-).

Resources