Converting 32 bit dll to 64 bit - c++

I had to switch to Office 64 bit (2019, Professional Plus). I have a large number of VBA scripts and most of them make calls to an old 32 bit dll written in plain C language and compiled with the very old Developer Studio 97. I managed to recompile it with Visual Studio 2019 as a C++ dll at 64 bits and I faced 2 problems: the function MessageBox (and MessageBoxA) is flagged as "undefined". Workaround: I temporarily replaced them with OutputDebugStringA and the DLL compiles fine.
Calling the function from VBA, it fails to load. Thanks to ProcessorMonitor I found my dll tried to load VCRUNTIME140D.dll and UCRBASED.dll. I downloaded them from the internet and I discovered I must place them in C:\Program Files\Microsoft Office\root\Office16. But that was not enough! VCRUNTIME140D.dll must be placed in C:\WINDOWS\SYSTEM32 too!
At that point, my DLL works fine as 64 bit dll.
Next surprise was that, after a reboot, it once again failed to load due to missing VCRUNTIME140_APP.dll (please note no "D" after "140")! Downloaded and placed in C:\Program Files\Microsoft Office\root\Office16, the DLL works fine as expected.
I tried to compile it as "static" ('Code Generation' -> 'runtime library' -> 'multithreaded' instead 'multithreaded dll') but I got the error:
MSB8024 Using static version of the C++ runtime library is not supported.
Somewhere I read that VCRUNTIME140 is related to Visual Studio 2014... strange, but may be I miss some .obj from that version too in order to statically link? Why do I need elements from an older system?
Back to the MessageBox problem, I tried a simple c++ 64 bit console application and the exact same function is accepted and works as expected, so I guessed was some #ifdef in the header files that excludes the declaration in a dll. Moved the MessageBox declarations in my header file, the compilation is successful, but (as I could guess) a linker "unresolved external" for MessageBox shows up.
At this points, my questions are:
-Is it possible to create a 64 bit static .dll?
-Is it normal I have to download the above 3 dll's from the web and copy them in some directories?
-It it possible to use the plain MessageBox (handle, text, caption, buttons) in a 64 bit dll?
Thanks.

Finally, thanks to rustyx's intuition, I discovered I was using a "Solution" suitable for "app" development. (The string _APP inside the called dll name indicated just that!) I managed to switch to "Desktop" solution, and now the dll's loaded are without the _APP suffix. The MessageBox function works fine, without the need of any particular settings in libraries.
VCRUNTIME140D.DLL (debug version) and VCRUNTIME140.DLL (release version) are present in my installation installed while they are part of Visual Studio 2019 (as well as 2015 and 2017).
Finally, it is now possible to generate a static dll in this case, VCRUNTIME140.DLL (and many more) is not loaded at runtime but the same code is statically linked. Dumpbin shows it.
Dynamic linking:
USER32.dll
VCRUNTIME140.dll
api-ms-win-crt-filesystem-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
KERNEL32.dll
Static linking:
USER32.dll
KERNEL32.dll
All problems solved!

Related

VBA Calling C++ DLL - error 48 (file not found)

