I have a VB6 application that uses a C# compiled Dll. I have been successfull in making this work by means of COM.
But my problem is that I have a Variant array with String and Double data types inside it. I need to pass this array to my C# Dll, which is receiving the array as an Object.
So, all I need to do is to convert the Variant array into an Object array "understandable" by C#. Anyone has any clue on it?
This should do the trick
ArrayList a = new ArrayList(YourObjectArrayHere);
This has to be done right from C# side of things; if it's not, then there isn't much you can do from VB6. That said, by default, a method declared like this:
void Foo(object[] a);
will be seen from VB6 as taking an array of Variant (or, on IDL level, as SAFEARRAY(VARIANT)).
If it doesn't work that way for you, then there's something wrong with your C# declarations - please post them so they may be reviewed.
object[] System.Runtime.InteropServices.Marshal.GetObjectsForNativeVariants(IntPtr aSrcNativeVariant, int cVars)
Have you tried this method?
object[] result;
unsafe
{
pin_ptr<object> pinObj = &obj;
result = Marshal.GetObjectsForNativeVariants(new IntPtr(pinObj), objSize);
}
Haven't tried it myself but seems like it would do the trick.
This is the C# function declaration:
public double[][] CalcMatching( object[][] data1, object[][] data2, long dataLen1, long dataLen2, string matchingType )
This is the VB6 call:
result = matchingCalcObj.CalcMatching(data1, data2, dataLen1, dataLen2, Matching)
where data1 and data2 are arrays of Variant.
I don't think I can do much at the C#, like you guys are saying, once the error I get at the function calling is "Invalid procedure call or argument". Any option at the VB6 side?
Thanks for all the replies.
Related
I am currently messing around with C# in order to be able to approach ASP.NET with an acceptable knowledge base. In order to do so I occasionally look at my old C++ code and see if I can figure out how to make it work in C#.
So I figured that I will look into arrays, a pretty common way to store data. What I was wondering is what would the C# equivalent of creating a two dimensional array via pointers would look like?
I know that in C++ one way to do it could look like this:
double **myArray;
myArray = new double * [rows];
for(int I = 0; I < rows; I++) {
myArray[I] = new double[cols];
}
I also know that in C# you could easily just say double [rows,cols] and that would create a 2D array. I know that C++ and C# most likely treat pointers differently, but just for the sake of interest, how would I mimic a similar behavior in C#?
Cheers.
C# arrays and C++ pointers are incredibly similar, with the biggest difference is that C# has a layer of managed logic on top of the array data.
An array of pointers in C# is possible. You could do it, for example, with:
unsafe
{
double*[] ptrArray = new double*[5];
ptrArray[2][0] = 4.0;
double*[,] ptr2DArray = new double*[5,5];
ptr2DArray [2, 2][0] = 4.0;
}
However, like I said in my previous comment, using pointers in C# is discouraged, and generally you want to use a managed approach whenever possible. Personally, I cannot fathom a need for creating an array of pointers (much less a 2D array) and I imagine that if someone's program needs a structure like this, then they probably need to rethink their approach.
Usually pointers are very less used in C#, When you use pointers in C# it is considered as unsafe context.
Please check following MSDN Pointer Document that illustrates how to use pointers.
I would like to say don't use pointers if not required. You can use Ref Keyword and Out keyword to pass your parameter as a reference.
When you use pointer you loose all managed code benefits.
You can check C# ref is it like a pointer in C/C++.
Apart from that i think that all arrays are already Reference Type even if it contains all members of value type.
Check Value Types and Reference Types in C#.
I hope it helps.
The following method is in C++ (ATL COM dll)
Void Write( Const VARIANT *pData)
pData is a 2-dimensional array of data type Variant.
When I add this reference in a C# .NET project, the IDE shows the method as
Void Write( ref object pData);
How do I pass a 2-dimensional array from C#?
Array of VARIANTs fits itself well into VARIANT type. You can have it like this:
void Write(VARIANT vData)
where vData.vt == (VT_ARRAY | VT_VARIANT), and vData.parrray is array data (safe array - it can by anydimensional, the array descriptor itself contains bounds and number of dimensions). C# will be able to get it right.
There is a very good tutorial on how to exchange VARIANT's between unmanaged code (c++) and managed code (c# or .NET for instance) here , it may help you.
Edit
As promised long time ago (I'm sorry I forgot) I edit my answer :
You can declare your 2D array in c# like this :
object thearray = new object[,] {{2.0, 1.0},{-3.0, 9.0}} ;
and pass it to you com method. You could also do this :
object[,] thetempmatrix = {{2.0, 1.0},{-3.0, 9.0}} ;
object thearray = thetempmatrix ;
Note that would you have rather defined
object[,] thearray = {{2.0, 1.0},{-3.0, 9.0}} ;
it would have worked also, but thearray wouldn't have been passed by reference : assume no const in your COM method signature, it would have been updated by your COM method, but at the exit of your COM method call, you would have got the same thearray as the one you passed. Of course, this last remark does not concern you, as you do have a const in your COM method signature.
I would like to pass C# reference to C/C++ code(pointer), and than get it back from pointer to C#reference.
I have many pairs (uint,Object). I created sorting mechanism in C code, because its much faster than C#. There is only key(uint) and value(object reference) needed. C code is using key for sorting, and is not changing the value(pointer). Is there any simple way to do it? Do i need to use marshalling? C function will be called many times(maybe even a million times), so i am affraid it will be with marshalling too slow, and i don´t even know how to do it with marshalling. I believe when objects address is changed by GC, address of C# reference is not changed. So there will not be needed to place object in pined memory. Am i right about this?
Now i am able to call C function using DllImport, i am able to store C# reference to C pointer, but i am not able to get address stored in C pointer to C# reference.
Any ideas on how to do this?
It is not possible to pass any variables directly from manged c# code to native c++ code. The solution is pinvoke where you can marshal the data.
This works fine but you should know that this is not everytime the fastes solution. On every call the memory must be copied and maybe converted depending on the data types.
My solution to a similar problem, I had some old code in Fortan.
I convert this code to c, then created a managed c++ project.
In c#, I called this manged c++ project.
the c# code looks like this:
unsafe
{
double* input = (double*)utils.Memory.Alloc(sizeof(double) * n);
double* output = (double*)utils.Memory.Alloc(sizeof(double) * n);
//calling the c++ code
c_plus_plus.code(input,output);
//now output contains the output
// (you can use the same array as input and output
}
I hope this helps.
I have some legacy code I want to port to C#. I cannot modify the C++ code, I just have to make do with what I'm given.
So, the situation. I'm using SwIG, and I came across this function:
void MarshalMe(int iNum, FooClass** ioFooClassArray);
If I ran SWIG over this, it wouldn't know what to do with the array, so it will create a SWIGTYPE_p_pFooClass. Fair enough!
C# code for this would look like
void MarshalMe(int iNum, SWIGTYPE_p_p_FooClass ioFooClassArray); // Not ideal!
There are some techniques for marshalling this kind of code correctly, so I tried a few of them:
%typemap(ctype) FooClass** "FooClass**"
%typemap(cstype) FooClass** "FooClass[]"
%typemap(imtype, inattributes="[In, Out, MarshalAs(UnmanagedType.LPArray)]") FooClass** "FooClass[]"
%typemap(csin) FooClass** "$csinput"
%typemap(in) FooClass** "$1 = $input;"
%typemap(freearg) FooClass** ""
%typemap(argout) FooClass** ""
This effectively creates a nicer signature:
void MarshalMe(int iNum, FooClass[] ioFooClassArray); // Looks good! Would it work?
However, when I try to run it, I get the following error:
{"Exception of type 'System.ExecutionEngineException' was thrown."}
Any ideas about the actual typemap?
The exception tells you that the function has corrupted the garbage collected heap. It writing past the end of the array. If it is actually a FooClass[], big question, then you'll have to create the array first:
FooClass[] array = new FooClass[666];
MarshalMe(42, array);
Which assumes that the function will fill the array with FooClass objects. The size of the array really matters here, you'll have to have some kind of idea how many elements you'll get back. That can only work reliable if "iNum" is an argument that says how long the array is. Pass array.Length.
It could also mean that the function will create the array itself and return a pointer to it. You're really screwed if that's the case, you cannot release the memory for the array.
[Swig] Java: Another way to pass pointer-to-pointer
I had a similar problem with a C-function (API) which returned a pointer-to-pointer as an input argument. I was trying to call the C-function from JAVA and I had no way modify the API.
The API.h header file contained:
extern int ReadMessage(HEADER **hdr);
The original C-call looked like:
HEADER *hdr;
int status;
status = ReadMessage(&hdr);
The function of the API was to store data at the memory location specified by the pointer-to-pointer.
I tried to use SWIG to create the appropriate interface file. SWIG.i created the file SWIGTYPE_p_p_header.java from API.h. The problem is the SWIGTYPE_p_p_header constructor initialized swigCPtr to 0.
The JAVA call looked like:
SWIGTYPE_p_p_header hdr = new SWIGTYPE_p_p_header();
status = SWIG.ReadMessage(hdr);
But when I called the API from JAVA the ptr was always 0.
I finally gave up passing the pointer-to-pointer as an input argument. Instead I defined another C-function in SWIG.i to return the pointer-to-pointer in a return value. I thought it was a Kludge ... but it worked!
You may want to try this:
SWIG.i looks like:
// return pointer-to-pointer
%inline %{
HEADER *ReadMessageHelper() {
HEADER *hdr;
int returnValue;
returnValue = ReadMessage(&hdr);
if (returnValue!= 1) hdr = NULL;
return hdr;
}%}
The inline function above could leak memory as Java won't take ownership of the memory created by ReadMessageHelper, since the HEADER instance iscreated on the heap.
The fix for the memory leak is to define ReadMessageHelper as a newobject in order for Java to take control of the memory.
%newobject ReadMessageHelper();
JAVA call now would look like:
HEADER hdr;
hdr = SWIG.ReadMessageHelper();
If you are lucky, as I was, you may have another API available to release the message buffer. In which case, you wouldn’t have to do step 4.
William Fulton, the SWIG guru, had this to say about the approach above:
“I wouldn't see the helper function as a kludge, more the simplest solution to a tricky problem. Consider what the equivalent pure 100% Java code would be for ReadMessage(). I don't think there is an equivalent as Java classes are passed by reference and there is no such thing as a reference to a reference, or pointer to a pointer in Java. In the C function you have, a HEADER instances is created by ReadMessage and passed back to the caller. I don't see how one can do the equivalent in Java without providing some wrapper class around HEADER and passing the wrapper to the ReadMessage function. At the end of the day, ReadMessage returns a newly created HEADER and the Java way of returning newly created objects is to return it in the return value, not via a parameter.”
Using SWIG typemap to pass pointer-to-pointer:
Here is another approach using typemaps. It is targetting Perl, not Java, but the concepts are the same. And I finally managed to get it working using typemaps and no helper functions:
For this function:
typedef void * MyType;
int getblock( int a, int b, MyType *block );
I have 2 typemaps:
%typemap(perl5, in, numinputs=0) void ** data( void * scrap )
{
$1 = &scrap;
}
%typemap(perl5, argout) void ** data
{
SV* tempsv = sv_newmortal();
if ( argvi >= items ) EXTEND(sp,1);
SWIG_MakePtr( tempsv, (void *)*$1, $descriptor(void *), 0);
$result = tempsv;
argvi++;
}
And the function is defined as:
int getblock( int a, int b, void ** data );
In my swig .i file. Now, this passes back an opaque pointer in the argout typemap, becaust that's what useful for this particular situation, however, you could replace the SWIG_MakePtr line with stuff to actually do stuff with the data in the pointer if you wanted to. Also, when I want to pass the pointer into a function, I have a typemap that looks like this:
%typemap(perl5, in) void * data
{
if ( !(SvROK($input)) croak( "Not a reference...\n" );
if ( SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0 ) == -1 )
croak( "Couldn't convert $1 to $1_descriptor\n");
}
And the function is defined as:
int useblock( void * data );
In my swig .i file.
Obviously, this is all perl, but should map pretty directly to Java as far as the typemap architecture goes. Hope it helps...
I managed to solve this using Swig Managed Arrays and Pinning documentation.
Given a function in C++
void myArrayCopy(int *sourceArray, int *targetArray, int nitems);
Declare the method as unsafe in C#
%csmethodmodifiers myArrayCopy "public unsafe";
Add the appropriate typemaps
%include "arrays_csharp.i"
%apply int FIXED[] {int *sourceArray}
%apply int FIXED[] {int *targetArray}
As a result, we get the following method in the module class:
public unsafe static void myArrayCopy(int[] sourceArray, int[] targetArray, int nitems)
{
fixed ( int *swig_ptrTo_sourceArray = sourceArray )
{
fixed ( int *swig_ptrTo_targetArray = targetArray )
{
examplePINVOKE.myArrayCopy((IntPtr)swig_ptrTo_sourceArray,
(IntPtr)swig_ptrTo_targetArray,
nitems);
}
}
}
In practice this might differ a little with FooClass** but Swig does support direct pointer to pointer marshalling, which also avoids a copy as well so can be considered better performance
I need to pass string lists to unmanaged c++ how can I do this ?
I have used IDictionary as method return type and send through com but it doesn't work. How to achieve this?
What I have written in C# is as follows -
IDictionary<string,string> postNames()
{
IDictionary<string,string> post=Dictionary<string,string>();
post.Add("Raj");
post.Add("Mahesh");
post.Add("john steek");
return post;
}
Then I have created a dll for that class contains this method.
Now how can i access these values in unmanaged c++....
I am worried about two things
1) About the return type to carry these values in c++
2) Is it possible to use like this way ..
Any help in this regard?
A quick, dirty method is write a C++/CLI wrapper.
It's essentially the same problem as in this question. You can implement perfect Earwicker's answer here - declare a set of interfaces and accessor classes that wrap the Dictionary and expose them to COM.
Probably the simplest way is to pass a string[] and use it in the unmanaged side as an SAFEARRAY(BSTR) type. You can also pass a string[] and consume it in COM as a LPStr[] by using the MarshalAs (this is the sample on MSDN):
void FunctionCall([MarshalAs(UnmanagedType.LPARRAY,
ArraySubType= UnmanagedType.LPStr, SizeParamIndex=1)]
String [,] ar, int size );
See Default Marshaling for Arrays for more details.