I have a problem with invoking a few functions from DLL (SDK of some camera). In source of .dll, there is function:
NET_SDK_API LONG CALL_METHOD NET_SDK_Login(char *sDVRIP,WORD wDVRPort,char *sUserName,char *sPassword,LPNET_SDK_DEVICEINFO lpDeviceInfo);
and I am trying to call it from .Net console app with following code:
[STAThread]
static void Main(string[] args)
{
long userid = 0;
_net_sdk_deviceinfo dinfo = new _net_sdk_deviceinfo();
short port = 6036;
try
{
if (DVR.NET_SDK_Init())
{
Console.WriteLine("ok");
userid = DVR.NET_SDK_Login("192.168.1.132", port, "admin", "123456", out dinfo);
userid.ToString();
}
else
{
Console.WriteLine("err");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadKey();
}
i get following error:
A call to PInvoke function 'DVRtest!DVRtest.DVR::NET_SDK_Login' has
unbalanced the stack. This is likely because the managed PInvoke
signature does not match the unmanaged target signature. Check that
the calling convention and parameters of the PInvoke signature match
the target unmanaged signature.
Init passes fine but i cant get anything else. I tried dozen of solutions and I'm getting nowhere.
Here is source of dll and source of my .Net app. Thanks!
[edit]
As #david pointed out, CallingConvention was wrong and now, i get following error:
The runtime has encountered a fatal error. The address of the error
was at 0x6fda02c7, on thread 0x2554. The error code is 0xc0000005.
This error may be a bug in the CLR or in the unsafe or non-verifiable
portions of user code. Common sources of this bug include user
marshaling errors for COM-interop or PInvoke, which may corrupt the
stack.
Is this error from DLL or CLR (.Net)? I never imported any functions from DLL to .Net, so any help is appreciated.
From the unmanaged source:
#define CALL_METHOD __stdcall
And from the managed source:
[DllImport("DVR_NET_SDK.dll", CallingConvention = CallingConvention.Cdecl)]
Your calling conventions do not match.
As for the edit to the question, that is presumably because the C# struct definition does not match the unmanaged struct. You have failed to translate any of the arrays correctly. They will require the use of [MarshalAs(UnmanagedType.ByValArray, SizeConst=...)].
Related
I am trying to export code from a function in C# to Delphi. I used DllExport with stdcall convention and made some tests :it works. I tested for integers and strings as params. The problem occurs when I try to use a class from Aforge library in C#. Delphi returns an error: "External Exception E0434F4D".
public class ProcessClass
{
[DllExport(CallingConvention=CallingConvention.StdCall)]
public static void ProcessImage()
{
try
{
Erosion erosion = new Erosion();
}
catch (Exception Ex)
{
}
}
}
Delphi code:
procedure ProcessImage; stdcall; external 'C:\Users\Reznicencu Bogdan\source\repos\OCR\OCR\bin\x86\Release\OCR.dll';
procedure TForm1.FormCreate(Sender: TObject);
begin
ProcessImage;
end;
The error apears at Erosion.Actually every function I use from Aforge library generates an error. I used Try/catch because I know Delphi can't catch exceptions from unmanaged code but it still doesn't work.
How can I solve this error?
The event log says: First chance exception at $767EDDC2. Exception class EExternalException with message 'External exception E0434F4D'. Process Project1.exe (9528)
The problem appears to be related to the location of the AForge DLLs. If you place those, and your class library DLL, in the same directory as your Delphi executable then the error disappears.
Perhaps there is some other way to tell AForge where to locate its DLLs. I will leave that as an exercise for the reader to investigate.
I am migrating some VB6 code to C# (.NET 4.5.2) and got stuck into a piece of code that is calling the gethostname method from the WSOCK32.DLL to apparently retrieve the computer name. All the code samples that I have found so far point to
this code. And since I haven't been able to successfully PInvoke the gethostname method in C#, I can't help asking if is there an alternative to it.
This
[DllImport("WSOCK32.DLL", SetLastError = true)]
internal static extern long gethostname(string name, int nameLen);
string host = string.Empty;
var res = gethostname(host, 256);
fails with the following error:
The runtime has encountered a fatal error. The address of the error was at 0x6a13a84e, on thread 0xd88. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
I also read about using System.Environment.MachineName or the "COMPUTERNAME" environment variable, but I am interested in how the result differs than what gethostname method returns.
What options do I have?
I am developing on a 64bit system but I don't know if/how this affects working with WSOCK32.DLL since I found no documentation about it.
You cannot send an zero-length immutable C# string and expect it to get turned into something new. You are probably experiencing a buffer overflow. You need to use a StringBuilder instead:
[DllImport("WSOCK32.DLL", SetLastError = true)]
internal static extern long gethostname(StringBuilder name, int nameLen);
var builder = new StringBuilder(256);
var res = gethostname(builder, 256);
string host = builder.ToString();
More info here:
Passing StringBuilder to PInvoke function
C# PInvoke out strings declaration
http://pinvoke.net/default.aspx/ws2_32/gethostname.html
Also, there is really no reason for using that really old DLL function to get the name of the local computer. Just use System.Environment.MachineName instead.
I've done a lot of searching and testing and I've been unable to get this to work correctly.
I'm using MVS Express 2013, compiling a c++ win32 DLL that I hope to call from a c# GUI.
On the C++ Side of things, I have a function that I've exported, and it gets passed a struct. The struct originally contained two strings but it seems easier to pass a char array of known size.
C++ Code:
struct runDetails{
char requestedRuntype[32];
char filename[32];
};
void __declspec(dllexport) WindowRecreatorCall(runDetails* incomingRunRequests);
c# Code:
Attempting to recreate the Struct to pass in:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public struct runDetails{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 32)]
public string requestedRuntype;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 32)]
public string filename;
};
Set up the Dynamic DLL Wrapper:
class CallWindowRecreator
{
[DllImport("WindowRecreatorDLL.dll", EntryPoint = "WindowRecreatorCall", CharSet = CharSet.Unicode)]
public static extern void WindowRecreatorCall(ref runDetails runDetails);
};
Actual Call to the DLL:
runDetails testing;
testing.requestedRuntype = "Minimize";
testing.filename = "";
CallWindowRecreator.WindowRecreatorCall(ref testing);
As it is right now, I get this error when I attempt the DLL call:
An unhandled exception of type 'System.BadImageFormatException' occurred in WindowRecreatorGUI.exe
Additional information: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
I've done a lot of googling and code changing and I've learned a lot but I just can't figure this one out. Any tips would be greatly appreciated.
Edit: Changed the code and error recieved
Edit 2: I've changed the C# program from Any CPU to x86 specifically, and now I get this error:
An unhandled exception of type 'System.EntryPointNotFoundException' occurred in WindowRecreatorGUI.exe
Additional information: Unable to find an entry point named 'WindowRecreatorCall' in DLL 'WindowRecreatorDLL.dll'.
And Edit 3 before bed:
I've added an extern c{} around the c++ function. Now I get this error:
Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\Users\Tom\workspace\WindowRecreatorGUI\WindowRecreatorGUI\bin\x86\Debug\WindowRecreatorGUI.vshost.exe'.
Additional information: A call to PInvoke function 'WindowRecreatorGUI!WindowRecreatorGUI.CallWindowRecreator::WindowRecreatorCall' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
Your native method takes a pointer to the struct.
In C#, that becomes a ref parameter:
[DllImport("WindowRecreatorDLL.dll", EntryPoint = "WindowRecreatorCall", CharSet = CharSet.Unicode)]
public static extern void WindowRecreatorCall(ref runDetails runDetails);
You also need to pass the correct CallingConvention in the attribute, which is probably Cdecl.
have been working on this for hours, couldn't get it work :(
below code gives exception "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." this is fixed, see below update
but when i change the return type to int and return a int value, it works. how to make it to return a float value? thanks.
vs2012
c++ code
extern "C" __declspec(dllexport)
float compute_similarity()
{
return 1.01;
}
c# code
[DllImport("demo.exe", EntryPoint = "compute_similarity", CallingConvention = CallingConvention.Cdecl)]
public static extern float compute_similarity();
public void Get()
{
float x = compute_similarity(); // here returns random value
}
=====================================
UPDATE
See comments from David below, the problem was the c# project is targeting x64 and c++ is targeting Win32. After changing the c# project to target to x86, the exception went away.
However the call from c# returns some random value instead of 1.01 expected
I think your problem is that your function is declared in an executable rather than a DLL. Convert your native code into a library project and compile a DLL.
Your code will result in a call to LoadLibrary passing the file name demo.exe. The documentation for LoadLibrary says:
LoadLibrary can also be used to load other executable modules. For example, the function can specify an .exe file to get a handle that can be used in FindResource or LoadResource. However, do not use LoadLibrary to run an .exe file. Instead, use the CreateProcess function.
And so your code is doing exactly what you are told not to do. The call to LoadLibrary will succeed. The subsequent calls to GetProcAddress will succeed. But the module that you loaded is not fit to execute code.
I am using C DLL in C# code (.net 4.0) in a console application and facing issue.
When I call the C method it raises the below exception.
"A call to PInvoke function 'ProcessFilesC' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature."
Here is the C code
int ProcessFilesC(
char **p_FilesOrDirs,
ImageInfoC **p_vecImageInfo,
int ***p_vecStackIndexes,
RectC ***p_vecFaces
);
Here is my C# code
[DllImport(#"..\ref\myCApp.dll", CallingConvention = CallingConvention.StdCall)]
unsafe private static extern UInt16 ProcessFilesC(
String[] p_FilesOrDirs,
ref ImageInfoC[] p_vecImageInfo,
out Int32[] p_vecStackIndexes,
out RectC[] p_vecFaces
);
public unsafe struct ImageInfoC
{
public String resizedFilePath; //char* (in C)
public Byte isUsable; //unsigned char (in C)
public UInt32 imageId; //long int in (in C)
public UInt16 stackIndex; //int (in C)
public Boolean isBestPhoto; //unsigned char (in C)
}
Below is C# code to call the method
unsafe
{
iResult = ProcessFilesC(
p_FilesOrDirs, // Value getting passed to DLL
ref p_vecImageInfo,
out p_vecStackIndexes,
out p_vecFaces
);
Console.WriteLine("ProcessFilesC Complete");
}
When code reaches here, I can see that method is processing as it prints in console but after processing, it raises the mentioned exception.
I guess this is due to C DLL is trying to write values in output/ref parameters.
I am not getting where is the issue or what's the wrong in my code.
Please note that I have already uncheck option "Suppress JIT optimization on module load" at Tools -> Options -> Debugging -> General
Please help as soon as poosible.
Thanks for spending to valuable time to read this post.
Thanks,
Kiran
The first thing to check is the calling convention. In most cases the calling convention specified in your DllImport attribute differs from the actual calling convention in the native DLL.