views:

487

answers:

5

So I'm trying to call a function that is a manged wrapper around an OCX object. Having great difficulty. Function is;

foo(System::Object ^% theBuffer)

where 'theBuffer' is an array of bytes. The template for the unmanaged OCX which 'foo' wraps is

goo(VARIANT* theBuffer);

So I've tried;

System::Int32 buf[10];
foo(buf);

which fails. And

Bitmap ^b;
foo(b);

which compiles but obviously the called function is not going to create a .NET bitmap for me.

So I guess the question is how do I pass this function a block of memory it can write to and then get access to it back in .NET world.

Thanks

+1  A: 

You can't convert a VARIANT to the buffer directly.

First you need to check what kind of object is stored in it by checking theBuffer->vt. The returned value will be of the type VARTYPE .

arul
sorry I phrased the question wrong, see edit. So I'm not actually trying to write the wrapper. I just need to know what to pass to foo(System::Object ^% theBuffer) given that it wraps a function that looks like goo(VARIANT* theBuffer).
A: 

What about something like..

Bitmap ^b = gcnew Bitmap(...
foo(b);
Edouard A.
Unfortunately the 'foo' wrapper function dosn't seem to do any sort of smart passing to the unamanged version so it has no knowledge of how to construct .NET objects. I think it basically just wants a block of memory.
From what I remember of C++/CLI, the COM wrapper are built in such a way you shouldn't worry about all that stuff.
Edouard A.
A: 

ok so I'm actually using the Axis Media Control SDK to interface with a network camera ( http://www.axis.com/techsup/cam_servers/dev/activex.htm ). The OCX function I am calling via the wrapper looks like;

HRESULT GetCurrentImage(int theFormat,    [C++]
        VARIANT* theBuffer,
        LONG* theBufferSize
       );

the wrapper is supplied by Axis. Using .NET Reflector I have disasembled the wrapper function;

public: virtual void __gc* GetCurrentImage(Int32 __gc* theFormat, [Out] Object __gc*   *theBuffer, [Out] Int32 __gc* *theBufferSize)
{
    if (this->ocx == 0)
    {
        throw __gc new InvalidActiveXStateException(S"GetCurrentImage", ActiveXInvokeKind::MethodInvoke);
    }
    this->ocx->GetCurrentImage(theFormat, out theBuffer, out theBufferSize);
}

So it's not doing anything smart, just passing a chunk of memory. In C++ CLI syntax the template looks like;

GetCurrentImage(int theFormat, System::Object ^% theBuffer, int % theBufferSize)

So my question becomes how do I pass this a chunk of memory to write to and then recover it back into a .NET object. I tried this;

unsigned char c[100];
GetCurrentImage(0, (System::Object)c, BufSize);

but obviously it dosn't work.

A: 

I've just tried;

unsigned char a[1024*256];
System::IntPtr^ iPtr = gcnew System::IntPtr(a);
myAMC->GetCurrentImage(0, iPtr, BufferSize);

which compiles but dosn't write the buffer to 'a' .

A: 

//compile with /CLR (VS2005:sp1, vs2008)

class A {

public:

A(char *c)
{
 printf("this %x\n",this);
 strcpy(m_c,c);
}

char m_c[4096];   //use high memory >=4096

~A(){}      //to reproduce this bug

};

class B {

public:

B(char *c)
{
 printf("this %x\n",this);
 strcpy(m_c,c);
}

char m_c[4096];

};

void func(A a="2",B b="1") { printf("%s:%x %s:%x\n",a.m_c, &a, b.m_c, &b); }

int _tmain(int argc, TCHAR argv[]) { func(); return 0; }

//prints garbage value, want to know if this is a bug in the compiler