Passing string array from C# to C++ through interop - c#

I have a COM component which is written in C++ which I want to call its interface in my C# application through interop.
The interface which I want to call is defined like this:
C# interop interface definition:
void ICertainInterface.Func(int cnt, ref string colors)
C++ definition:
ICertainInterface : IUnknown
{
virtual HRESULT Func(long cnt, BSTR * colors) = 0;
}
This is clear to me that, the interface is expected a BSTR array with specific lenth from my application. The 2nd parameter BSTR * colors suppose to stand for the 1st string address in my string array.
Now this is the code I used to call up the interface from my C# application:
ICertainInterface obj = GetInterface();
string[] strArray = new string[4];
strArray[0] = "aaa";
strArray[1] = "bbb";
strArray[2] = "ccc";
strArray[3] = "ddd";
obj.Func(4, ref strArray[0]);
Once I run the application, error given "Attempted to read or write protected memory". This won't happen if the array size is only 1.
It seems to me that, because the string array is managed data in C#. So the memory allocation is not predictable, Once I pass strArray[0] as a reference to C++ interface, the interface will take it as the starting address of an array and assume add by 4 will get the address for next element but which could not be go in the same way in C# memory allocation.
I searched some post from online, seems most interfaces user "ref string[]" as the pointer to an C# array but not like this "ref string" which I can only refer to the 1st element in the array (I even don't know if it is the right approach, because in C++ the 1st element address is equivalent to the array address.)
Further more, I did a same test in excel VBA code which called the same interface:
Dim msColor(4) As String
msColor(0) = "aaa"
msColor(1) = "bbb"
msColor(2) = "ccc"
msColor(3) = "ddd"
Dim obj as ICertainInterface
Set obj = GetInterface();
Call obj.Func(4, msColor(0))
This VBA code works perfect without any error.
Now I totally have no idea how to fix this in my C# application. Can someone point me a way? I would very much appreciate.

Shouldn't the method signature be
void ICertainInterface.Func(int cnt, ref string[] colors)
...and instead of passing the first element in the array, pass the entire array?
Arrays in C# don't behave like arrays in C/C++; you can't just pass a reference to the first element and expect to be able to access the rest of the elements using pointer arithmetic.
Edit: You probably don't need the ref keyword in there, either.

You may need to marshal to appropriate type in order to pass between CLR and non CLR processes
Here you go with the correct signature
so if you are trying to pass a single string then
void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.BStr)] ref string colors)
or if it is kind of array then
void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_BSTR)] ref string[] colors)
I made this solution based on your code. If above solution does not work for you then you may try finding the appropriate array type/subtype suitable for your application here http://msdn.microsoft.com/en-us/library/z6cfh6e6(v=vs.110).aspx and for string types here http://msdn.microsoft.com/en-us/library/s9ts558h(v=vs.110).aspx
using DllImport attribute example
if you are trying to pass a single string then
[DllImport("yourLib.dll", EntryPoint = "Func")]
public static extern void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.BStr)] ref string colors)
if it is kind of array then
[DllImport("yourLib.dll", EntryPoint = "Func")]
public static extern void ICertainInterface.Func(int cnt,[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_BSTR)] ref string[] colors)
This may help you achieve the same, Dll import is usually used to call win api

Related

How can I pass and save C/C++ pointers to C#, and return them back, using Mono Project

I'm having a serious problem figuring out how to pass and store effectively C pointers to C#, and then returning them back when I need them with Mono. I'm building a scripting layer with C# on top of C++. For example (pseudocode):
C++:
GameObject* owner = new GameObject();
void* args[1] = {owner};
return_object = mono_runtime_invoke("InitReference", mono_object, args, &exception);
C#: (C# GameObject class instance)
public IntPtr InitReference(IntPtr game_object_ptr)
{
return game_object_ptr;
}
What I want to achieve is a relation between the C++ object instance and the actual C# representation. There is little information about this, and I'm a little lost.
My suggestion:
New a .Net struct which has StructLayout attribute, like:
[StructLayout( LayoutKind.Explicit )]
public struct GameObject
{
[FieldOffset(0)]
public int Id;
......
}
then .net pointer can point the struct instance.
After some trying i solved my problem:
First I stored my pointer address into a char buffer, and then I passed it to mono as an array of ints int[]. This allowed my pointer adress to stay alive in the C# environment, and I'm able to retrieve it whenever I want.

Powerbuilder calling C# DLL (RGiesecke dll Export template)

