I have the following function from a c++ header file:
__int16 __stdcall s_em4305_login (HANDLE m_hUSB, int DataRate, UCHAR * password);
When I run the VB equavelent:
Private Declare Function RF_EM4305_Login Lib "SRF32.dll" Alias "s_em4305_login" (ByVal handle As Long, ByVal DataRate As Long, ByRef bytes As Byte) As Integer
I get -1100 back as a value
When I run the c# equavilent:
[DllImport("SRF32.dll", EntryPoint = "s_em4305_login")]
private static extern ushort RF_EM4305_Login(IntPtr handle, int DataRate,byte[] password);
I get a different value. The 3rd paramater is most likely declared incorrectly. Can someone please assist in converting the c++ declaration to c#
Update
I have added some additional declarations
private static extern ushort RF_EM4305_Login(IntPtr handle, int DataRate,IntPtr password);
private static extern ushort RF_EM4305_Login(IntPtr handle, int DataRate,ref byte[] password);
With all 3 c# declarations I get the value "64436" returned.
If your unmanged code treats the password as a Null-terminated ansi string, this two should both work.
[DllImport("SRF32.dll", EntryPoint = "s_em4305_login", CharSet = CharSet.Ansi)]
private static extern short RF_EM4305_Login(IntPtr handle, int DataRate, string password);
[DllImport("SRF32.dll", EntryPoint = "s_em4305_login")]
private static extern short RF_EM4305_Login(IntPtr handle, int DataRate, [MarshalAs(UnmanagedType.LPStr)]string password);
And your C# declaration wasn't wrong either, because ushort 64436 equers short -1100 in memory.
Related
I have the following C++ function exported in a DLL:
extern "C" __declspec(dllexport) bool GetResolutionArray(int32_t adapterIndex, int32_t outputIndex, uint32_t arrayLength, Resolution outResolutionArr[]) {
memcpy_s(
outResolutionArr,
sizeof(Resolution) * arrayLength,
RENDER_COMPONENT.GetResolutionArray(adapterIndex, outputIndex),
RENDER_COMPONENT.GetOutput(adapterIndex, outputIndex).NumResolutions * sizeof(Resolution)
);
return true;
}
And, the matching extern function declaration in C#:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetResolutionArray", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetResolutionArray(int adapterIndex, int outputIndex, uint resolutionArrayLength, [MarshalAs(UnmanagedType.LPArray), In, Out] ref Resolution[] resolutions);
However, when I attempt to use this function as below, the program crashes with a FatalExecutionEngineError (indicating I corrupted something somewhere I guess) (error code 0xc0000005, i.e. access violation):
Resolution[] resolutions = new Resolution[outOutputDesc.NumResolutions];
if (!_GetResolutionArray(outAdapterDesc.AdapterIndex, outOutputDesc.OutputIndex, (uint) resolutions.Length, ref resolutions)) {
EnginePipeline.TerminateWithError("Internal engine call failed: _GetResolutionArray");
}
I strongly suspect that my call to memcpy_s is causing the access violation, but I can't see how or why, and I therefore reason that perhaps the marshalling is going wrong somewhere.
Thank you.
The array parameter is declared incorrectly. A C# array is already a reference and so you don't need the ref. Declare it like this:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetResolutionArray",
CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetResolutionArray(int adapterIndex,
int outputIndex, uint resolutionArrayLength, Resolution[] resolutions);
I have the following function in C++ native dll, and I want to use it in a C# app.
DWORD __cdecl Foo(
LPCTSTR Input,
TCHAR** Output,
DWORD Options,
ErroneousWord** List = NULL,
LPDWORD Count = 0
);
Using Pinvoke
[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 Foo(string InputWord, out string Output, UInt32 Options, out object List,out UInt32 Count);
Calling code:
string output;
object dummyError = null;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x | y,out dummyError,out dummyCount);
I got the following exception
Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt
P.S:
ErroneousWord is struct and I do not need its output, so I marshal it as object
That error more than likely means that you have a marshaling problem.
You don't show us what the ErroneousWord type is, but I assume it's some kind of class defined in your C++ code. My guess is that it's not being marshaled correctly to a .NET object.
Considering that it's a pointer (or a pointer to a pointer), try changing that parameter to an IntPtr type to represent a pointer, instead. It shouldn't matter, since you're simply passing NULL for the argument anyway, easily represented using the static IntPtr.Zero field.
You probably also want to marshal Output the exact same way. If you change the parameter to an IntPtr type, you'll receive a pointer to a TCHAR*, which you can then pass to the other unmanaged functions however you see fit (e.g., to free it).
Try the following code:
[
DllImport("dllName",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.Cdecl)
]
public static extern UInt32 Foo(
string InputWord,
out IntPtr Output, // change to IntPtr
UInt32 Options,
out IntPtr List, // change to IntPtr
out UInt32 Count);
IntPtr output;
IntPtr dummyError = IntPtr.Zero;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x | y, out dummyError, out dummyCount);
You might also need to use the Marshal.AllocHGlobal method to allocate unmanaged memory from your process that is accessible to the C++ code. Make sure that if you do so, you also call the corresponding Marshal.FreeHGlobal method to release the memory.
Given Cody's answer and the comments, you will have to do it this way:
[DllImport("dllName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
extern static UInt32 Foo(string InputWord, out IntPtr Output, UInt32 Options, out IntPtr List, out UInt32 Count);
Now to get the string value in Output marshalled over to managed memory you will do:
string outputValue = Marshal.PtrToStringAnsi(Output);
You must know if TCHAR is Ansi or Unicode and use the appropriate marshal.
Remember to hang onto the Output IntPtr so you can pass that to the native Free method.
Thanks Cody for your answer but I want to make a seperate one, first Output is created by Foo from the native side, and I call FreeFoo to free the allocated memory by Foo.
The following is the code
[DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 Correct(string InputWord, out IntPtr Output, UInt32 Options, out object List,out UInt32 Count);
[DllImport("dllname", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern void FreeFoo(IntPtr Output);
}
To use it:
public string FooWrapper(string Text)
{
IntPtr output;
object dummyError = null;
uint dummyCount = 0;
uint x = 0;
Foo(Text, out output, x,out dummyError,out dummyCount);
string str = Marshal.PtrToStringUni(output);
FreeFoo(output);
return str;
}
Whatever the ErroneousWord type is, you can't marshal an array as a single out object. If it is at all possible to marshal as an object...
I hav a function in c++ DLL that has following prototype
int function(RefPar ¶ms);
how can i call this function from a c# program using "DLLImport".
when i tried like below, AccessViolationException happened while running in visual studio 2008..
[DllImport("VistaGMMDLL.dll", EntryPoint = "function"]
unsafe static extern int function(ref RefPar params);
and called as..
int ret=function(ref params);
Note:RefPar structure has many
unsigned integer values and 1 enum
value as its members.
pls anyone help me to call the function correctly..
A couple of things jump out at me. First of all I don't see why you need to use unsafe. Secondly, you probably have a calling convention mismatch, cdecl in the C++ and stdcall in the C#.
I'd do it like this:
C++
struct RESOURCE_PARAMETERS{
unsigned int uSurfaceHeight;
unsigned int uSurfaceDepth;
unsigned int uSurfaceWidth;
unsigned int uMSAAHeight;
unsigned int uMSAAWidth;
unsigned int uArraySize;
unsigned int uNumSamples;
unsigned int uMaxLod;
unsigned int uBpp;
unsigned int uprefFlag;
unsigned int uusageFlag;
RESOURCE_TYPE_REC ResourceType;
int ResourceFormat;
int iBuildNumber;
};
int function(RefPar ¶meters)
{
}
C#
[StructLayout(LayoutKind.Sequential)]
public struct RESOURCE_PARAMETERS
{
uint uSurfaceHeight;
uint uSurfaceDepth;
uint uSurfaceWidth;
uint uMSAAHeight;
uint uMSAAWidth;
uint uArraySize;
uint uNumSamples;
uint uMaxLod;
uint uBpp;
uint uprefFlag;
uint uusageFlag;
[MarshalAs(UnmanagedType.U4)]
ResourceType ResourceType;
int ResourceFormat;
int iBuildNumber;
}
[DllImport("VistaGMMDLL.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int function(ref RESOURCE_PARAMETERS parameters);
RESOURCE_PARAMETERS parameters = new RESOURCE_PARAMETERS();
int result = function(ref parameters);
I'm not sure how big the enum is on the C++ size. That's why I've put an explicit MarshalAs in the C# code. If it's just a single byte, then use UnmanagedType.U1 instead. I trust you get the idea.
If your C++ function treats its parameter as an in/out parameter then using ref on the C# side is correct. If its actually an out parameter then change the code to be like this:
[DllImport("VistaGMMDLL.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int function(out RESOURCE_PARAMETERS parameters);
RESOURCE_PARAMETERS parameters;
int result = function(out parameters);
Try in this way:
[StructLayout(LayoutKind.Sequential)]
public struct RefPar
{
UInt32 uint1;
UInt32 unti2;
....
}
[DllImport("VistaGMMDLL.dll", EntryPoint = "function"]
unsafe static extern int function(IntPtr params);
//calling
//fill the refParStructure
//create the IntPtr
refParStruct rs = new RefPar();
IntPtr refparPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(refPar)));
Marshal.StructureToPtr(refParStruct, refparPtr,false);
ret=function(refParPtr);
Let Me know if you need more details
Another very simple way to call this function is:
Create a c++ dll warapper that link your original dll and contains this function
//c++ code
function2(uint param1, uint param2.....)
{
RefPar refpar;
refpar.param1=param1
refpar.param2=param2
function(&refpar)
}
in this way you have just to import (in C#) the dll wrapper function in this way
[DllImport("wrapperdll.dll", EntryPoint = "function2"]
static extern int function2(Uint32 param1,Uint32 param2....);
that is very simple to call.
Regards
I am making a wrapper to read TDM and TDMS files but i have a problem
[DllImport(lib, CharSet = CharSet.Auto)]
static extern int DDC_OpenFileEx(
[MarshalAs(UnmanagedType.LPStr)]
string filePath,
[MarshalAs(UnmanagedType.LPStr)]
string fileType,
int read_only,
ref long file);
works fine but
[DllImport(lib, CharSet = CharSet.Auto, SetLastError = true)]
static extern int DDC_GetNumChannelGroups(long file,
[MarshalAs(UnmanagedType.U4)]
ref int numChannelGroups);
int numGru = 0;
errCode = ReadTDM.DDC_GetNumChannelGroups(file,ref numGru);
System.Console.WriteLine("Error Code {0} GetNumChannelGroups", errCode);
gives an error -6202, // An invalid argument was passed to the library.
i have tried ref uint, uint * (unsafe), UIntPtr. The def from .h file
int __stdcall DDC_GetNumChannelGroups (DDCFileHandle file,unsigned int *numChannelGroups);
the second parametr is the problem.
it seems that unsigned int* != uint.
Does anyone have an idea how to call this function form the dll?
http://forums.ni.com/ni/board/message?board.id=60&thread.id=11821
It is the 1st argument that's declared wrong. That throws off the stack frame and prevents the unmanaged code from properly reading the pointer for the 2nd argument. "long" is 64-bits, DDCFileHandle is almost certainly a pointer, 32-bits on a 32-bit operating system.
Change the argument declaration to IntPtr. You'll also need to change the declaration of the function that returns that handle.
I have a delphi dll that is defined like this
type
tSSL_connect = packed record
pssl : Pointer;
pctx : Pointer;
sock : Integer;
end;
function SSLCLT_Connect(pIPAddr: PChar;
iPort: Integer;
var pConn: tSSL_connect;
iTimeout: Integer;
bEnableNonBlockingMode: BOOL = TRUE): BOOL;
stdcall; external cltdll;
I converted to C# like this :
[StructLayout(LayoutKind.Sequential,CharSet = CharSet.Ansi, Pack=1)]
public unsafe struct tSSL_connect
{
public IntPtr pssl;
public IntPtr pctx;
public UInt32 sock;
};
[DllImport("cltdll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern bool SSLCLT_Connect(string pIPAddr, UInt32 iPort, ref tSSL_connect pConn, UInt32 iTimeout, bool bEnableNonBlockingMode);
The call is like this :
tSSL_connect conn = new tSSL_connect();
btest = SSLCLT_Connect("127.0.0.1", 3858, ref conn, 1500, false);
It is asking to open a channel and writes it in conn.
It returns false. So I can't get through. The conn objects returns null. I know that the server is receiving my call.
I think that it has something to do with the struct C# that has a wrong type. I'm pretty new to unmanaged stuff so if anyone can help getting thru.
I have only the dll. Thanks
Try using a char (NULL terminated string) and give the function a pointere to that char as an argument.
Should work for strings.
This may or may not help you but, in your C# code you use UInt32 (32-bit unsigned integer) for tSSL_connect.sock (and in the SSLCLT_Connect prototype) whereas the Delphi header defines it as Integer (32-bit signed integer).
If this doesn't work then the alternative is to write a quick wrapper in delphi that converts between the tSSL_connect record and its fields such that it can be accessed by C#.
I'm not sure if this is your problem but I notice you are just using string in your dllimport. It appears that the default marshalling 'style' for strings is "A COM-style BSTR with a prefixed length and Unicode characters". You need a null terminating string. If that is the issue then use the MarshalAs attribute to set the marshalling type for the pIPAddr parameter:
[MarshalAs(UnmanagedType.LPWStr)]
Like this:
[DllImport("cltdll.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
public static extern bool SSLCLT_Connect([MarshalAs(UnmanagedType.LPWStr)]string pIPAddr, UInt32 iPort, ref tSSL_connect pConn, UInt32 iTimeout, bool bEnableNonBlockingMode);