I am creating an Autodesk Revit add-in in C#. Output of this project is a DLL itself. Within this project, I am loading another unmanaged DLL by calling:
IntPtr pDll = LoadLibrary("E:\\Rep3DLib\\builds\\Release\\Index.dll");
int a = Marshal.GetLastWin32Error();
Within debugger, I see that pDll has value 0 and a has value 127 (Error: The specified procedure could not be found.). This is surprising because I am not even looking any particular procedure within the DLL. I just want to load the DLL.
Now I delete the unmanaged DLL from E:\\Rep3DLib\\builds\\Release\\Index.dll and in the above code, a has value 126 (Error: The specified module could not be found.). This does make sense. It also means that when the DLL is present at the correct location, the code is able to find it but somehow it's looking for a procedure which it's not able to find.
To debug this problem, I created another project within the same solution. Here's the code for this project:
namespace testIndex {
class Program {
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad);
static void Main(string[] args) {
IntPtr pDll = LoadLibrary("E:\\Rep3DLib\\builds\\Release\\Index.dll");
int a = Marshal.GetLastWin32Error();
}
}
}
When I run this, pDll has a non-zero value and I am able to call the functions defined within the Index.dll.
Note that both the projects have target platform as x64. I also verified that if I build the Revit add-in and run it on a different machine, it does find the DLL. So somehow it's not finding the DLL only on my machine although the path E:\\Rep3DLib\\builds\\Release\\Index.dll is definitely correct.
Any idea what could be wrong?
Here's the answer to the question I posted above. My add-in was using a dependent DLL named "pcl_features_release.dll". Revit was loading another add-in before mine, which was also loading its own "pcl_features_release.dll" which might be slightly different than mine. As a result, although Revit was finding my DLL, it was not able to load it.
Another question: In this case, two add-ins are dependent on "pcl_features_release.dll", which is a DLL supplied by Point Cloud Library (http://pointclouds.org/). What is the best practice to avoid conflict in such cases. I can not change someone else's add-in. How do I make sure that my add-in loads my "pcl_features_release.dll" that is being supplied with the add-in?
Related
I have been using a pre-compiled DLL in some software for a few years now. Now that software required a new feature so I dusted off my project and made my changes. It was originally built for .NET 4.0, but since that is unsupported I switched to .NET 4.8, trying to keep the same major version to avoid too many differences.
My original code I did not specify a calling convention so I assume StdCall was used, but when I went to run it I got a "PInvoke has left the stack unbalanced" exception. I changed all call types to Cdecl, which resolved that error. I think this was correct to do, but it could be related to my problem still.
Now one particular method is called, (one that is supposed to give a human readable reason for an error code) the application closes. If I try to execute the method in the watch window I get an error that the target process exited with a seemingly random code (-1073740940) which does not seem like the intention of the DLL.
Since the DLL hasn't changed, I assume something about dllimport has that is causing this issue. The documentation for the DLL denotes a single long input and a char* return type which I assume means it is an ANSI string, but I've tried multiple return marshal types. This is what I think is the most correct DLLImport I've tried (the DLL I'm using is not public so I've changed the DLL name and entry point).:
[DllImport("provided.dll", EntryPoint = "getErrorString", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetDLLErrorString(long errorCode);
I'm having a problem on a machine while attempting at loading a library with a P/Invoke call to LoadLibrary.
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(string dllToLoad);
This is my configuration. The calling assembly (A) is compiled in x64 and it calls another assembly (B) compiled as AnyCPU. From B I call LoadLibrary(dll_C_Path) to a library C that is 64-bit. All this works on my machine running Win10 64-bit, but it fails on another machine running Win7 64-bit with the following error (after calling GetLastError): "%1 is not a valid Win32 application".
On B, before calling LoadLibrary I've verified that Environment.Is64BitProcess=true. I've opened the library C with DependencyWalker and it appears 64-bit. But the most strange thing to me is that on one machine works while on another not. What can be the cause?
EDIT
I'm passing the full absolute path to LoadLibrary. Here below a screenshort from Depency Walker (library C is aec.dll). I'm not used to it, but one thing I noticed is that the msvcr120.dll, which aec.dll depends on, has not the icon of a 64-bit. Can this give some hint?
There are two possible explanations:
Your code finds a 32 bit DLL, or an otherwise invalid image. We don't know whether you rely of the DLL search path or specify an absolute path.
Your code finds a 64 bit DLL but when it resolves its dependencies, a 32 bit or otherwise invalid module is found.
You should do some debugging to work out what is wrong. I would write a simple C++ program to load the library and avoid the extra complexity of p/invoke. I'd use Dependency Viewer in profile mode to determine which dependency is not valid.
I have a program that uses Tesseract to extract text from images. I made a Native C++ DLL that is used in C# via P/Invoke. My C# application is a console x64 based and the DLL is also 64 bit.
After deploying to a Windows Server I receive an error that suggets the DLL (one I've made) does not exists. The error message is below.
System.DllNotFoundException: Unable to load DLL 'TesseractX64.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E) at Utilities.Finance.PDFParser.PDF.OCRObject.GetUTF8Text(String path, String lang, String imgPath)
I know for sure that the DLL exists in that path. The TesseractX64.DLL is placed in the same folder as the C# application so it should work without any issues.
Here is my code:
[HandleProcessCorruptedStateExceptions]
[DllImport(#"TesseractX64.dll", EntryPoint = "GetUTF8Text", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GetUTF8Text(string path, string lang, string imgPath);
What I have tried so far:
Set the DLLImport path to a relative path for example C:\DLL\Tesseract.DLL. Still same issue.
Installed Visual C++ 2005 - 2012 both x86 and x64. Still same issue.
It works perfectly fine on my Windows 7 x64 computer that I used to develop the program.
Either:
The DLL cannot be found, or
One of the DLL's dependencies cannot be found.
Place the DLL in the same directory as the executable to ensure that it can be found.
Make sure that all the DLL's dependencies are met on each machine that needs to run your software. That will involve first working out what those dependencies are. The documentation for the DLL should tell you that information. Typically this means installing the MSVC runtime against which the DLL was linked.
You aren't allowed to redistribute the debug runtime. You'll want to make a release build of the native DLL even if the .NET code is in debug mode.
I have a managed dll file which imports functions from a C++ dll to the managed environment. I'm using some of its functions in my program but the problem is, I get this error when I use it:
Unable to load DLL 'Libraries\lib.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
I placed the .dll file in the program's directory and in the system32 folder. However, it still doesn't work. I think I have to use DLLImport but I have no idea how to use it.. even after looking at some examples I am still confused. Can someone help me here?
You say:
I placed the .dll file in the program's directory...
But:
Unable to load DLL 'Libraries\lib.dll'
We need to see your DLLImport attribute creation, i.e., the C# signature of the native method. It looks to me like you probably specify the path, i.e.,
[DllImport( "Libraries\lib.dll" )];
static extern void MyNativeMethod();
Try using this instead:
[DllImport( "lib.dll" )];
static extern void MyNativeMethod();
That will search the running directory as well as through your PATH environment variable. If you specify a file path as you do I honestly don't know if it will search through PATH if the file is not found (I couldn't find mention of it in the docs).
There isn't enough information here to help, as you're not showing the API (in native code) you're trying to import, etc.
That being said, I'd strongly recommend reading the Platform Invoke Tutorial as well as A Closer Look at Platform Invoke on MSDN. They walk through the main issues, as well as showing many examples of how to import and use functions from a C++ DLL.
The best and easiest way of using a c++ dll file in c# :-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace demo1
{
class Program
{
[DllImport("shi.dll", EntryPoint = "?HelloWorld##YAXXZ")]
public static extern int HelloWorld();
public static void Main(string[] args)
{
//Console.WriteLine(StringUtilities.HelloWorld());
Console.WriteLine(HelloWorld());
// public static extern void HelloWorld();
// HelloWorld();
// Console.ReadKey();
}
}
}
If you are sure of the exports (use dependancy walker to check) and that you have correctly mapped them using the correct PInvoke calls, then your issue might be 32/64 bit related especially if you are on a 64bit OS with a .NET application set to Any CPU.
A 32 bit native DLL can only be loaded by a 32 bit .NET process when using PInvoke (the same applies to 64 bit native DLLs).
You can change the platform target using Properties->Build->Platform target or you can use the CorFlags utility.
I faced the same issue with different .dll file , the solution was to change the target to x64 instead of x86
I have an unmanaged C++ MFC dll that was developed in VS 6.0. I would like to use it in my C# app. I'm trying to use PInvoke.
Here is the C++ code:
// testDll.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
extern "C" {
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
__declspec(dllexport) int test(int a)
{
return a * a;
}
}
And here is how I'm trying to invoke the method "test" from C#:
// PInvokeTest.cs
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest
{
[DllImport("TestDll.dll")]
internal static extern int test(int number);
public static void Main()
{
Console.WriteLine(test(5));
}
}
This approach works just fine when I set C++ dll to be just a regular Win32 dll.
But once I change the project type to MFC ("Use MFC in a Shared DLL") I'm getting this error:
Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'TestDll.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
at PlatformInvokeTest.test(Int32 number)
Thanks!
TestDll.dll probably can't load one of it's dependent DLL's.
Try loading your TestDll.dll file in the Depends (Dependency Walker) utility. Depends should be installed with VC 6, under Microsoft Visual Studio 6.0 Tools. That will show you what dependencies the DLL has and will flag if one of the dependencies failed.
Make sure you load the TestDll.dll from the same folder that the C# code does.
Note that Depends only works with unmanaged DLL's.
The DLL needs to be in a path where the system can pick it up. have you put it in the directory where your application starts ? (probably in a DEBUG folder of you VS solution).
The second option is to give it the absolute path of the DLL.
The third option is to place it in "c:\windows\System" but this is a '-1' approach :D
In general, when you hit errors like this you can use Assembly Binding Log Viewer to determine if the dll is failing to load because of a missing dependency.
In your particular case, the most probabl cause is that you are dynamically linking your dll to MFC and when the C# app attempts to load your dll, it is failing to load the MFC dlls.
You can either copy the required MFC dlls side-by-side or you can switch to statically linking MFC to your lib.