__declspec(dllexport) ::vector<std::string> - c#

I've been trying to work out how to return an array of strings from a c++ dll to a c# application but am stuck on how to do this or find an article at a very basic level.
Suppose I have the code below. How do I fix the bolded line:
extern "C" {
__declspec(dllexport) int GetANumber();
//unsure on this line:
**__declspec(dllexport) ::vector<std::string> ListDevices();**
}
extern::vector<std::string> GetStrings()
{
vector<string> seqs;
return seqs;
}
extern int GetANumber()
{
return 27;
}
thanks
Matt

You could use the COM Automation SAFEARRAY type, even without doing full COM (no object, no class, no interface, no TLB, no registry, etc.), just with DLL exports, as .NET supports it natively with P/Invoke, something like this:
C++:
extern "C" __declspec(dllexport) LPSAFEARRAY ListDevices();
LPSAFEARRAY ListDevices()
{
std::vector<std::string> v;
v.push_back("hello world 1");
v.push_back("hello world 2");
v.push_back("hello world 3");
CComSafeArray<BSTR> a(v.size()); // cool ATL helper that requires atlsafe.h
std::vector<std::string>::const_iterator it;
int i = 0;
for (it = v.begin(); it != v.end(); ++it, ++i)
{
// note: you could also use std::wstring instead and avoid A2W conversion
a.SetAt(i, A2BSTR_EX((*it).c_str()), FALSE);
}
return a.Detach();
}
C#:
static void Main(string[] args)
{
foreach(string s in ListDevices())
{
Console.WriteLine(s);
}
}
[DllImport("MyUnmanaged.dll")]
[return: MarshalAs(UnmanagedType.SafeArray)]
private extern static string[] ListDevices();

You can't do it directly - you need an extra level of indirection. For a C-style compatible interface you'll need to return a primitive type.
Forget about using C++ DLLs from any other compiler - there is no strict C++ ABI.
So, you'd need to return a opaque pointer to an allocated string vector, e.g.
#define MYAPI __declspec(dllexport)
extern "C" {
struct StringList;
MYAPI StringList* CreateStringList();
MYAPI void DestroyStringList(StringList* sl);
MYAPI void GetDeviceList(StringList* sl);
MYAPI size_t StringList_Size(StringList* sl);
MYAPI char const* StringList_Get(StringList* v, size_t index);
}
And implementation wise:
std::vector<std::string>* CastStringList(StringList* sl) {
return reinterpret_cast<std::vector<std::string> *>(sl);
}
StringList* CreateStringList() {
return reinterpret_cast<StringList*>(new std::vector<std::string>);
}
void DestroyStringList(StringList* sl) {
delete CastStringList(sl);
}
void GetDeviceList(StringList* sl) {
*CastStringList(sl) = GetStrings(); // or whatever
}
size_t StringList_Size(StringList* sl) {
return CastStringList(sl)->size();
}
char const* StringList_Get(StringList* v, size_t index) {
return (*CastStringList(sl))[index].c_str();
}
After doing all of this you can then provide a cleaner wrapper on the C# end. Don't forget to destroy the allocated object via the DestroyStringList function, of course.

You have two "standard" ways to get from C++ to C#.
The first is C++/CLI. In this case you will build a C++/CLI library that takes the std::vector<std::string> and converting that into a System::vector<System::string>. Then you can use it freely as a System.String[] in C#.
The other is COM. There you create a COM interface that returns a SAFEARRAY containing BSTR string. This COM interface is then instantiated though the System.Runtime.InteropServices in C#. The SAFEARRAY is then a Object[] which can be cased to single string objects.
The facility to load C interfaces into C# is basically restricted to C. Any C++ will fail and Pete provides that "non standard" approach. (It works very well, just not what MS wants you to do.)

Related

Suggestions for interop'ing with size_t via PInvoke

