How to call an ActiveX function with char * parameter in C# - c#

I have this c++ function :
unsigned int ReadUserMemory( unsigned char *lpBuffer, unsigned int iAddress, unsigned int nNumberOfByte );
Which reads nNumberOfByte bytes from iAddress of a memory and places it in lpBuffer.
I created an ATL Object for it( Going to be used in C# ) with this interface :
[id(6), helpstring("method ReadUserMemory")] HRESULT ReadUserMemory(BYTE* lpBuffer, [in] ULONG iAddress, [in] ULONG nNumberOfByte, [out,retval] ULONG* result);
I'm neither C# programmer nor experienced ATL programmer! Now I'm going to test this function in C# with this code :
byte [] b = new byte[100];
axObj.ReadUserMemory(b, 0, 100);
But apparently this code is wrong. How to call this method? Thanks in advance.

I think Peter R has a very valid point, in that using COM is complicated, because it requires learning COM as well as C++ and C#, as you've discovered. C++ interop is another option, but that also requires learning a third technology, called C++/CLI, which is probably a better fit than COM, but can still be problematic. Both COM and C++/CLI are quite big, complicated beasts, so you might be better off just declaring the C function you need in a dll and using P/Invoke, see e.g. http://msdn.microsoft.com/en-us/magazine/cc164123.aspx. If so, the magic you want can be found in How can I pass a pointer to an array using p/invoke in C#?.
Assuming you want to continue down the COM route, I had a play around with it, and to me it looks like you need to get something that is going to work via the type library that is embedded in the COM dll. In short, I couldn't make the COM interop work with unsigned char *lpBuffer, although perhaps someone else can! The type-library friendly type to use is a SAFEARRAY, which is essentially the way that VB likes to see arrays.
In this case, your idl becomes
[id(1)] HRESULT ReadUserMemory([out] SAFEARRAY(byte)* buffer, [in] ULONG iAddress, [in] ULONG nNumberOfByte, [out,retval] ULONG* result);
Your C++ implementation looks like something like this
STDMETHODIMP CObj::ReadUserMemory(SAFEARRAY ** pBuffer, ULONG iAddress, ULONG nNumberOfByte, ULONG* result)
{
if (pBuffer== nullptr)
return E_POINTER;
SAFEARRAY*& psa = *pBuffer;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = nNumberOfByte;
psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
if(psa == NULL)
return E_OUTOFMEMORY;
void* data = nullptr;
SafeArrayAccessData(psa, &data);
for(int i=0; i<nNumberOfByte; ++i) {
((char*)data)[i] = (char)i;
}
SafeArrayUnaccessData(psa);
return S_OK;
}
The SafeArrayUnaccessData should be called even if the code after the SafeArrayAccessData fails.
The C# client now looks like this, notably we have changed from byte[] to System.Array
static void Main(string[] args)
{
RUMLib.IObj axObj = new RUMLib.Obj();
Array a = null;
axObj.ReadUserMemory(out a, 2, 6);
for (int i = 0; i < a.Length; ++i)
{
Console.Write("{0},", a.GetValue(i));
}
Console.WriteLine();
}
and the output of the program is
0,1,2,3,4,5,
Note that there will v likely be marshalling, i.e. copying of the data, as the data comes back from the SAFEARRAY to the C# array. This might be prohibitively costly for you, in which case suggest you go with C++/CLI or P/Invoke.

Related

Remove out parameters from C# wrapper of C++ function in SWIG

I am wrapping a C++ object and it has certain methods that return by value, and I would like the C# wrapper method to return a native type without having to allocate and de-allocate memory in C++-land. In this situation I think copying data into the return type is appropriate but I can't figure out how to do it in a nice way.
As a simple working example the following C++ code is a file parser. I only list the the std::pair<int,int> version() method but you can imagine other that return a small constant std::array, list, etc.
#include <utility>
#include <tuple>
class MyFile {
public:
std::pair<int,int> version() const noexcept {
return {version_major_, version_minor_};
}
private:
int version_major_;
int version_minor_;
};
Using Out Arguments
I like this one the best, but I can't for the life of me figure out how to remove the out arguments for just the C# wrapper! C# is responsible for the memory and just passes it to C++ to fill in. This requires some C++ wrappers using %extend but that is ok.
I really want a final C# method with signature of public Tuple<int, int> version() 
SWIG code
%module parser
%include "typemaps.i"
%rename("$ignore", fullname=1) MyFile::version() const noexcept;
%extend MyFile {
void version(int* major_out, int* minor_out) {
std::tie(*major_out, *minor_out) = self->version();
}
}
%typemap(ctype, out="void *") int* major_out, int* minor_out "int *"
%typemap(imtype, out="void") int* major_out, int* minor_out "out int"
%typemap(cstype) int* major_out, int* minor_out "out int"
%typemap(cstype) void MyFile::version "Tuple<int, int>"
%typemap(csin, pre=" int tmp_$csinput = 0;") int* major_out, int* minor_out "out tmp_$csinput"
// implment the C# function that returns the type specified above
%typemap(csout, noblock=1, excode=SWIGEXCODE) void MyFile::version
{
$imcall;$excode
major_out = tmp_major_out;
minor_out = tmp_minor_out;
return new Tuple<int, int>(tmp_major_out, tmp_minor_out);
}
Generated C++ wrapper
SWIGEXPORT void SWIGSTDCALL CSharp_parser_MyFile_version(void * jarg1, int * jarg2, int * jarg3) {
MyFile *arg1 = (MyFile *) 0 ;
int *arg2 = (int *) 0 ;
int *arg3 = (int *) 0 ;
arg1 = (MyFile *)jarg1;
arg2 = (int *)jarg2;
arg3 = (int *)jarg3;
MyFile_version(arg1,arg2,arg3);
}
Generated PInvoke Code
[global::System.Runtime.InteropServices.DllImport("parser", EntryPoint="CSharp_parser_MyFile_version")]
public static extern void MyFile_version(global::System.Runtime.InteropServices.HandleRef jarg1, out int jarg2, out int jarg3);
Generated C# Bindings
public Tuple<int, int> version(out int major_out, out int minor_out) {
int tmp_major_out = 0;
int tmp_minor_out = 0;
parserPINVOKE.MyFile_version(swigCPtr, out tmp_major_out, out tmp_minor_out);
major_out = tmp_major_out;
minor_out = tmp_minor_out;
return new Tuple<int, int>(tmp_major_out, tmp_minor_out);
}
Other methods
I have tried other methods but to keep the question short I won't post all the generated code here.
Returning pointer to a static array
this works, but requires static data for every method that I want to work this way. This doesn't scale. I could easily run into lifetime issues if I try to do this with member data that I assume will live long enough for C# to copy.
wrap the default generated code in a csout typemap
This also works but allocated and de-allocates a lot for a function just returning two ints! you end up with a C# wrapper something like:
public Tuple<int, int> version() {
System.IntPtr cPtr = parserPINVOKE.MyFile_version(swigCPtr);
pair_of_int tmp = new pair_of_int(cPtr, false);
Tuple<int, int> ret = new Tuple<int, int>(tmp.first, tmp.second);
tmp.Dispose();
return ret;
}
Other SO Questions
a similar question is this one, but that deals with java. Java has JNI and Pyhton has a C interface that lets you create memory/object in the C code and return it... I don't see a way to do that in .NET withou C++/CLI (which SWIG isn't using).