I have an Excel workbook that calls a test DLL I wrote in C++. The path to DLL is hardcoded in VBA. The only files the DLL uses are stdlib and iostream.
On my machine it works. On several other office machines it works. However, on the remainder when i try to call the DLL through Excel I get error 48 - file not found.
My understanding is error 53 is the file is missing; error 48 is there are missing dependencies. I have used dependency walker and have not found any issues.
What I did discover, however, is that if I install Visual Studio on a machine there is a 90% chance that after the install the Excel file/DLL works perfectly. On the 10% that it does not work, I restart and re-run the Visual Studio install, selected 'repair', and after the installation finishes again the Excel/DLL combo works. So basically installing Visual Studio allows the DLL to be loaded by Excel. If i uninstall Visual Studio the DLL still works fine.
Obviously this means something is missing on those machines, but I have no idea what - I've tried separately installing all the pieces that show up under 'programs', such as most current .net framework, visual c++ re-distributables, etc... and it doesn't work. The only thing that works is installing Visual Studio itself.
I'm not certain how to proceed since asking users to mount a 5gig ISO and install a developer environment isn't really ideal.
Ah-ha, I found the issue. It turns out that it requires 2 DLL files - msvcr120.dll and msvc120.dll. I had these 2 files in my System32 folder, but not in my SysWOW64 folder. As soon as i populated that folder then the DLLs started working.
I found many threads on google with the 'same' problem but no answer, so if you run into the same issue I'd suggest using dependency walker and making sure the DLLs are in both system folders to be safe (although I suspect System32 is only needed for 64bit DLL, and SysWOW64 for 32bit DLLs).
Most probably your DLL depends on C++ redistributables. Depending on the version of VC++ you have used to develop your DLL, you should install the relevant version of VC++ redistributables on the target machine.
In case of VS 2015 you can find VC++ redistributables here:
https://www.microsoft.com/en-us/download/details.aspx?id=48145
Use the SysInternals Process Monitor utility to monitor DLL access and look for errors. An example is in this other answer. Watch the Excel process and the CreateFile operation.
Ah-ha, I found the issue. It turns out that it requires 2 DLL files - msvcr120.dll and msvc120.dll. I had these 2 files in my System32 folder, but not in my SysWOW64 folder. As soon as i populated that folder then the DLLs started working.
I found many threads on google with the 'same' problem but no answer, so if you run into the same issue I'd suggest using dependency walker and making sure the DLLs are in both system folders to be safe (although I suspect System32 is only needed for 64bit DLL, and SysWOW64 for 32bit DLLs).
Error 48 can also be returned when the dll does not correspond to the bitness of the calling program. So, if you're runnning Excel's VBA with Excel 64-bit, for example, you want to make sure the DLL is compiled as a 64-bit binary.
Note this is different from error 53 wich really means the DLL is not found in any paths.

Win32 application and Error 0xC0000007b due to 64-bit DLL

I'm' trying to build a C++ application with Visual Studio 2015 using OpenSSL.
The application experiences a 0xC0000007b error with the message "The application was unable to start correctly". Using Dependency walker I saw my application, built as x86, uses the X64 OpenSSL DLL (in System32 instead of SYSWOW64).
How can i force Visual Studio to use the 32-bits DLL?
I just added these two dependencies :
libeay32.lib
ssleay32.lib
And visual studio loads automatically ( or windows ? ) the 64 bits version, which gets me the 0xc0000007b error
Edit : Yeah, the DLL 32-bits are in the SysWow64 too.
Any idea please ?
Thanks a lot :)
You cannot force Visual Studio to automatically find proper libraries for your architecture. Instead of it you should point to it explicitly via Library Path. Use $(PlatformName) there if you have multiple target platforms.
If you compile application as x86 than Windows automatically redirects you to the proper 32 bit system32 folder. But don't rely on it, deploy required OpenSSL dlls locally, into your application folder. If you have multiple target platforms it's also handy to use $PlatformName macros in post-build event. E.g:
copy "$(SolutionDir)3rdParty\OpenSSL\$(PlatformName)\ssleay32.dll" "$(TargetDir)"
copy "$(SolutionDir)3rdParty\OpenSSL\$(PlatformName)\libeay32.dll" "$(TargetDir)"

Error "msvcr100.dll" (only on Windows 7 & Vista) even AFTER statically linking (/MT)

I have a simple dll that is being injected into a target process using MS detours. The process doing the injecting is C# .net application.
Both the DLL and the detours library have been statically linked (/MT option).
However when I try to inject the dll into a target program on a client's machine I get error "msvcr100.dll" is missing" error. Now I open the dll w/ depends and there is no dependency on "msvcr100.dll".
Even weirder this issue only happens when the client is vista x64 or windows 7 x64. The dll is successfully injected on windows xp x32 and windows 7 x32 systems.
Any ideas on what bug in visual studio is indicating a dependency on a library not being used?
On edit:
Looks like someone else had the same issue ... never resolved.
Compiled .dll files requiring msvcr100.dll to load
For the record installing Visual studio 2010 C++ redistributable on client machine "solves" the issue however I hoped to avoid that dependency by statically linking.
You might be able to figure out what's going on my attaching (pre-injection) the cdb debugger to the process on a machine where msvcr100.dll is loaded (with the DLL installed). Use the
sxe ld:msvcr100
command to break when that DLL is loaded (I'm not 100% sure if that's the exactly correct syntax). Once it's loaded, you might be able to figure out why by looking at the call stack. If not, try setting a breakpoint on everything in that module:
bm msvcr100!*
and see who's calling it. That should give you a really good idea why it's being loaded.
So I never did discover exactly what the issue is but on a hunch I tried running the application (exact same build w/ mscvr100.dll error) on another Windows 7 machine and it worked fine.
I reinstalled Windows 7 on the "problem" machine and the same build works fine without error. In my google searching I came across a report of another person having this issue after uninstalling Visual Studio. I know for a fact that Visual Studio was installed on the "problem" Windows 7 machine at one time and was currently uninstalled.
If this happens to someone else I would recommend try running the binary on a machine that has never had visual studio installed. If it works without issue then likely there is some issue related to VS uninstall.