We have a native code SDK which predominantly uses the C/C++ size_t type for things like array sizes. We additionally provide a .NET wrapper (written in C#) which uses PInvoke to invoke the native code, for those that want to integrate our SDK into their .NET app.
.NET has the System.UIntPtr type which pairs perfectly with size_t functionally, and functionally everything works as expected. Some of the C# structures provided to the native side contain System.UIntPtr types and they're exposed to consumers of the .NET API which requires them to work with System.UIntPtr types. The problem is that System.UIntPtr does not interoperate well with typical integer types in .NET. Casts are required and various "basic" things like comparisons to integers/literals don't work without more casting.
We tried declaring the exported size_t params as uint and applying the MarshalAsAttribute(UnmanagedType.SysUInt) but that results in a runtime error for invalid marshaling. For example:
[DllImport("Native.dll", EntryPoint = "GetVersion")]
private static extern System.Int32 GetVersion(
[Out, MarshalAs(UnmanagedType.LPStr, SizeParamIndex = 1)]
StringBuilder strVersion,
[In, MarshalAs(UnmanagedType.SysUInt)]
uint uiVersionSize
);
Calling GetVersion in C# passing a uint for the 2nd param results in this marshal error at runtime:
System.Runtime.InteropServices.MarshalDirectiveException: Cannot marshal 'parameter #2': Invalid managed/unmanaged type combination (Int32/UInt32 must be paired with I4, U4, or Error).
We could create facade wrappers which expose 'int' types in .NET and internally do the casting to System.UIntPtr for native-compatible classes, but (a) we worry about performance of copying the buffers (which could be very large) between near-duplicate classes and (b) it's a bunch of work.
Any suggestions on how to PInvoke with size_t types while maintaining a convenient API in .NET?
Here's a sample of one case which is effectively the same as our real code but with simplified/stripped names. NOTE This code is derived from our production code by hand. It compiles for me, but I've not run it.
Native (C/C++) code:
#ifdef __cplusplus
extern "C"
{
#endif
enum Flags
{
DEFAULT_FLAGS = 0x00,
LEVEL_1 = 0x01,
};
struct Options
{
Flags flags;
size_t a;
size_t b;
size_t c;
};
int __declspec(dllexport) __stdcall InitOptions(
Options * const pOptions)
{
if(pOptions == nullptr)
{
return(-1);
}
pOptions->flags = DEFAULT_FLAGS;
pOptions->a = 1234;
pOptions->b = static_cast<size_t>(0xFFFFFFFF);
pOptions->c = (1024 * 1024 * 1234);
return(0);
}
#ifdef __cplusplus
}
#endif
Managed (C#) Code:
(This should to repro the incorrect marshalling. Changing the fields a, b, and c in the struct to type UIntPtr makes it function properly.
using System;
using System.Runtime.InteropServices;
namespace Test
{
public enum Flags
{
DEFAULT_FLAGS = 0x00,
LEVEL_1 = 0x01,
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Options
{
public Flags flags;
public uint a;
public uint b;
public uint c;
}
public class Test
{
[DllImport("my.dll", EntryPoint = "InitOptions", CallingConvention = CallingConvention.StdCall)]
internal static extern Int32 InitOptions(
[In, Out]
ref Options options
);
static void Main(string[] args)
{
Options options = new Options
{
flags = DEFAULT_FLAGS,
a = 111,
b = 222,
c = (1024 * 1024 * 1)
};
Int32 nResultCode = InitOptions(
ref options
);
if(nResultCode != 0)
{
System.Console.Error.WriteLine("Failed to initialize options.");
}
if( options.flags != DEFAULT_FLAGS
|| options.a != 1234
|| options.b != static_cast<size_t>(-1)
|| options.c != (1024 * 1024 * 1234) )
{
System.Console.Error.WriteLine("Options initialization failed.");
}
}
}
}
I tried changing the enum field in the managed struct to a int type and it still doesn't work.
I'll test more with size_t function params next.
The binary equivalent to size_t is IntPtr (or UIntPtr). But for parameters, you can just use int or uint without any additional attribute.
So, if you have this in C/C++:
int InitOptions(size_t param1, size_t param2);
then you can declare it like this in C# and it will work for x86 and x64 (well, you won't get any bit value above 32 of course, the hi-uint is lost):
[DllImport("my.dll")]
static extern int InitOptions(int param1, int param2); // or uint
For x86 it works because, well, it's just supposed to.
For x64, it works magically because arguments are always 64-bit, and luckily, the extra hi-bits are zeroed by errrhh... some components of the system (the CLR? C/C++ compiler? I'm unsure).
For struct fields this a complete different story, the simplest (to me) seems to use IntPtr and add some helpers to ease programming.
However, I've added some extra sample code if you really want to add some sugar for the developers using your structs. What's important is this code could (should) be generated from the C/C++ definitions.
public static int InitOptions(ref Options options)
{
if (IntPtr.Size == 4)
return InitOptions32(ref options);
Options64 o64 = options;
var i = InitOptions64(ref o64);
options = o64;
return i;
}
[DllImport("my64.dll", EntryPoint = "InitOptions")]
private static extern int InitOptions64(ref Options64 options);
[DllImport("my32.dll", EntryPoint = "InitOptions")]
private static extern int InitOptions32(ref Options options);
[StructLayout(LayoutKind.Sequential)]
public struct Options // could be class instead (remove ref)
{
public Flags flags;
public uint a;
public uint b;
public uint c;
public static implicit operator Options64(Options value) => new Options64 { flags = value.flags, a = value.a, b = value.b, c = value.c };
}
[StructLayout(LayoutKind.Sequential)]
public struct Options64 // could be class instead (remove ref)
{
public Flags flags;
public ulong a;
public ulong b;
public ulong c;
public static implicit operator Options(Options64 value) => new Options { flags = value.flags, a = (uint)value.a, b = (uint)value.b, c = (uint)value.c };
}
Note that if you uses classes instead of struct for Options and Options64, you can remove all the ref argument directions and avoid the painful copy from structs (operator overloading doesn't work well with ref). But this has other implications, so it's up to you.
Here is another discussion on the same subject: C# conditional compilation based on 32-bit/64-bit executable target
Basically, what you could also do is use conditional compilation constants for x86 and x64 targets and have your code vary using that.
Here's what I ended up doing:
First some goals:
Expose .NET-friendly and customary types to .NET library users.
Avoid data being silently lost when interop'ing with native code.
Avoid propagating 32-bit/64-bit distinction to .NET library users (in other words, avoid having type differences outside my .NET API due to underlying native DLL bitness; strive for a single data type that (mostly) hides the bitness issue).
Nice to minimize having separate structures and/or code paths for 32-vs-64 bit.
Naturally all things developers prefer (less code to write & maintain, easier to keep in sync, etc).
FUNCTIONS
The C functions exported from the DLL are presented in the DllImport with .NET types as close as possible to the native (C) types. Then each function is wrapped with a more-inline-with-.NET facade.
This accomplished 2 things:
Preserving the native types in the DllImport avoids silent (!)
data loss. As Simon Mourier pointed out, .NET can use uint in
place of size_t in functions. While this seems to work, it also
will silently drop data that's out of range. So if the native code
returns a value larger than uint.MaxValue, our .NET code will never
know. I'd rather handle the situation than have some spurious bug.
Various techniques and types which are specific to C and/or
non-object oriented are presented in a style more native to .NET.
For example, buffers in the C API which are presented as a byte
pointer plus a size parameter are presented as simply byte arrays in
.NET. Another example is non-zero-terminated strings (ex. UTF, XML)
are presented in .NET as a String or Xml object instead of byte
array and size parameters.
Specifically for size_t function params, they are presented as UIntPtr in the DllImport (per #1 above), and if still necessary to be exposed to the library user, they are presented as either uint or ulong as applicable. The facade then verifies the value of each (in/out as applicable) and throws an exception if
there's an incompatibility.
Here's an example using pseudo-code:
C Function:
// Consume & return data in buf and pBufSize
int __declspec(dllexport) __stdcall Foo(
byte * buf,
size_t * pBufSize
);
C# DllImport:
[DllImport("my.dll", EntryPoint = "Foo", CallingConvention = CallingConvention.StdCall)]
private static extern System.Int32 Foo(
[In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
System.Byte[] buf,
[In, Out]
ref System.UIntPtr pBufSize
);
C# Facade (pseudo-code):
void Foo(System.Byte[] buf)
{
// Verify buffer size will fit
if buf.LongLength > UIntPtrMaxValue
throw ...
UIntPtr bufSize = buf.LongLength;
Int32 nResult = Foo(
buf,
bufSize
);
if nResult == FAILURE
throw ...
// Verify return size is valid
if (UInt64)bufSize > int.MaxValue // .NET array size type is 'int'
throw ...
buf.resize((int)bufSize);
}
STRUCTURES
To interop with structures containing size_t (and even in general), I followed a similar approach as with functions: create a .NET structure ("Interop Structure") which most closely resembles the native-code structure, and then put a .NET-friendly facade around it. The facade then does value checking as appropriate.
The specific implementation approach I took for the facade was to setup each field as a property with the Interop Structure as the backing store. Here's a small example:
C Structure:
struct Bar
{
MyEnum e;
size_t s;
}
C# (pseudo-code):
public class Bar
{
// Optional c'tor if param(s) are required to be initialized for typical use
// Accessor for e
public MyEnum e
{
get
{
return m_BarInterop.e;
}
set
{
m_BarInterop.e = value;
}
}
// Accessor for s
public uint s
{
get
{
VerifyUIntPtrFitsInUint(m_BarInterop.s); // will throw an exception if value out of range
return (uint)m_BarInterop.s;
}
set
{
// uint will always fit in UIntPtr
m_BarInterop.s = (UIntPtr)value;
}
}
// Interop-compatible 'Bar' structure (not required to be inner struct)
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal struct Bar_Interop
{
public MyEnum e;
public System.UIntPtr s;
}
// Instance of interop-compatible 'Bar' structure
internal Bar_Interop m_BarInterop;
}
While a bit tedious at times, I've found that after taking this approach for only 2 structures so far it's yielded great flexibility and a clean API being exposed to consumers of my .NET wrapper.

How to pass a string or string equivalent between C# and C++ that is in a struct? [duplicate]

I thought the problem is inside my C++ function,but I tried this
C++ Function in C++ dll:
bool __declspec( dllexport ) OpenA(std::string file)
{
return true;
}
C# code:
[DllImport("pk2.dll")]
public static extern bool OpenA(string path);
if (OpenA(#"E:\asdasd\"))
I get an exception that the memory is corrupt,why?
If I remove the std::string parameter,it works great,but with std::string it doesnt work.
std::string and c# string are not compatible with each other. As far as I know the c# string corresponds to passing char* or wchar_t* in c++ as far as interop is concerned.
One of the reasons for this is that There can be many different implementations to std::string and c# can't assume that you're using any particular one.
Try something like this:
bool __declspec( dllexport ) OpenA(const TCHAR* pFile)
{
std::string filename(pFile);
...
return true;
}
You should also specify the appropriate character set (unicode/ansi) in your DllImport attribute.
As an aside, unrelated to your marshalling problem, one would normally pass a std:string as a const reference: const std:string& filename.
It's not possible to marshal a C++ std::string in the way you are attempting. What you really need to do here is write a wrapper function which uses a plain old const char* and converts to a std::string under the hood.
C++
extern C {
void OpenWrapper(const WCHAR* pName) {
std::string name = pName;
OpenA(name);
}
}
C#
[DllImport("pk2.dll")]
public static extern void OpenWrapper( [In] string name);
I know this topic is a tad old but for future googlers, this should also work (without using char* in C++)
C#:
public static extern bool OpenA([In, MarshalAs(UnmanagedType.LPStr)] path);
C++:
bool __declspec( dllexport ) OpenA(std::string file);
std::wstring and System.string can be compatible through below conversion:
C++ :
bool func(std::wstring str, int number)
{
BSTR tmp_str = SysAllocStringLen(str.c_str(), str.size());
VARIANT_BOOL ret = VARIANT_FALSE;
// call c# COM DLL
ptr->my_com_function(tmp_str, number, &ret);
SysFreeString(tmp_str);
return (ret != VARIANT_FALSE) ? true : false;
}

Is it possible to import unmanaged class or struct from DLL using C# DllImport?

As msdn http://msdn.microsoft.com/en-us/library/aa288468(v=vs.71).aspx says "Platform Invocation Services (PInvoke) allows managed code to call unmanaged functions that are implemented in a DLL."
I want to import some class from DLL that i made in c++
Is it possible and how?
for example, i have some structures inside DLL:
struct __declspec(dllexport) DLLVector3
{
float x, y, z;
};
struct __declspec(dllexport) DLLQuaternion
{
float x, y, z, w;
};
class __declspec(dllexport) DLLCharacter
{
public:
DLLVector3 position;
DLLQuaternion orientation;
DLLCharacter()
{
}
~DLLCharacter()
{
}
void setPosition(PxVec3 pos)
{
position.x = pos.x;
position.y = pos.y;
position.z = pos.z;
}
void setOrientation(PxQuat or)
{
orientation.x = or.x;
orientation.y = or.y;
orientation.z = or.z;
orientation.w = or.w;
}
};
struct __declspec(dllexport) PhysicalObject
{
DLLCharacter *character;
PxRigidActor *mActor;
PxController *mController;
};
Which way i can import those? Especially those structures with pointers
You don't need to write C++ managed code for access - but - you can't easily hop around between unmanaged and managed memory. Here's a few key points
1) Use [StructLayout(LayoutKind.Sequential)] to define .net classes that map on top of your c++ structs
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public struct SFVec3F : IRawStreamIO
{
public double _x;
public double _y;
public double _z;
}
2) Basic types like doubles, int32, etc move across the P/Invoke layer efficiently - more complex types earn you the .net variant of thunking - msft doco covers which data types move efficiently, try and use them
3) Everything that's a pointer in C++ land is an IntPtr in .net land and if you want to be safe you should treat it as a handle, i.e. you get the c++ side to do any manipulations/access to the underlying structure
4) Access to the native C++ is pretty straightforward (the Handle props are IntPtrs that were originally sourced on the native C++ side)
[DllImport("CS2V3.dll", CharSet = CharSet.Ansi)]
private static extern void AddChild(IntPtr csoPtr, IntPtr childPtr, short recomputeBounds, short adjustCoords, short blindchild);
public void AddChild(V3CSO theChild)
{
AddChild(m_handle, theChild.Handle,0,0,0);
}
5) Strings and some other types require marshalling to obtain a .net usable form - note that this happens automatically for strings when you pass a string to unmanaged code, but you have to do it yourself when it's inbound
[DllImport("CS2V3.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetName(IntPtr csoPtr);
[DllImport("CS2V3.dll", CharSet = CharSet.Ansi)]
private static extern void SetName(IntPtr csoPtr, string newName);
public string Name
{
get
{
IntPtr np = GetName(m_handle);
return Marshal.PtrToStringAnsi(np);
}
set
{
SetName(m_handle, value);
}
}
This is possible.... but you need to write wrapper code in C++/CLI. This allows you to write classes that can be used from C#/.net code (on the outside it is managed code), and in the implementation you can use C++ code.
You can't import the C++ classes directly. Only C-style functions. C-style functions only allow you to pass C primitive types, which makes interopping with them easy. In general, from non-C++ code, it is close to impossible to correctly pass in C++ types. And if you can't pass in C++ objects, there are typically very few interesting functions that you can call.
Later edit:
Alternatively, you can write a C-style wrapper function for your unmanaged functionality. You will have to pass all parameters in one go (you can pass structs), but you can write the wrapper in standard C/C++.

How do I call a function defined in a C++ DLL that has a parameter of type int *, from inside C# code?

I have a native regular C++ Dll which I want to call from C# code, so i created C++/CLI class (as described here and here) which will include managed C++ code and which can be called by any C# code directly and which can make calls inturn to native unmanaged C++.
One of function in native C++ dll has parameter of type int *. How do I declare in wrapper function and how can i convert it into int *?
It is the C/C++ way of passing a value by reference. You should use the ref or out keyword:
[DllImport("something.dll")]
private static extern void Foo(ref int arg);
In C++/CLI that would look roughly like this:
public ref class Wrapper {
private:
Unmanaged* impl;
public:
void Foo(int% arg) { impl->Foo(&arg); }
// etc..
};
[DllImport("some.dll")]
static extern void SomeCPlusPlusFunction(IntPtr arg);
IntPtr is a type that is roughly equivalent to void *.
From your comment, you'd be best off doing something like this (C#):
int size = 3;
fixed (int *p = &size) {
IntPtr data = Marshal.AllocHGlobal(new IntPtr(p));
// do some work with data
Marshal.FreeHGlobal(data); // have to free it
}
but since AllocHGlobal can take an int, I don't know why you wouldn't do this:
IntPtr data = Marshal.AllocHGlobal(size);

std::string in C#?

I thought the problem is inside my C++ function,but I tried this
C++ Function in C++ dll:
bool __declspec( dllexport ) OpenA(std::string file)
{
return true;
}
C# code:
[DllImport("pk2.dll")]
public static extern bool OpenA(string path);
if (OpenA(#"E:\asdasd\"))
I get an exception that the memory is corrupt,why?
If I remove the std::string parameter,it works great,but with std::string it doesnt work.
std::string and c# string are not compatible with each other. As far as I know the c# string corresponds to passing char* or wchar_t* in c++ as far as interop is concerned.
One of the reasons for this is that There can be many different implementations to std::string and c# can't assume that you're using any particular one.
Try something like this:
bool __declspec( dllexport ) OpenA(const TCHAR* pFile)
{
std::string filename(pFile);
...
return true;
}
You should also specify the appropriate character set (unicode/ansi) in your DllImport attribute.
As an aside, unrelated to your marshalling problem, one would normally pass a std:string as a const reference: const std:string& filename.
It's not possible to marshal a C++ std::string in the way you are attempting. What you really need to do here is write a wrapper function which uses a plain old const char* and converts to a std::string under the hood.
C++
extern C {
void OpenWrapper(const WCHAR* pName) {
std::string name = pName;
OpenA(name);
}
}
C#
[DllImport("pk2.dll")]
public static extern void OpenWrapper( [In] string name);
I know this topic is a tad old but for future googlers, this should also work (without using char* in C++)
C#:
public static extern bool OpenA([In, MarshalAs(UnmanagedType.LPStr)] path);
C++:
bool __declspec( dllexport ) OpenA(std::string file);
std::wstring and System.string can be compatible through below conversion:
C++ :
bool func(std::wstring str, int number)
{
BSTR tmp_str = SysAllocStringLen(str.c_str(), str.size());
VARIANT_BOOL ret = VARIANT_FALSE;
// call c# COM DLL
ptr->my_com_function(tmp_str, number, &ret);
SysFreeString(tmp_str);
return (ret != VARIANT_FALSE) ? true : false;
}

Categories