Converting between IVector<T>^ and C-style array of bytes in a winrt component

My universal store project for windows 8.1 and windows phone 8.1 (C#) uses a windows runtime component (C++) that consists of a C library and a C++/CX wrapper class that provides access to C code for winrt environment.
I pass arrays of bytes from C# code to the component and get arrays of bytes back using IVector<unsigned char>^ interface. So, I need to convert back and forth between IVector and C-style array of unsigned char.
This is how I do that now:
unsigned char *Component::CopyToArray(IVector<unsigned char>^ source)
{
unsigned char *target = new unsigned char[source->Size];
for (unsigned int i = 0; i < source->Size; i++) {
target[i] = source->GetAt(i);
}
return target;
}
Vector<unsigned char>^ Component::CopyToVector(unsigned char *source, unsigned int length)
{
Vector<unsigned char>^ target = ref new Vector<unsigned char>();
for (unsigned int i = 0; i < length; i++) {
target->Append(source[i]);
}
return target;
}
Is there a way to avoid allocating memory and copying data?
UPDATE: I realized CopyToVector is obsolete, because there's a constructor that takes a pointer.
ref new Vector<unsigned char>(pointer, size)
UPDATE & SOLUTION
I changed code to use const Platform::Array<unsigned char>^ for parameter types and Platform::Array<unsigned char>^ for return types of public api of C++ wrapper class. C# sees these types as byte[], so there's no need for explicit conversion. And in C++ unsigned char * pointer is accessible as simple as argOfArrayType->Data. To return data from C++ to C# I use ref new Array<unsigned char>(pointer, size).
My experience with C++/CX is limited to a couple of apps, but why not use Platform::WriteOnlyArray instead of the vector? With the array you can access the data directly through the Data property. So the C# -> C++/CX direction can be optimized that way. It also has a Array(T* data, unsigned int size) constructor that should help in the C++/CX -> C# direction. However I'm not sure about the memory management in this case, if the array wraps or copies the data. And if it does wrap it, how does it know how to free it?

Best Way To Marshal A Pointer of Array of Struct

I'm calling functions from C++ that returns a pointer to an array of struct and I'm having problems since I'm new to this operation/implementation.
My C++ codes:
// My C++ Structs
typedef struct _MainData {
double dCount;
DataS1 *DS1;
int iCount1;
DataS2 *DS2;
int iCount2;
}MainData;
typedef struct _DataS1 {
unsigned int uiCount1;
unsigned int uiCount2;
int iCount;
void *pA;
void *pB;
} DataS1;
typedef struct _DataS2 {
unsigned int uiCount1;
unsigned int uiCount2;
unsigned int uiCount3;
unsigned int uiCount4;
double dCount;
int iCount1;
char strLbl[64];
} DataS2;
// My C++ Function
MainData* GetData(const int ID)
{
MainData* mData;
int iLength = Get_Count();
mData = new MainData[iLength];
for(int x = 0;x < VarCounter; x++)
{
// Codes here assign data to mData[x]
}
return mData;
}
Question:
How can I call the C++ function GetData to C#?
My current codes in C# are:
[DllImport(".\\sdata.dll")]
[return: MarshalAs(UnmanagedType.LPArray)]
private static unsafe extern MainData[] GetData(int ID);
// The struct MainData in my C# side is already "Marshalled"...
//My function call is here:
MainData[] SmpMapData = GetData(ID);
When I compiled it, there's an exception:
"Cannot marshal 'return value': Invalid managed/unmanaged type combination."
Sorry for the poor coding... Please help...
I tried to do exactly the same thing but didn't succeed due to lack of time but I learned something in process:
Allocate memory in C#
To pass array of structs, struct must be blittable.
Good luck with that, I couldn't make it to work.
One problem is that the marshaller doesn't know how many items are in the array returned by the C++ code. An alternative approach could be to have two C++ methods - one which returns the number of items, and one which returns a single MainData given an index.
What do your structures look like on the C# side?
Since you are coding both the C++ and C# side, it may be easier to use C++/CLI to interface them instead of PInvoke.

Complicated (?) pinvoke situation - avoid function overloading

Summary:
I have a bunch of C functions I have to call from C#. My current working solution is based on function overloading and I'm wondering if there is a more elegant solution.
The C stuff:
somewhere in a header file
typedef struct _unknown_stuff * handle; // a opaque pointer
an example of the function
func( uint num_entries,
handle * objects,
uint * n)
{ ... }
in C the function should be used similar to this:
// warning: i bet that the syntax is not correct but you should get the idea...
uint n;
func(0, null, &n);
handle * objects = malloc(n * sizeof(handle));
func(n, objects, null);
The C# stuff:
right now I'm doing the following in C#:
public struct handle
{
public IntPtr Pointer;
}
// version to get number of objects
[DllImport(dll, ...]
private static extern void
func( uint must_be_zero,
object must_be_null,
out uint n);
// version to get the actual data
[DllImport(dll, ...]
private static extern void
func( uint num_entries,
[Out] handle[] objects,
int must_be_zero);
and then:
handle[] objects;
uint n = 42;
func(0, null, out n);
objects = new handle[n];
func(n, objects, 0);
The Question
Since I'm a C# noob, I was wondering if this is the best way to do this. Especially I would like to know if there is a way around overloading the function.
First of all, your code as is is wrong, because in the second C# signature your third argument is int, while the corresponding C argument is still int*. It will work when targetting 32-bit Windows, because sizeof(int)==sizeof(int*) there - so when you pass a 0 int you end up passing a null pointer - but it is not 64-bit safe. If you still want to do it that way, you need to use IntPtr there.
Aside from that, you could try:
[DllImport(dll, ...]
private static extern void func(
uint num_entries,
[Out] handle[] objects,
[Out] int[] num_devices);
making the third argument an array so that you could pass null there.
Or just use pointers. There's nothing bad about it, and don't be afraid of unsafe keyword - any kind of P/Invoke is inherently unsafe anyway, so you might as well be explicit about it.
Wouldn't the C dll look at 0, and process that as null?
It only has one function, correct? That is, the C function is defined once, and not separately for a null case, and would have an if( objects == NULL ) check somewhere in there. On most systems (check the stdio.h of the target system) this is 0.
So calling from pinvoke with a 0 value in this place should do what you wanted overloading to do.

Passing pointers from unmanaged code

I have a C# project that imports a C dll, the dll has this function:
int primary_read_serial(int handle, int *return_code, int *serial, int length);
I want to get access to the serial parameter. I've actually got it to return one character of the serial parameter, but I'm not really sure what I'm doing and would like to understand what is going, and of course get it working.
So, I'm very sure that the dll is being accessed, other functions without pointers work fine. How do I handle pointers? Do I have to marshal it? Maybe I have to have a fixed place to put the data it?
An explanation would be great.
Thanks!
Richard
You will have to use an IntPtr and Marshal that IntPtr into whatever C# structure you want to put it in. In your case you will have to marshal it to an int[].
This is done in several steps:
Allocate an unmanaged handle
Call the function with the unamanged array
Convert the array to managed byte array
Convert byte array to int array
Release unmanaged handle
That code should give you an idea:
// The import declaration
[DllImport("Library.dll")]
public static extern int primary_read_serial(int, ref int, IntPtr, int) ;
// Allocate unmanaged buffer
IntPtr serial_ptr = Marshal.AllocHGlobal(length * sizeof(int));
try
{
// Call unmanaged function
int return_code;
int result = primary_read_serial(handle, ref return_code, serial_ptr, length);
// Safely marshal unmanaged buffer to byte[]
byte[] bytes = new byte[length * sizeof(int)];
Marshal.Copy(serial_ptr, bytes, 0, length);
// Converter to int[]
int[] ints = new int[length];
for (int i = 0; i < length; i++)
{
ints[i] = BitConverter.ToInt32(bytes, i * sizeof(int));
}
}
finally
{
Marshal.FreeHGlobal(serial_ptr);
}
Don't forget the try-finally, or you will risk leaking the unmanaged handle.
If I understand what you're trying to do, this should work for you.
unsafe
{
int length = 1024; // Length of data to read.
fixed (byte* data = new byte[length]) // Pins array to stack so a pointer can be retrieved.
{
int returnCode;
int retValue = primary_read_serial(0, &returnCode, data, length);
// At this point, `data` should contain all the read data.
}
}
JaredPar gives you the easy way to do it however, which is just to change your external function declaration so that C# does the marshalling for you in the background.
Hopefully this gives you an idea of what's happening at a slightly lower level anyway.
When writing your P/invoke declaration of that function, try using keyword ref for the pointer parameters like this:
[DllImport("YouDll.dll", EntryPoint = "primary_read_serial")]
public static extern int primary_read_serial(int, ref int, ref int, int) ;
I'm not sure if you need to specify the parameters' name in C#. And remember, when calling that method, you will also have to use ref in the arguments you're passing by reference.

Categories

Resources