EntryPointNotFoundException in kernel32.dll SetEnvironmentVariable - c#

I'm running a c# application on mac using mono and xamarin as the IDE.
In my main method i have:
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling=false)]
public static extern bool SetEnvironmentVariable(string lpName, string lpValue);
and then when i call it:
SetEnvironmentVariable("PATH", path);
i get an EntryPointNotFoundException
System.EntryPointNotFoundException: SetEnvironmentVariable
at at (wrapper managed-to-native) EICService.Program:SetEnvironmentVariable (string,string)
at EICService.Program.Main (System.String[] rawArgs) [0x00031] in (*my path*)/Program.cs:34
now i know that calling kernel32.dll on mac is a problem, but i assume that it is finding it or whatever mono has as a replacement for it because if i put some dummy dll file name there i get a dll not found error.
i'm very much a noob with c#, but this code runs on windows, we just want to have it running on unix.
any ideas?

This is a Windows API function. It simply does not exist on a Mac. Hence the error.
You don't need to p/invoke this function to set a variable in the process environment. You can use the native .net functionality. That is Environment.SetEnvironmentVariable.
What's more, you should be doing exactly the same on Windows. It's never a good idea to p/invoke a native function to perform functionality offered by the .net runtime libraries.

Related

dllimport broke between .NET 4.0 and 4.8

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);

c# calling LoadLibrary from a 64-bit process to load a 64-bit library fails

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.

Using DllImport on class library [duplicate]

I'm getting this weird error on some stuff I've been using for quite a while. It may be a new thing in Visual Studio 2010 but I'm not sure.
I'm trying to call a unamanged function written in C++ from C#.
From what I've read on the internet and the error message itself it's got something to do with the fact that the signature in my C# file is not the same as the one from C++ but I really can't see it.
First of all this is my unamanged function below:
TEngine GCreateEngine(int width,int height,int depth,int deviceType);
And here is my function in C#:
[DllImport("Engine.dll", EntryPoint = "GCreateEngine", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr CreateEngine(int width,int height,int depth,int device);
When I debug into C++ I see all arguments just fine so thus I can only think it's got something to do with transforming from TEngine (which is a pointer to a class named CEngine) to IntPtr. I've used this before in VS2008 with no problem.
I had a _cdecl c++ dll that I called without any trouble from Visual Studio 2008, and then the identical code in Visual Studio 2010 would not work. I got the same PInvoke ... has unbalanced the stack error as well.
The solution for me was to specify the calling convention in the DllImport(...) attribute:
From:
[DllImport(CudaLibDir)]
To:
[DllImport(CudaLibDir, CallingConvention = CallingConvention.Cdecl)]
I guess they changed the default calling convention for DLLImport between .NET 3.5 and .NET 4.0?
It could also be that in the .NET Framework version 3.5, the pInvokeStackImbalance MDA is disabled by default. Under 4.0 (or maybe VS2010) it is enabled by default.
Yes. Technically, the code was always wrong, and previous versions of
the framework silently corrected it.
To quote the .NET Framework 4 Migration Issues document: "To improve
performance in interoperability with unmanaged code, incorrect calling
conventions in a platform invoke now cause the application to fail. In
previous versions, the marshaling layer resolved these errors up the
stack... If you have binaries that cannot be updated, you can include
the <NetFx40_PInvokeStackResilience> element in your application's configuration file to enable calling
errors to be resolved up the stack as in earlier versions. However,
this may affect the performance of your application."
An easy way to fix this is to specify the calling convention and make sure it is the same as in the DLL. A __declspec(dllexport) should yield a cdecl format.
[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl)]
Maybe the problem lies in the calling convention. Are you sure the unmanaged function was compiled as stdcall and not something else ( i would guess fastcall ) ?
Use the following code, if say your DLL has the name MyDLL.dll and you want to use the function MyFunction within the Dll
[DllImport("MyDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunction();
this worked for me.
In my case (VB 2010 and DLL compiled with Intel Fortran 2011 XE) the problem exists when my application targets .NET Framework 4. If I change targeted framework to version 3.5, then everything works fine as expected.
So, I would guess the reason is something introduced in .Net Framework 4 but I have no idea at the moment which one
Update: The problem was solved by recompiling Fortran DLL and explicitly specifying STDCALL as calling convention for export names in the DLL.

How do I import a DLL I created in Qt into a C# application

I created a DLL in Qt with one function called test. I created another Qt project in which I am able to use the DLL with no problems. I now want to use this DLL in a C# app, however, I am having problems calling the function. I have placed the DLL in the same folder as my C# exe. I import the function like so
[DllImport("TestDll.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool test();
I receive the following exception:
EntryPointNotFoundException
I tried adding EntryPoint = test to my DllImport but still receive the same exception
What am I doing wrong?
Have you tried changing option in CharSet? I have been in similar situation. But at that time, I was using a third party Dll compiled in Fortran. Say may be try from Ansi to Unicode.
HTH

C# interface C++ DLL?

How do I call functions from a C++ DLL?
The C++ DLL contains functions like this:
__declspec(dllexport) bool Setup () { return simulation.Setup (); }
The C# program does this:
[DllImport("mydll.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Setup();
The C# program crashes with the following message when it tries to load (?) the DLL:
An unhandled exception of type 'System.BadImageFormatException' occurred in TestFrame.exe
Additional information: There was an attempt to load a file with a wrong format (exception from HRESULT: 0x8007000B)
The C++ DLL is a standard DLL (no MFC, no ATL).
This error occurs when you try to load a 32-bit DLL into a 64-bit process. (Or vice-versa)
Until VS2010, C# projects are target any CPU by default and will run as 64-bit on a 64-bit OS.
You need to go to the Build tab in Project Properties and set the C# project to x86 only.
Is it possible that your exe and dll have different bitness (i.e. one is 64 and the other 32)?
Have you tried compiling the code for x86 platform?
See this blogpost for instructions.
It may not be appropriate for you to set the CPU architecture (platform target) for the assembly, but instead you can specify an alternate path to find the correct DLL to load.
How to use the correct unmanaged DLL file according CPU architecture? (32 / 64 bits)

Categories