Monday, March 28, 2011

C++ CLI cryptic function call

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

From stackoverflow
  • 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 .

  • What about something like..

    Bitmap ^b = gcnew Bitmap(...
    foo(b);
    
    Edouard A. : From what I remember of C++/CLI, the COM wrapper are built in such a way you shouldn't worry about all that stuff.
  • 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.

  • 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' .

  • //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

0 comments:

Post a Comment