I have an API written in C++ and am attempting to use this with interop in C# Windows forms.
I am having difficulty defining the equivalent C# struct.
Here is the C++ struct:
typedef struct
{
char SerNo[LENGTH];
HANDLE dev;
} myDevice;
Edit:
Thanks to the comments the first item is solved.
Here is the current C# status:
public unsafe struct sdrplay_api_DeviceT
{
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 64)]
string SerNo;
public IntPtr dev;
}
However nothing I try get's the HANDLE. So I guess at this time, I will expand on the code further:
In the original C++ code, there is a function as follows:
GetDevices(myDevice *devs);
and in the C# code I have done this:
public unsafe static extern GetDevices([In, Out] myDevice[] devs);
Now the code I use is as follows:
myDevice[] devs = new myDevice[6];
var error = GetDevices(devs);
If I look at devs in Visual Studio I see the SerNo (devs[0].SerNo) correctly but the "handle is always 0;
I tried IntPtr, byte, but I am at a loss.
Thanks, Tom
Related
I am trying to wrap the public API in a DLL file for the STMCubeProgrammer in C#. There is header file, documentation, and some C++ examples provided for the library.
The examples projects works well, so I can connect, read, write the target with them.
When I try to wrap the first function which is used in the example from the DLL, and I try to call it from C# simply just nothing happens.
This is the example code (important part):
debugConnectParameters *stLinkList;
int getStlinkListNb = getStLinkList(&stLinkList, 0);
This is from the header file for the DLL:
int getStLinkList(debugConnectParameters** stLinkList, int shared);
With this I get for getStlinkListNb = 1 as 1 STLink is connected
Here is the C# Dll import part:
[DllImport(#"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\api\lib\CubeProgrammer_API.dll")]
public static extern int getStLinkList(ref IntPtr stLinkList, int shared);
And here is my code in my test method:
IntPtr list = IntPtr.Zero;
var count = CubeProgrammerAPI.getStLinkList(ref list ,0);
But nothing happens, count is zero, list is zero, there is no error. I tried different verisons like this with ref, also out, used the In, Out attributes in the method prototype.
I tried with unsafe and pointers:
[DllImport(#"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\api\lib\CubeProgrammer_API.dll")]
public static unsafe extern int getStLinkList(debugConnectParameters** stLinkList, int shared);
CubeProgrammerAPI.debugConnectParameters *dbgParams;
var count = CubeProgrammerAPI.getStLinkList(&dbgParams, 0);
But nothing again
I tried with safe code also, ref array of the struct itself, but nothing happens, no error.
Can somebody help me? Is it normal, that I do not get any error but it is not working either?
Thanks for the help!
Okay I found the problem on an other topic. It is not interop related but related to the DLL I wanted to wrap (mostly).
This is the solution: https://stackoverflow.com/a/62924001/6330997
I've used the PInvoke Interop Assistant to generate a C# PInvoke Signature. I would like confirmation on this. I'm getting the "Can't find PInvoke DLL" message when invoking DLL. I am exporting the function. The DLL is present with executable. The message and cipherText are in/out blob of raw bytes and are the same buffer.
extern "C" int __declspec(dllexport) EncryptDeviceName(uint8 *message, uint8 *ciphertext, uint64 msglength)
{
...
return 0;
}
It generated the following C# PInvoke Signature:
/// Return Type: int
///message: UINT8*
///ciphertext: UINT8*
///msglength: UINT64->unsigned __int64
[DllImport("HC128.dll", EntryPoint = "EncryptDeviceName")]
public static extern int EncryptDeviceName(System.IntPtr message, System.IntPtr ciphertext, ulong msglength);
I'll follow suggestions in the following similar question and provide an update.
UPDATE
My signature does work on Windows CE 6 with marshal alloc/dealloc. Tergiver's signature also works on Windows CE 6 and it does not require marshal alloc/dealloc.
You're missing CallingConvention.Cdecl. Or else use __stdcall on the C side.
There are many ways to write a p/Invoke declaration. The one given can be worked with, however it would require that you perform the Marshaller's job for it (allocating unmanaged memory, copying, and performing character encoding conversion).
That native declaration doesn't provide enough information to guess at the required marshalling, which is probably why it's not there.
What character encoding does the native function expect in message? Is ciphertext a blob of raw bytes or does it too have a character encoding (both in and out)?
Updated
If both message and cipherText are raw byte arrays, we can get them marshalled as
[DllImport("HC128.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "EncryptDeviceName")]
public static extern int EncryptDeviceName([In] byte[] message, [In, Out] byte[] ciphertext, ulong msglength);
The In[Attribute] and Out[Attribute] tell the marshaller which way to perform a copy. [In, Out] is the default, I like to be explicit.
I am having some strange problem. I have written a small module in VC++ using OpenCV.
It works fine. The code aggregates feed from the CCTV camera connected to the USB port.
however, I had to write the rest of my application in C#, so I made a DLL of the VC++ code and called the VC++ method from C#.
Now, I have ended up getting an error
Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
Can anyone please suggest me any solution to this. Is there any Access Violation while accessing it in a managed code?
If TrackBlob returns a string, you should be able to define your dllimport as such:
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static string TrackBlob();
and skip trying to marshal it.
By returning it as an IntPtr, you're trying to get a pointer into memory owned by the unmanaged DLL... returning it as a string will return a copy of the string for you to work with.
Let me know if that works!
James
* Edit *
Try one of these:
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static [MarshalAs(UnmanagedType.BStr)] string TrackBlob();
or
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static [MarshalAs(UnmanagedType.AnsiBStr)] string TrackBlob();
Check out this MSDN link on string marshalling:
http://msdn.microsoft.com/en-us/library/s9ts558h.aspx
I am using VS 2008 C#
Windows Application.
I have this DLL Import I am trying to use.
[DllImport("Mapi32.dll", PreserveSig = true)]
private static extern void
WrapCompressedRTFStream(
[MarshalAs(UnmanagedType.Interface)]
UCOMIStream lpCompressedRTFStream,
uint ulflags,
[MarshalAs(UnmanagedType.Interface)]
out UCOMIStream lpUncompressedRTFStream
);
public const uint MAPI_MODIFY = 0x00000001;
public const uint STORE_UNCOMPRESSED_RTF = 0x00008000;
I have a compressed string that is in CompressedRFTFormat.
How do I pass the string into the WrapCompressedRTFStream? I do not understand what the method is expecting.
I am trying to use it on a button.
RichText1.text = WrapCompressedRTFStream(_CompressedRichText.ToString(),something,somethingelse);
The first error I get is "cannot convert from 'string' to 'System.Runtime.InteropServices.UCOMIStream"
I hope someone who understands this posts an answer that helps!
ok, so I end up in the same situation when I use the IStream.
[DllImport("Msmapi32.dll", PreserveSig = true)]
private static extern void WrapCompressedRTFStream(
[MarshalAs(UnmanagedType.Interface)]
IStream lpCompressedRTFStream,
uint ulflags,
[MarshalAs(UnmanagedType.Interface)]
out IStream lpUncompressedRTFStream
);
The real issue here is I do not understand what / how to deal with the input and output of this method.
I suppose it's not a good idea to use legacy native-code libraries & I would investigate some more time to find analogous code in .net
Try out com interop or p-invoke .net technologies to use legacy code.
If you can't find a native .NET method for doing this, a good approach would be to contain your approach in a Managed C++ wrapper.
What this will let you do is create C++ code to perform your work, while exposing a managed class to call the method. This may be more complicated since it will require you to learn Managed C++, but allows you to do any C++ work necessary, returning a .NET string containing your "answer".
UCOMIStream is deprecated, use ComTypes.Istream instead. Then look at System.Runtime.InteropServices.ComTypes.IStream to System.IO.Stream
I have a dll which comes from a third party, which was written in C++.
Here is some information that comes from the dll documentation:
//start documentation
RECO_DATA{
wchar_t Surname[200];
wchar_t Firstname[200];
}
Description:
Data structure for receiving the function result. All function result will be
stored as Unicode (UTF-8).
Method:
bool recoCHN_P_Name(char *imgPath,RECO_DATA *o_data);
Input:
char * imgPath
the full path of the image location for this
function to recognize
RECO_DATA * o_data
data object for receiving the function
result.
Function return:
True if Success, otherwise false will return.
//end documentation
I am trying to call the recoCHN_P_Name from my C# application. To this end, I came up with this code:
The code to import the dll:
public class cnOCRsdk
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RECO_DATA{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=200)]
public string FirstName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
public string Surname;
}
[DllImport(#"cnOCRsdk.dll", EntryPoint="recoCHN_P_Name")]
public static extern bool recoCHN_P_Name(byte[] imgPath, RECO_DATA o_data);
}
The code to call the function:
cnOCRsdk.RECO_DATA recoData = new cnOCRsdk.RECO_DATA();
string path = #"C:\WINDOWS\twain_32\twainrgb.bmp";
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] bytes = encoding.GetBytes(path);
bool res = cnOCRsdk.recoCHN_P_Name(bytes, recoData);
And the error I'm getting is
""Unable to find an entry point named 'recoCHN_P_Name' in DLL 'cnOCRsdk.dll'."
I'm suspecting that I'm having an error in converting a type from C++ to C#. But where exactly ... ?
First make sure the function is actually exported:
In the Visual Studio Command Prompt, use dumpbin /exports whatever.dll
C# doesn't support C++ name mangling and you either need to declare the C++ functions with
extern "C" {...}
(may not an option if they're from a third party), or call the mangled name directly if you can get it to work. It may be easier to get the third party to provide a non-mangled interface to the functionality.
Solved - at least to the point where the program does not break and actually returns me a bool value.
The key, I guess, was to specify the entry point as the 'mangled' name
[DllImport(#"cnOCRsdk.dll", EntryPoint="?recoCHN_P_Name#CcnOCRsdk##QAE_NPADPAURECO_DATA###Z")]
public static extern bool recoCHN_P_Name(ref string imgPath, ref RECO_DATA o_data);
After that I got some other errors but the 'unable to find entry point' went away.
I solved the same problem in these steps:
step 1) If you program your custom DLL in C++ using Visual studio,then at the property page of your project set the Common Language Runtime Support (/clr)parameter to Common Language Runtime Support (/clr).
step 2) To function deceleration in .h file use __declspec(dllexport) keyword like below:
__declspec(dllexport) double Sum(int a,int b);
step 3) Build and export DLL file, then use the Dependency Walker software to get your function EntryPoint.
step4) Import DLL file In the C# project and set EntryPoint and CallingConvention variable like below:
[DllImport("custom.dll", EntryPoint = "?Sum##YAXHHHHHHNNN#Z", CallingConvention = CallingConvention.Cdecl)]
public static extern double Sum(int a,int b);
I'd write a wrapper using C++/CLI. This wrapper will be able to include the .h files and link to the .lib files you got from the third party vendor. Then it is both easy and safe to write a managed interface for your C# program.
Correct EntryPoint string could be found in ".lib" file that comes along with main unmanaged dll.
We had this problem when we want to access to DB and solved it by changing EF core to EF 6.4.4
It may be you have a problem like this and need to change or downgrade your version of EF (If you used EF)
We had this problem .we change EntityFramework.core to EntityFrameWork 6.4.4 and after that the program worked fine. you most change you're Framework Version.
you may get this error due to string marshalling mismatch between DLL and your application . for example, one is using ANSI and the other is unicode.
you can try something like this:
[DllImport("yourDLL.dll", CharSet = CharSet.Unicode )]
public static extern String YourFunction(String name);
checkout HERE for a list of other possible reasons.
You could try using the unmangled name while specifying a CallingConvention in the DllImport