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.
Related
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.
I am trying to use an application called CLUT.exe which is an old application for MS-DOS that can be used to reindex NTX files for DBF databases.
(This is not the main topic, but I am just writing this if someone wants to test the app and don't trust at all about the content).
The problem starts when trying to run the command line version through console (cmd.exe) and this error appears:
C:\>CLUT.exe [arg1] [arg2] [arg3]
run-time error R6009
- not enough space for environment
So, according to what I've searched, this could be a possible solution:
http://support.microsoft.com/default.aspx?scid=kb;en-us;230205
but it doesn't work and every alternative that I found to solve this over the internet is the same.
Another alternative could be to make right-click in the .exe file, go to Properties then Memory tab and increase the Initial environment memory from Auto to the max value but it doesn't work too.
Well, I am stuck and no "possible" solution is working for me. If someone is interested, knows more about this issue and want to test, you can download the application from here (click "Free Download" green button):
http://www.filebasket.com/free/Development-Clipper-programming-language/clut-exe/13996.html
or directly from my DropBox:
https://dl.dropbox.com/u/15208254/stackoverflow/clut_214.rar
Just to know, I am using Windows 7 and the CLUT.exe application is a Clipper based app (old programming language) that may run under windows console (cmd.exe).
Wikipedia does mention other dos emulators but, oddly, doesn't mention BOCHS.
Reindexing NTX files is not a difficult thing to do, and can be done with tools other than CLUT. For example, many of the utilities listed on this part of Download32 could be used. Otherwise, you could write your own using Harbour Project or xHarbour. Or contact me off list and I'll cook up something in Clipper 5.3.
LATER
If I read the README correctly for CLUT, it's a replacement for the DBU utility that comes with Clipper 5.x. I can supply you with a build of that if you're unsuccessful with other approaches.
My computer crashed recently. We have a Delphi app that takes a lot of work to get running.
One of my co-workers has it all installed still. Is there a way to copy the stuff stored in the palette? And the library paths?
I am using Delphi 5 (I know it is very very very old)
That information is stored in the Registry. I don't know exactly how Delphi 5 does it, but try looking for a key called HKEY_CURRENT_USER\Software\Borland\Delphi\5 or something like that. You'll find all the registration information under that key, including a list of installed packages. You can export the keys to a registry file, copy it to the new computer and install it.
Standard disclaimer: Mucking around in the registry manually can be risky if you don't know what you're doing. Be very careful, and if this solution causes your computer to crash, your house to burn down, or demons to come flying out your nose, it's not my fault.
Try CNWizards which has an export functionality for your IDE settings. You can use the same tool restore them on the new machine. We use it to get the same settings on every development machine. In that way we can ensure that all builds are the same, regardless of who built it.
Based on my experience of having done this a few times(!), the most important registry keys are:
HKEY_CURRENT_USER\Software\Borland\Delphi\5.0\Known Packages
HKEY_CURRENT_USER\Software\Borland\Delphi\5.0\Library
and possibly
HKEY_CURRENT_USER\Software\Borland\Delphi\5.0\Known IDE Packages
and maybe
HKEY_CURRENT_USER\Software\Borland\Delphi\5.0\Palette
HKEY_CURRENT_USER\Software\Borland\Delphi\5.0\Palette Defaults
So long as you have done a standard D5 installation first.
It's easier/more reliable to let the IDE fill in the other bits as you start using it and you change options as appropriate. Some component packages, eg madExcept, DevExpress etc are often best re-installed using their own installers anyway.
Unless you're going to have multiple users on the same machine using Delphi then the HKLM stuff isn't really all that important - I don't think.
As a related aside - I have learned that a good way to handle this is to build a FinalBuilder script (or similar) to set up my Delphi environment each time I decide to use a new machine/installation. I copy/download/checkout (which can be done in FB too) all package source then use FB to compile it, copy it, create dirs, and fill in the appropriate registry keys etc. I always get a consistent environment and makes it much easier to rebuild individual components or packages as and when they get upgraded too. The items can also be put into the script in 'dependency order' so that you know to re-compile a dependent package if something else changes. I now have a single FB sciprt that builds D5, D2007, D2009, D2010 environments and packages of all my main components, all depending on which compiler(s) I'm interested in which I indicate by a simple variable. Well worth it.
Seems to have just worked for me on a Win 7, SP1 and Delphi 5
Logged as user with Delphi & 3rd party components installed.
registry export
hkey current user\software\borland
(no other borland products so selected Borland)
rather than Borland\Delphi\5.0)
Logged into pc as new user.
Did not start Delphi5 (i.e. never started for this user).
Regedit File, Import
Started Delphi all components, including lots of 3rd
party, present.
Project compiled as expected under new user.
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.
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.