I am writing a Windows 32 bit program that can use one of multiple possible dlls. So it tries to load each dll in turn, using SysUtils.SafeLoadLibrary and if loading succeeds, it uses that dll.
Unfortunately some of these dlls are statically linked to other dlls. These dlls may be missing from the computer. In that case I get dialog telling me
[myprogram]: [myprogram.exe] System Error
The program can't start because [some dll name] is missing from your computer. Try reinstalling the program to fix this problem."
After pressing the OK button on that dialog, the program gets the error code and tries one of the other dlls which then works fine.
Rather than showing that dialog to the user I want my program to silently ignore it.
How can I accomplish that?
In case it matters: My program is written in Delphi 2007. The Windows version is Windows 8.1, but the program should also work with other Windows versions >= Windows XP.
I have tried SetErrorMode(SEM_FAILCRITICALERRORS) but it did not make any difference.
SafeLoadLibrary sets the error mode to the value that you provide as an argument, and then restores it after the call to LoadLibrary returns. Most likely you are not supplying a value for that parameter, in which case a default of SEM_NOOPENFILEERRORBOX is passed. In that case it is probably disabling SEM_FAILCRITICALERRORS which would explain the behaviour that you see.
You could solve the problem by passing SEM_FAILCRITICALERRORS every time you call SafeLoadLibrary. Or, perhaps better would be to pass the current error mode. However this is hard to obtain. In Vista and later you can call GetErrorMode. But in older versions you have to do this:
ErrorMode := SetErrorMode(0);
SetErrorMode(ErrorMode);
Because this is a process wide setting, you have a window of opportunity between the two calls to SetErrorMode, for multi-threaded applications to be caught out.
Frankly, I believe that you should call SetErrorMode exactly once in the lifetime of a process, at startup. With that in mind, I would shun SafeLoadLibrary.
If you wish to take advantage of its other function, namely to protect against changes to floating point control state, then you should implement that functionality yourself, in my opinion.
I am trying to debug a dense piece of code with multiple function calls in single lines. I want to single step through all the code that I have written, but in doing that I keep finding myself in the supplied source code, including the assembler code.
This is happening at a client's site on his machine running XE5. It doesn't happen on my own code, running XE2 and XE4.
What is the magic setting that makes this work they way I want?
The best you can do is make sure that Debug DCUs is disabled in the project options. But even doing that sometimes is not sufficient to stop yourself landing in RTL code, in modern Delphi versions. I suspect that you have Debug DCUs disabled and are being caught out by this behaviour change.
The only thing you can do is get used to knowing when to use step out (F8) rather than step in (F7), and being able to escape from a function as quickly as possible. Usually that involves putting the cursor on the last line, running to cursor (F4), and stepping in again.
You might also be interested in the Selective Debugging tool by Uwe Raabe which allows you a fine grained selection for which DCUs are used with or without debug information.
I am trying to port an unmanaged C++ Dll from one embedded device to another and am facing some strange problems which I think must have something to do with memorymanagement and/or compilers. I am not posting much code but describe what I tried as I have tried too many different things to post all code and I think the problem must be somewhere deeper within.
The first device is running WinCE 5.0 and is compiled using embedded Visual C++ 4.0.
The second device is running Windows Embedded Compact 7 (I will call it WinCE 7 for simplicity) and is compiled using VS2008. Both devices have their own SDKs designed for the boards.
On the first device the Dll is running without any problems, but on the second device the with ne new SDK compiled Dll is not working. Having a C# applikation on the second device I tryed PInvoke to access the dll but on the PInvoke line in Debug Mode got the error message:
Can't find PInvoke DLL NAME.dll
After some research I learnd this error can have differend causes:
Missing dependencies of the native library you are calling into.
The native assmebly was compiled for the wrong subsystem (i.e. desktop, not CE)
The native assembly was compiled for the wrong processor (i.e. x86 and not ARM)
Not enough virtual memory for the DLL to load.
I used peinfo to check the dll. All dependencies are being found on the device, it is compiled for WinCE 7 and the processor type is right. (I would have been surprised if not, using the right SDK) So there still is number 4: not enough virtual memory. But WinCE5 is limited to 32MB virtual memory and running while WinCE7 can have up to 2GB?
So I started to try some things to narrow the error in and will tell you my results.
First I took my dll compiled for the first device and tryed to use it on the second device. Surprisingly the .net application can find and PInvoke this one. But some functions inside the Dll don't seem to be running right so I guess I have to use the right SDK. But having the right code for both dll I know the exports must be right. I am aware the two compilers use different c++ name mangling styles so that is not the problem, too.
Next I wrote a simple c++ application on VS2008 using the new SDK to Load the Dll from there. On the first device the application runs this way but now on my remote Display on running on the second device I get the Error Message:
Unable to import library NAME.dll ! Program will exit.
At least now I know it has nothing to do with .net and PInvoke. But further on I made a simple new dll using VS2008 and the new SDK and ne .net application is able to PInvoke it. So there must be something in the code that doesn't like to be Loaded. :-/
After some hours of searching through the code I realised the system doesn't like some global variables. I know global variables are bad and I would be glad if they wouldn't be there, but I have not started the code and over the years they got more and more before me dealing with it, so they would be very hard to erase right now.
These globals are instances of classes. Some of them seem to be bad, some others seem to be ok. Confusingly they all are instances of classes and I don't know why there are good and bad ones. When I comment out the bad globals, the application is able to PInvoke the Dll. One of the bad globals is enough to make to applikation not find the Dll.
Why is it like this using VS2008 with WinCE 7 but not using eVC4.0 with WinCE 5? And what is the problem with the globals? How can I solve this problem? At best the same code should be working for both compilers but first I need some ideas, what is wrong with the second compiler.
I have found the solution to my Dll loading problem. The two systems have a different behaviour on #pragma pack. So eventually there was missalignment while loading the dll what made the dll crash. Because of the globals it was in the loading process of the dll, so the error message did not say something about missalignment but the standard "Can't find PInvoke DLL".
We ported an application from Delphi 7 over to Delphi 2010 and have had customers encountering intermittent BSOD (blue screen of death) errors while running under Windows XP. The errors are very sporadic and have been very hard to track down. FYI : We are using the built-in memory manager from Delphi 2010.
Our first thought was a hardware issue but upgrading system drivers failed to fix the problem.
Has anyone else encountered BSOD issues under XP with Delphi 2010 generated applications? If so, do you have any suggestions on how we might correct this problem?
Thanks for your assistance!
There's nothing in the Delphi core libraries that can cause a BSOD directly. As David pointed out, Delphi programs run in user space. However, if they're sending invalid data to a kernel-space driver, that's a different matter.
You said D7-D2010 update, and the first thing that occurs to me there is the string revamp. Delphi's standard string type has been changed from AnsiString (1 byte per char) to UnicodeString (2 bytes per char) and if you're sending the wrong type of string to a driver or system routine somewhere it might cause strange behavior.
First thing I'd do is run a full build and watch for "implicit conversion" warnings from the compiler. This means that you're mixing string types. Find these and fix them and see if that helps.
Also, if you have any import units for external libraries, and they use APIs that take a string (or more likely a PChar) parameter, make sure they're converted to PAnsiChar. Delphi's already taken care of this for the Windows API stuff used in windows.pas, but if you've got any of your own you need to take care of it yourself.
BSOD can be analyzed opening the crash dump with WinDbg or other tool able to process crash dumps. Even a "minidump" will give enough informations to try to understand where and hopefully why a BSDO occurs. WinDbg can be downloaded freely, and you don't need to install it on the target machine, you can ask your customers to ship the crash dumps to you, and you can analize them offline. Anyway generating a BSOD from user mode code is usually very difficult - but there are ways to crash a system. What kind of error the BSOD displays?
Update: if the error is PAGE_FAULT_IN_NONPAGED_AREA this link explains what happened: http://technet.microsoft.com/en-us/library/cc957625.aspx. It usually a memory-related issue, and it may be that D2010 using more memory than older version may end up to trigger it. Could you run a memtest on those machines (http://www.memtest.org/)?
Ntkrlnpa.exe is not a driver, is the image containing the OS executive and kernel code (the version with PAE support). Using winDbg and the crash dump it is possibile to obtain the call stack leading to the crash.
Delphi with 64 bit compilation is now in Beta, but only invited beta-testers will get their hands on this version.
What should be tested by the beta testers?
Embarcadero will probably provide a tester's guide for the beta testers. But, here are some ideas:
Memory allocation, alignment, heap and stack. 32-bit could use up to 4GB (well, 3.5) of address space on a 64-bit version of Windows with the /LARGEADDRESSAWARE switch: Delphi64 should be able to use much more. Try allocating 8, 16, and 32 GB. (Even if you have less RAM, the allocation should work since it's a virtual address space.) Now read and write values into it a certain spots: check your allocation and pointers all work. Have a look at what Process Explorer reports for the app. Inspect your stack: it runs top-down, unlike the heap - what does it looks like, what addresses is it using? What does the 16-byte alignment look like? Is that alignment kept for all internal Pascal functions, or only those that call external code? In the 32-bit VCL, there were some bits of code that weren't safe for addresses larger than 2GB. Have those been fixed? Does anything break when it's allocated in, say, the 53rd GB of your program's address space? (Try allocating a huge amount, and then dynamically creating forms, controls etc - they'll probably be created with high addresses.) Does the memory manager fragment? How fast are memory moves and copies?
Compiler warnings. (This one is important.) Upgrade your programs - compile them without changes, and see what warnings / errors you get; fix any; and then fix bugs that occur even though you weren't warned. What issues did you encounter? Should the compiler have warned you, but didn't? Do you get warnings when truncating a pointer when casting to an integer? What about more complex issues: if you use the Single floating-point type, what happens? Warning, or is it silently represented as a double? What if you pass in a parameter to a method that's a different size - for example, PostMessage and you pass in a 32-bit-sized value to the handle parameter - will the compiler be smart enough to guess that if the size is wrong, your code might be wrong, even though it's often valid to pass a smaller type to a larger parameter? Under what circumstances should it do so? (Another thing: what if you pass a 64-bit pointer to a 32-bit type in a method expecting a pointer to a 64-bit type - the type safety should yell loudly, but does it? A use case for that is reading blocks from a binary file, something that could easily cause problems with the wrong-sized types.) ...etc.
Compiler warnings are probably one of the most useful tools for people who upgrade, so the compiler should produce as many as possible, in as many situations as possible, with as few false positives as possible. Remember Delphi is used by a wide range of programmers - you may know what a warning means or recognize bad code even if the compiler is silent, but anything that will help novices (or good programmers having a bad day) is important.
Custom controls & WinAPI. You probably have a few customs controls or bits of code that make heavy use of Windows APIs instead of the VCL. Are there any Windows API-specific issues?
Language compatibility. Does the old file IO code work - AssignFile, etc? RTTI? If you have an event signature with an Integer type, and an event handler is auto-created by the IDE, is it generated as Integer or a size-specific integer type depending on the platform that's currently set? What if the event is NativeInt, what then? (I've seen bugs in event handler method signature generation before, though only on the C++ side.)
Different types of application. We can assume GUI programs have been tested well. What about console and service applications?
C++Builder compatible file generation. C++Builder won't be 64-bit in XE2, but hopefully will in XE3. Delphi can produce ..hpp and .obj files for Pascal code, though. What happens in for a 64-bit platform? Can you produce those files, even though they're useless? Does the compiler generate C++-specific warnings in 64-bit mode, or does it give up and not let you do it? In 32-bit mode, is there anything you can do for 64-bit compatibility that will generate a warning building the C++ header?
Linker. Can you link .lib and .obj files created with other compilers? (I'd expect .lib yes, .obj no.) Does the linker use COFF or OMF for 64-bit - have they changed? This thread implies an ELF format. Has it changed for 32-bit too? Does this affect the DCU format, will we still get ultra-fast compiling / linking?
COM and 64-bit plugins. Are there any marshalling issues? Can you build a 64-bit plugin for Explorer now?
Calling conventions. Safecall's supposed to be the only 'calling convention' (if safecall counts...) that's still different - does it still work? Function and procedure pointers, and closures (object method pointers): do they work? What do they look like in the debug inspector? Given all calling conventions are now the same, if you mix calling conventions in your method declaration and your calling pointer, what happens? Is there any legacy stuff around that will break or does it transparently work? Does it now give you an (erroneous) warning that the types are incompatible?
Floating point math. The Delphi 64 preview said floating point would be double only. Can Delphi handle long doubles? Are there any compatibility routines for handling the old Real (48 bits, I think??) type? Does the compiler generate SSE or SSE2 code or a mix, and how good is it?
Performance. This is their first go at a 64-bit compiler; it will probably be refined over the next few releases. But are there any obvious performance problems, with:
compiling; linking; IDE insight?
Generated code: are your programs faster or slower? Is FP math faster or slower? Does inline work, and does it generate any unnecessary header/footer bits around inlined methods?
Debugging. This is probably easiest to test through the whole process of testing everything else, but how well does the 64-bit debugger work? Does it have all functionality of the 32-bit one? Do IDE debug visualiser plugins still work? What if you debug a non-Delphi 64-bit program or attach to a process, instead of running normally?
Misc Is Delphi itself compiled as a 64-bit program? If not, why not? (Are they "eating their own dogfood"?) Code inspect the new VCL (assuming the preview comes with VCL source.) What have they done to make the VCL 32/64 compatible? Are there any errors, or if you already know 64-bit code well from other IDEs, are there better approaches they could take instead?
...etc. I could keep typing for hours, but I think that's a good start though :)
I'm sure Embarcadero will provide some testing guidance. For what it's worth this is what I'd test; Mostly because it's the stuff I care about:
Small console application should work.
Allows me to allocate a 4Gb flat hunk of memory. Don't really need that, but it will be the first thing my console application tries, right after WriteLn('I''m using all 64 bits!!!!');
Can create 64bit DLL and the DLL can be imported and used from other environment.
Do some simple things and look at the generated assembler, just for kicks.
Can create Firebird 64bit compatible UDF's
I'd probably try compiling my "utility" units, because they do an fair amount of pointer manipulation, see how they work.
If the VCL works I'd put it through it's paces: create small form, put a button on it, ShowMessage.
Generally speaking the only thing I really need 64bit Delphi for is Firebird 64bit UDFs. That's minor and can be "fixed" using FPC. I assume the best testing will be done by people that actually need 64 bit delphi. And those people don't need testing suggestions.
The base foundation stuff would come first, to ensure that Delphi 64 can be used for what Delphi 32 can't be used:
compiler correctness: first and foremost, no internal errors, no incorrect code-gen
ability to compile to 64bit DLLs and stability of those
stress the memory manager: with large objects, fragmented allocation, multi-threaded allocations, etc.
multi-threading: is it stable? is it efficient? does it scale? that for core RTL functions and units, and not forgetting the reference-counted types.
floating point: does the compiler deliver proper SSE? are the maths functions properly implemented and correct? what happens if you stress the SSE register set with complex expressions?
And as a bonus, ability to accept 64bit object files from the usual C++ compilers.
Non visual stuff ... I think. There is already success from some beta testers that already ported their libraries. I don't know the preview but from the information I don't have I would assume more complex non visual scenarios currently make sense. Anyone who knows it better please correct me ...
I think the preview first allows you to setup a migration strategy, this would be my intention. The VCL ... intended to work on one code base and maybe backport your code to purepascal instead of assembler.
Mike