need help converting c++ definitions to c# equivalent - c#

I'm using an API (written in c++) to connect to a DVR machine, actually I only have the .dll and the .lib files, and I want to do the job in .NET (C#).
So, the API doc contains definitions to all functions inside the dll, and I'm having a hard time trying to figure out how to translate those functions to equivalente C# definitions. Some of them are straightforward, but some I cannot make it work.
For example, there is this function:
bool searchEvent(int channel, const LONG* condition, bool next)
In my c# class I put the following:
[DllImport("search.dll")]
protected static extern bool searchEvent(int channel,
[MarshalAs(UnmanagedType.I8)]long condition, bool next);
but when I call the searchEvent function, it raises an error (memory error), I guess because of that long var. So my question is how can I translate "const LONG* condition" to c#?
Also, that searchEvent function triggers a callback that returns a struct. I am unable to translate some vars of that struct, like:
char _version[2]
time_t _time
BYTE* _minute
unsigned short int _dwell[MAX]
Can someone help me with this, please? I´m no expert in c++, so any tips are greatly appreciated. Thanks!

[DllImport("search.dll")]
[return: MarshalAs(UnmanagedType.U1)]
private static extern bool searchEvent(
int channel,
ref int condition,
[MarshalAs(UnmanagedType.U1)] bool next
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct Mumble {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2)]
public string version;
public long time;
public IntPtr minute;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX)]
public ushort _dwell[];
}
You will have to marshal the Mumble.Minute value yourself with Marshal.ReadXxxx(). These declarations are not great for interop, writing a wrapper in the C++/CLI language is advisable.