Delphi: Doesn't load a DLL unless I install Visual C++ 2008 Redistributable

I have a DLL that gets loaded in my application, like so:
procedure LoadTessDLL;
var
DLLHandle: THandle;
begin
DLLHandle := LoadLibrary(PChar(ExtractFilePath(application.exename) + 'tessdll.dll'));
if DLLHandle >= 32 then
begin
TessDLLLoaded := True;
We discovered that on an XP PC with Service Pack 2, the DLL fails to get loaded (the DLLHAndle = 0 etc), UNLESS we install Microsoft Visual C++ 2008 Redistributable. Then it gets loaded and works just fine.
Please can you help me get this working without it?
Do you control the source DLL? If not then no, the DLL relies on the C++ 2008 Runtime and it must be installed for the DLL to run and you need to add that as part of your install.
If you you do control the source for the DLL then statically link it to the C++ runtime, which will build the runtime into the DLL.
This issue has nothing to do with Windows XP. The DLL requires the C++ 2008 runtime on Vista and 7 as well, it just so happens that the machines you tested with already had it installed. The C++ runtime is not guaranteed to be installed on an any version of Windows.
If the DLL needs the VS2008 redistributable then it needs it and you should include the redistributable as part of your product's installer.
Microsoft provide the redistributable packaged up for inclusion in other installers and it is intended to be used in this way. (It'll add a megabyte or two to your installer.)
There is no getting around this unless you have the source to the DLL and can recompile it to statically link the C Runtime.
(Even if you do have the source, simply recompiling with static linking may introduce bugs. It's possible the DLL assumes it shares the same heap as some other module(s) in the process and that's only the case if they all dynamically link to the same C Runtime DLL. Well designed DLLs avoid such assumptions but you'd need to double-check the way the DLL is written to be sure.)
Well, my best guess would be that your TessDLL.DLL requires a DLL from the Visual C++ distributable. If it can't find the given DLL, it fails to load.
If I am right on this, the only way it will work without it is if you have the source code to TessDLL.DLL and remove all dependencies on Visual C++'s DLL.
A good place to start debugging this is on a station where it actually works. Make a little test program that load the DLL. Run it in the debugger and see what other DLL gets loaded when you load your DLL. If you're lucky, the probem could be in the version of an OS file that the MSVC redistributable happens to update.
Prior to installing Visual C++, I assume you have the DLL some place on your computer and installing VC puts another copy of the DLL possibly in your environment's PATH.
Have you tried putting the tessdll.dll in a location that is included in your search PATH? Say System32 or in the same directory from which you're running your executable? I'm not familiar with Delphi so I'm guessing at the logic of ExtractFilePath
"tessdll.dll". isn't that a DLL that's part of the Tesseract OCR software? The Windows version is compiled with Visual C++ 6 and thus it needs those runtime libraries. Your version seems to be compiled with VC++ 2008.
If you have the RAD Studio version then you could download the code and recompile it all with C++Builder, although that might need some adjustments. More information about the code also seems to be available here.
You have this options:
Compile the DLL without requiring the runtime, but be aware of issues if you have multiple DLLs written with VC++2008 requiring a shared runtime
Install the VC++ 2008 redistributable, which will install a system-wide available runtime
Install the needed VC+2008 runtime DLLs in the same path as the DLL requiring it, thus having a "private" copy of that.
See here: http://msdn.microsoft.com/en-us/library/zebw5zk9(VS.90).aspx

Visual C++/Studio: Application configuration incorrect?

My C(++) program, written and compiled using Visual C(++)/Visual Studio, runs fine on my own machine, but refuses to run on another machine. The error message I get is "This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem."
If you write a C++ program, it links dynamically to the C Runtime Library, or CRT for short. This library contains your printf, your malloc, your strtok, etcetera. The library is contained in the file called MSVCR80.DLL. This file is not by default installed on a Windows system, hence the application cannot run.
The solution? Either install the DLL on the target machine through VCREDIST.EXE (the Visual C++ Redistributable Package), or link to the CRT statically (plug the actual code for the used functions straight into your EXE).
Distributing and installing VCREDIST along with a simple application is a pain in the arse, so I went for the second option: static linking. It's really easy: go to your project's properties, unfold C/C++, click Code Generation, and set the Runtime Library to one of the non-DLL options. That's all there is to it.
The problem here is a missing DLL dependency, such as the CRT (C Runtime Library). A good tool for diagnosing this sort of problem is Dependency Walker (depends.exe), which you can find here:
http://www.dependencywalker.com/
You would run this program on the computer that generates the error message you posted, and use it to open the exe that's generating this error. Dependency Walker will quickly and graphically indicate any DLLs that are required but not available on the machine.
Chances are high that you miss the runtime libraries of Visual Studio (CRT amongst others), you can either get rid of those dependencies (link statically) or install the VC redist packages on the target computer.
Depending on the Visual C++ version you use, you have to install different packages :
Visual C++ 2005
Visual C++ 2005 SP1
Visual C++ 2008
Warning : those packages only contain release versions of the libraries, if you want to be able to distribute debug builds of your application you'll have to take care of the required DLL yourself.
It is much the simplest to link to the runtime statically.
c++ -> Code Generation -> Runtime Library and select "multi-threaded /MT"
However, this does make your executable a couple hundred KByte larger. This might be a problem if you are installing a large number of small programs, since each will be burdened by its very own copy of the runtime. The answer is to create an installer.
New project -> "setup and deployment" -> "setup project"
Load the output from your application projects ( defined using the DLL version of the runtime ) into the installer project and build it. The dependency on the runtime DLL will be noticed, included in the installer package, and neatly and unobtrusively installed in the correct place on the target machine.
The correct VC Redist package for you is part of your Visual Studio installation. For VC 8, you can find it here:
\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\vcredist_x86
POSSIBLE SOLUTION........
EDIT: (removed most of my post)
Long story short, I was having similar problems, getting the "Application Configuration Incorrect" messages, etc etc.
Depends.exe was only finding ieshims.dll and wer.dll as possible issues, but this is not the problem.
I ended up using the Multithreaded (/mt) compile option.
What HAS worked though, as a workable solution, is making an installer with InstallShield.
I've selected several merge modules in installshield builder and this seems to have fixed my problem. The modules selected were:
VC++ 9.0 CRT, VC++ 9.0 DEBUG CRT, and the CRT WinSXS MSM merge module.
I'm pretty sure its the WinSXS merge module that has fixed it.
DEBUG CRT: I noticed somewhere that (no matter how hard I tried, and obviously failed thus far), my Release version still depended on the DEBUG CRT. If this is still the case, the InstallShield merge module has now placed the DEBUG CRT folder in my WinSXS folder :) Being somewhat of a novice with VC++ I assume that this would normally be used to distribute debug versions of your programs to other people. To test if this is what fixed my problem I removed the DEBUG CRT folder from the WinSXS folder and the application still worked. (Unless something is still running in the background etc etc - I'm not that into it)
Anyway, this has got things working for me on an XP SP3 fully updated machine, and also on a VMWare XP SP3 machine with the bare bones (.net 3.5 and VC++ 2008 RTM basically) - and also on a mate's XP machine where it previously wasn't working.
So give these things a try, you might have some luck.
First thing you must use
#define _BIND_TO_CURRENT_VCLIBS_VERSION 1
or add _BIND_TO_CURRENT_VCLIBS_VERSION=1 to the preprocessor directives.
The problem is related to binding and the manifest types, you can find more http://www.nuonsoft.com/blog/2008/10/29/binding-to-the-most-recent-visual-studio-libraries/
By doing this your application will run with a larger range of runtime libraries versions.
Often times this error is the result of attempting to run the debug version of an application that uses .NET. Since the .NET redistributable package doesn't include the debug versions of the dlls that are installed with Visual Studio, your application will often get this error when running it on any other machine that doesn't have Visual Studio installed. If you haven't already, try building a release version of your application and see if that works.
Note also - that if you change to static runtime, you will have to do the same for MFC if your app uses MFC. Those settings are in properties->Configuration/General
I ran into this problem and was able to fix it very simply.
Visual studio gives you the option (on by default) to build a manifest for each build.
The manifest was put in the release folder, but it was a different release folder than the exe.
Even when using the setup utilities it was not packaged.
You should look for a file names something like myprogram.exe.indermediate.manifest
If this is in the same folder as the exe (and you have all the dlls) it should run