I need to call a 'classic' DLL C# (not COM) from Powerbuilder.
The creation of the DLL in C# I based on this example:
RGiesecke dll Export template.
And I managed to call the DLL from within Powerbuilder.
BUT I want to pass the string 'as reference': so I added 'ref' to the function declaration:
[DllExport("ExpTest", CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static string ExpTest([MarshalAs(UnmanagedType.LPWStr)] ref string sText, out int length)
{
MessageBox.Show(sText, "ExpTest");
length = sText.Length;
//sText = "def";
return sText;
}
The code from Powerbuilder calling this function:
String ls_arg, ls_ret
ls_arg = "abc"
long ll_len
ls_ret = ExpTest(ls_arg, ll_len)
messagebox(ls_arg, ls_ret)
When calling the original functio (without 'ref' to the 'string sTest' declaration), it returns "abc".
When I add 'ref' to the 'string sTest' declaration, it returns some 'chinese characters').
Can anyone help?
Even better: how to pass an array of strings (by ref) from and to Powerbuilder?
Thanks for your help!!
Msc.
Tried to define the External functions in Powerbuilder like this:
- FUNCTION String ExpTest(REF String value, REF long len) LIBRARY "Classicdll.dll"
- FUNCTION String ExpTest(String value, REF long len) LIBRARY "Classicdll.dll"
- and both with ALIAS FOR "ExpTest;Ansi"...
Do not use ref. You have to use ref only if you want to change what the object is not what it contains!
Strings in .NET are special objects. They're acting like a value type but they're a reference type.
More information can be found here:
https://www.codeproject.com/articles/6852/strings-in-net
http://csharpindepth.com/Articles/General/Strings.aspx
I think your chinese characters are the reference, as a string, to the String object and not a String which contains chinese characters.
EDIT:
It looks like that using unmanged exports is a ugly hack.
So creating a C# COM *.dll would be the better (supported) way of writing extensions for PowerBuilder.

Deleting a uint8_t array defined with first pointer and number of elements

I'm calling a c++ dll from my C# program. It appears that, once a variable is passed to unmanaged code, C# doesn't want anything to do with it, as a result my program is leaking memory like crazy.
Here's the C# part of the code:
byte[] bytes = MyData;
int array_lenght = bytes.Length;
DataProcessor(bytes, array_lenght);
DataProcessor is defined as
[DllImport("Processor", EntryPoint = "DataProcessor")]
public static extern void DataProcessor(byte[] array, int ArrayElementCount);
Here's the DLL side of the DataProcessor function:
void DataProcessor (uint8_t* InputArray, int ArrayElementCount)
// do some stuff here
Now it appears I need to delete this array(InputArray) from DLL, however I couldn't find a way to do that. I tried stuff like
delete *(InputArray + i) // inside a for loop
And mapping array to a vector like this and clearing it
std::vector<uint8_t> fckn_vector(InputArray, InputArray + ArrayElementCount);
fckn_vector.clear();
I'm 100% sure that there must be a very simple way to do this, however I'm not good with C++.
You can use the Marshal.FreeCoTaskMem method:
Marshal.FreeCoTaskMem(InputArray);

trying to use clr dll but cannot call method from c#

I have a library of c functions I am trying to access from c#. I have tried the PInvoke route but there were structs containing variable length arrays so this approach wasn't working and I was advised to try c++/cli. After looking into it (and asking a lot more questions) I have created a wrapper class for one of my c functions. The input to the c function is a struct that contains two double arrays and the length of one of the arrays (the other being fixed size), as well as a double. I was able to create a little test app (clr console) for my wrapper so I know that its calling the c code and doing what its supposed to, I now just need to figure out how to call it from c#. As its now a managed dll I have added it to my references and I can put it in the code but the method signature has transformed the arrays into pointers whch I cant do in c#. I tried just apssing the arrays, using ref, cant figure out how to make this work.
c++ signature:
static void test_wrapper(double prefix[], double arr[], int arrayLength, double value);
so when I call this in c# its:
Test_Wrapper_Class.test_wrapper(???, ???, array.Length, 2.2);
however the ??? is showing its expecting a double* and I'm not quite sure what to put in for that.
for bonus points I would like to return a double array but not sure about which way to do it. Options for this would be:
just reuse arr as the returned array will be same size
add another double[] in input and fill that one
return a double[]
It is not terribly clear why are making it difficult for the C# to use your function. Keep in mind that the C++/CLI language allows you to either use managed or unmanaged arrays. You are using an unmanaged array as an argument now, so giving the C# code a hard time to call the function. It isn't impossible with unsafe code:
static unsafe void Main(string[] args) { // NOTE unsafe keyword
var arg1 = new double[] { 1, 2, 3 };
var arg2 = new double[] { 4, 5, 6 };
fixed (double* arg1ptr = arg1)
fixed (double* arg2ptr = arg2) {
Test_Wrapper_Class.test_wrapper(arg1ptr, arg2ptr, arg1.Length, 42.0);
}
}
Note how the C# code needs to use the unsafe keyword. And how it is truly unsafe, you didn't include an argument that says how long the 2nd array is so the native code can easily scribble into the GC heap and corrupt it.
But that isn't necessary when you declare the arguments as managed arrays:
static void test_wrapper(array<double>^ prefix, array<double>^ arr, double value);
Safe and easy to call from C#. Note how you no longer need to pass the array length argument, you already know it from prefix->Length. If necessary at all, you can use pin_ptr<> in your C++/CLI code to get a double* that native code can use. Be careful, it is only pinned temporarily.

Accessing native objects via C++/CLI from C#!

I have written a C# application that injects a DLL into a third-party executable (which happens to have been built using the Qt framework). This DLL uses EasyHook to intercept calls to a number of specific functions. When my injected code is called, I then try to inspect some of the objects that are parameters to these functions.
For example, I have intercepted a call made to parse some XML:
virtual bool __thiscall QXmlSimpleReader::parse(class QXmlInputSource const &)
In my C# code, I have a PInvoke signature to match this:
static extern bool XmlParse(IntPtr Reader, IntPtr Source)
I would like to call the "data()" function which is a member of the "Source" class. That is, the QXmlSimpleReader parses the raw XML from the QXmlInputSource, but before it does so, I am trying to inspect the raw XML via this "data()" function.
On the advice of one of the experts here, I have tried to use C++/CLI to access the object natively (see Calling methods in third-party DLLs ). I have constructed a wrapper object in C++ that accepts the IntPtr from the C# code:
Header:
public ref class QXmlInputSource
{
public:
// Constructor must be called with C# IntPtr
QXmlInputSource(IntPtr Ptr);
bool LoadQt(void);
bool UnloadQt(void);
String^ Data();
private:
// Pointer to the native Qt object
void * Native;
HINSTANCE DllHandle;
// SIGNATURE: virtual QString QXmlInputSource::data() const
typedef void * (__thiscall *QXmlInputSource_Data)(void *);
QXmlInputSource_Data fpData;
};
CPP file:
QXmlInputSource::QXmlInputSource(IntPtr Ptr)
{
LoadQt();
Native = Ptr.ToPointer();
}
bool QXmlInputSource::LoadQt(void)
{
FARPROC Addr;
/* get handle to dll */
std::wstring LibName = QtPath + QtXml;
DllHandle = LoadLibrary(LibName.c_str());
/* get pointer to the function in the dll*/
Addr = GetProcAddress(HMODULE (DllHandle), "?data#QXmlInputSource##UBE?AVQString##XZ");
fpData = QXmlInputSource_Data(Addr);
return true;
}
bool QXmlInputSource::UnloadQt()
{
/* Release the Dll */
FreeLibrary(DllHandle);
return true;
}
String^ QXmlInputSource::Data()
{
void* Ptr = fpData(Native);
return "EPIC FAIL";
}
The Qt-based application crashes when I try to call the fpData() function pointer. Help :P
Some additional information which may or may not help:
I have successfully called functions on "simpler" objects, such as QString.count() and QString.data() using the same methodology. (QString seems to be just a lightweight wrapper for a standard unicode string).
In the QtXml4.dll file that contains the XML functions I am interested in, there are actually TWO parse() methods; one where the Source is a const &, and in the other, Source is a const *. I have no idea if I should be using one or the other. I don't think my signatures will change in any event.
While I was trying to play around, I tried dereferencing the IntPtr in the C# code and passing it to C++:
IntPtr DerefSrc = (IntPtr)Marshal.PtrToStructure(Source, typeof(IntPtr));
If I print out the values of these two IntPtrs, Source has a value of around 3.5Mb, while the DerefSrc has a value of 1.6Gb - which roughly matches the address of the QtXml4.dll in memory. My guess is that the 3.5Mb is a relative offset, while the DerefSrc is clearly an absolute reference. Is it worth a shot converting the DerefSrc to a relative address and passing that to C++ instead ... ?
I see several problems:
1.: You don't check the return value of LoadLibrary and GetProcAddress. Is QXmlInputSource::data even a DLL-exported method? If not then GetProcAddress will obviously fail.
2.: How do you instantiate the QXmlInputSource class? I ask because it seems you are trying to do it in the C# code, which is hard to do right (you need to know the size required for the class, allocate a properly aligned chunk of memory of that size, and call the constructor on it).
3.: The way you're invoking the function pointer is wrong. You need to declare a method pointer of the appropriate type:
FARPROC fp = ::GetProcAddress(...);
typedef QString (QXmlInputSource::*DataMethod)();
DataMethod mpData = reinterpret_cast<DataMethod>(fp);
QXmlInputSource source;
QString data = (source.*mpData)();
4.: Looking at the documentation for QXmlInputSource::data, I see that it returns a QString, which is woefully different from a pointer (as you're currently treating it). To convert it to a System.String, you need code like this:
QString s1 = (QChar*)L"example string";
String^ s2 = gcnew String((wchar_t*)s1.data()); // calls the String::String(wchar_t*) constructor overload

Categories