Without getting into the specifics, you need to overcome two hurdles:
1) Since you don't have the original .h (header) file, you're guessing as to what it could be, based on the API documentation. Hopefully you'll get it right, but there may be some subtle things in the header file that won't be in the documentation, such as structure packing, calling convention, name mangling, etc. You can start by assuming the defaults for this stuff. Bottom line you have to experiment.
2) You are attempting to create P/Invoke calls into a C DLL when you don't have the original header file. You don't know even know if you know how to make these calls from C, much less C#.
By doing this straight from C#, you're trying to attack these two issues at the same time. when something doesn't work, you're not sure if it's because you go the P/Invoke syntax wrong, or it's an issue related to your interpretation of what the header file content looks like. I'd try to attack these problems one at a time. First, try to make the DLL calls from a simple C console app. This shouldn't be difficult to create, then hand build a .H file, and very that you can make all the calls.
After you're done with that, you now have to get those calls to work from C#.
Frankly, I avoid P/Invoke unless I can just reuse one that someone else created (from http://PInvoke.net) for the Windows API. If I were you, and I already new how to make the calls from C, I'd just create a C++/CLI wrapper DLL for it. The advantage is that, you make the calls exactly as you do in the console app -- no P/Invoke necessary. And then expose those calls from the C++/CLI DLL as .NET. Your C# code will call the C++/CLI DLL, which looks just like (and is) a .NET component, with no weird P/Invoke stuff in the C# code.
Good luck.

Related

c# dll import entry point with colons / scope

Looking to dll import from vssapi.dll,
Looking at the GetSnapshotDeviceName function, and DLL export viewer gives me:
protected: long __cdecl CVssWriter::GetSnapshotDeviceName(unsigned short const * __ptr64,unsigned short const * __ptr64 * __ptr64)const __ptr64
protected: long __cdecl CVssJetWriter::GetSnapshotDeviceName(unsigned short const * __ptr64,unsigned short const * __ptr64 * __ptr64)const __ptr64
Assuming I want the first one, how do I declare the dll import,
for instance:
[DllImport("vssapi.dll", EntryPoint = "CVssWriter::GetSnapshotDeviceName", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
private static extern uint GetSnapshotDeviceName(string wszOriginalVolume, out string ppwszSnapshotDevice);
[With or without the ExactSpelling] always gives me the
Unable to find an entry point named
'CVssWriter::GetSnapshotDeviceName' in DLL 'vssapi.dll
error. Variations on the colons (removing etc), and reversing the names (as the decorated version) gave me no joy either.
I know it can work using the decorated name or the ordinal, but I'd like the code to be reasonably portable (decls being compiler dependent, and nothing I've ever seen says ordinals will stay the same in updates either).
Yeah I already know with this dll it won't port to pre Vista ... that I can live with.
Also heard about AlphaVSS too - but for what I need would be like using an aircraft carrier to go fishing on a lake (- and did they really need to make it so ungainly to use?)
These are C++ instance methods, that is member functions. As such, they cannot be imported using p/invoke. This API for VSS that you are attempting to use is available either as C++ classes, or via COM.
If the functionality that you need is available through the COM interface, then that will be the simplest way for you to proceed. Otherwise you will need to wrap the C++ classes one way or another. Surely the simplest way to do that will be with a mixed mode C++/CLI assembly.
Either way, p/invoke cannot help you here.

P/Invoke Calls Failing

I have the following struct defined in C++:
struct GraphicsAdapterDesc {
// ... Just some constructors / operators / destructor here
DEFINE_DEFAULT_CONSTRUCTOR(GraphicsAdapterDesc);
DEFINE_DEFAULT_DESTRUCTOR(GraphicsAdapterDesc);
ALLOW_COPY_ASSIGN_MOVE(GraphicsAdapterDesc);
std::wstring AdapterName;
int32_t AdapterNum;
std::wstring HardwareHash;
int64_t DedicatedVMEM;
int64_t DedicatedSMEM;
int64_t SharedSMEM;
int32_t NumOutputs;
};
In C#, I have a 'mirror' struct declared thusly:
[StructLayout(LayoutKind.Sequential)]
public struct GraphicsAdapterDesc {
string AdapterName;
int AdapterNum;
string HardwareHash;
long DedicatedVMEM;
long DedicatedSMEM;
long SharedSMEM;
int NumOutputs;
};
I've tried to be really careful about matching up the widths of the variables (although I'm a bit unsure on what to do with the strings exactly).
Anyway, I have the following exported C method:
extern "C" __declspec(dllexport) bool GetGraphicsAdapter(int32_t adapterIndex, GraphicsAdapterDesc& outAdapterDesc) {
outAdapterDesc = RENDER_COMPONENT.GetGraphicsAdapter(adapterIndex);
return true;
}
And, the following extern method in my C# app:
[DllImport(InteropUtils.RUNTIME_DLL, EntryPoint = "GetGraphicsAdapter", CallingConvention = CallingConvention.Cdecl)]
internal static extern bool _GetGraphicsAdapter(int adapterIndex, out GraphicsAdapterDesc adapterDesc);
However, this doesn't work right when I call it. I get a different result depending on whether or not I'm compiling in x64 or x86 mode (both the C++ DLL and the C# app are compiled as x86 or x64):
In x86 mode, the call returns, but the struct has 'nonsense' values in, and the strings are all null,
In x64 mode, the call throws a NullPointerException.
My expectation is that I'm doing something wrong marshalling the strings, and that I need to specify 'wide-mode' for the characters, but I don't know how (or if that's even the right option).
Thank you in advance.
C++ types are not compatible with C# unless they're wrapped in managed C++. and you're using std::wstring which cannot be marshaled into .NET.
To interop successfully you'll either need to use a wchar_t[] or a whar_t* and tell C# now to marshal it.
I don't know what your macros are doing but this will only work if your c++ type is POD. c++11 Has an expanded sense of POD but I don't think you meet the expanded criteria anyway. Otherwise you can't guarantee layout. If you want to export your c++ classes to C# I would suggest you use c++\cli. Also you have wstring defined in your stuct which are definitely not POD. When you use DLLImport think C constructs only or you are going to have a bad time.

Calling unmanaged c++ code in C# Mixed with STL

Hey, I want to call unmanaged c++ code in C#
The function interface is like following(I simplified it to make it easy to understand)
Face genMesh(int param1, int param2);
Face is a struct defined as:
struct Face{
vector<float> nodes;
vector<int> indexs;
}
I googled and read the MSDN docs found ways to call simple c/c++ unmanged code in C#, also know how to hand the struct as return value. And My question is how to handle "vector". I did not find rules about mapping between vector and some types in C#
Thanks!
You want, if possible, to avoid using STL in anything but pure UNmanaged code. When you mix it with C++/CLI (or Managed C++), you will likely end up with the STL code running as managed and the client code running as unmanaged. What happens is that when you, say, iterate over a vector, every call to a vector method will transition into managed code and back again.
See here for a similar question.
You're probably going to need to pass the raw arrays unless you really want to jump through some hoops with the interop as the rules specify the types have to either be marhallable by the framework, or you've given the framework a specific structure it can marshall. This probably is not possible for vector. So, you can define you C++ struct as
#pragma pack(push, 8)
struct ReflSettings
{
double* Q;
double* DisplayQ;
}
#pragma pack(pop)
then you C# struct would be
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
public class ModelSettings:IDisposable
{
[XmlIgnore] internal IntPtr Q;
[XmlIgnore] internal IntPtr DisplayQ;
}
Hope this helps.
Probably the simplest thing to do is to create a managed class in C++ to represent the 'Face' structand copy the it's contents into the new managed class. Your c# code should then be able to understand the data.
You could use an ArrayList in place of the vectors.

How do I use DLLImport with structs as parameters in C#?

All the examples I can find using DLLImport to call C++ code from C# passes ints back and forth. I can get those examples working just fine. The method I need call takes two structs as its import parameters, and I'm not exactly clear how I can make this work.
Here's what I've got to work with:
I own the C++ code, so I can make any changes/additions to it that I need to.
A third party application is going to load my DLL on startup and expects the DLLExport to be defined a certain way, so i can't really change the method signature thats getting exported.
The C# app I'm building is going to be used as a wrapper so i can integrate this C++ piece into some of our other applications, which are all written in C#.
The C++ method signature I need to call looks like this
DllExport int Calculate (const MathInputStuctType *input,
MathOutputStructType *output, void **formulaStorage)
And MathInputStructType is defined as the following
typedef struct MathInputStuctTypeS {
int _setData;
double _data[(int) FieldSize];
int _setTdData;
} MathInputStuctType;
The MSDN topic Passing Structures has a good introduction to passing structures to unmanaged code. You'll also want to look at Marshaling Data with Platform Invoke, and Marshaling Arrays of Types.
From the declaration you posted, your C# code will look something like this:
[DllImport("mydll.dll")]
static extern int Calculate(ref MathInputStructType input,
ref MathOutputStructType output, ref IntPtr formulaStorage);
Depending on the structure of MathInputStructType and MathOutputStructType in C++, you are going to have to attribute those structure declarations as well so that they marshal correctly.
For the struct:
struct MathInputStuctType
{
int _setData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = FieldSize)]
double[] _data;
int _setTdData;
}
You might want to look at this project on CodePlex, http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120. It should help you marshal the structures correctly.

p/invoke C function that returns pointer to a struct

How do I declare in C# a C function that returns a pointer to a structure?
I believe following is one way to do that, followed by Marshal.PtrToStructure to get actual structure value.
// C-function
SimpleStruct * Function(void);
// C# import
[DllImport("MyDll.dll")]
public static extern IntPtr Function();
Am I correct about that?
Are there other ways to accomplish the same? (It would be OK to get struct back by value)
Since the function returns a pointer (hopefully not a locally allocated one?) your best bet is to manually marshal it (via Marshal.PtrToStructure).
If it were a parameter you could create a managed version of the structure using the PInvoke Interop Assistant then pass it via ref or out.
Caveat: this will only work if the pointer returned is to memory already managed by the CLR
I believe what you are looking for is
// C# import
[DllImport("MyDll.dll")]
[return : MarshalAs(UnmanagedType.LPStruct)]
public static extern StructureName Function();
[StructLayout(LayoutKind.Sequential)]
public class StructureName {}
This should eliminate the need for any manual Marshal.PtrToStructure calls. Depending on what your structure contains, you may need to tag some fields with MarshalAs attributes as appropriate. MSDN has a good example of this.
I am not an expert here at all, but I happened to be looking at a piece of code (that i don't understand completely mind you) that is doing this same thing.
Here is what they are doing
[DllImport("")]
private static extern short MethodName([In,Out] ref StructureName variable);
and then on the structure they have the following attribute
[StructLayout(LayoutKind.Sequential, Size = #)]
public struct StructureName {}
I think the part you are looking for is the [In,Out] part, and since it's being passed via ref, you should be getting the same data back.
marked as community wiki so people can fix this if wrong.

Categories