Need MFC to pass SAFEARRAY COM component using IDispatch::Invoke() RRS feed

  • Question

  • I am upgrading a legacy Visual Studio C++ application that does a lot of MFC style COM invocations. The COM components were originally implemented in J++. Recently the J++ code was ported to pure Java and made into COM components using the EZJCom COM-to-Java bridge tool.

    I need to invoke a method that had the following signature when it was implemented in J++:

                    The Java implementation:

                    public void setBlobByPointer(int handle, byte[] theblob, int theSize)

                    The corresponding IDL:

                    [id(0x00000099), helpstring("setBlobByPointer")]

                    void setBlobByPointer(

                                [in] long Parameter0,

                                [in] IDispatch* Parameter1,

                                [in] long Parameter2);

    The EZJCom tool  implements this method using the following signature (the EZJCom implements bridge components in C++ using ATL):

    [id(12),  helpstring("Method SetBlobByPointer")]

    HRESULT SetBlobByPointer(

    int arg1,

    [in, out] SAFEARRAY(byte) arg2,

    int arg3);

    When I import the TypeLibrary containing the method into the MFC ClassWizard and attempt to generate a C++ wrapper, I receive the following error:

                    // method 'SetBlobByPointer' not emitted because of invalid return type or parameter type

    I believe the ClassWizard is rejecting the SAFEARRAY(BSTR) parameter. I’m thinking I can create my own wrapper for this method using IDispatch::Invoke() functionality but I’m not that familiar with COM. Can anyone help me?

    The legacy C++ client code that calls this method looks like this:

                     CString aCString = “A String”;

    VARIANT varData;
                    SAFEARRAY FAR* psa;
                    SAFEARRAYBOUND rgsabound[1];
                     rgsabound[0].lLbound = 0;
                    rgsabound[0].cElements = size;
                    psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
                     memcpy(psa->pvData, aCString, size);
                     varData.vt =VT_ARRAY | VT_UI1;
                    V_ARRAY(&varData) = psa;
                    myDispatch.setBlobByPointer(handle, varData, size);

    Tuesday, July 10, 2012 12:11 AM


  • Well, you have a big problem.

    The problem is the way Java handles arrays (or rather Javascript, but I suspect the implementation in this scenario is the same). Java arrays are not SAFEARRAY's as recognized by other COM-aware languages, but are objects. In the COM world, this object has an interface named IDispatch* which is what you are seeing in the setBlobByPointer IDL signature.

    Therefore, if you are going to prepare C++ client code that is going to call the setBlobByPointer signature, the calling code is going to have to implement an object that supports the IDispatch* interface. This interface of course implements two key methods: GetIDsOfNames() and Invoke().

    The Java code will call these two methods when it wants to access an element of the array. The index of the element is passed to GetIDsOfNames() as a string. For example, to retrieve the third parameter, the string "3" is passed to GetIDsOfNames(). The ID that is returned is then passed to Invoke() in order to retrieve the element itself. This is the behaviour that you will need to implement. The calling code then instantiates this object, passes the associated IDispatch* pointer to the setBlobByPointer, and then releases the IDispatch* pointer after the function returns.

    I don't use MFC very much, but I'm pretty sure MFC isn't any value here with the implementation of such an object. You have to get down and dirty and implement this in straight C++. Perhaps one of the gurus in this forum might point you to some code you can use as a template.

    Frankly, I get suspicous when I see things like "COM components implemented in Java", helped by other third party software that is used as a bridge. This doesn't sound like a clean solution. I'd be exploring how to implement this with a more conventional framework such as ATL. However, there isn't sufficient information in your post to comment any further on this.

    • Edited by Brian Muth Tuesday, July 10, 2012 3:35 AM
    • Marked as answer by Helen Zhao Tuesday, July 17, 2012 2:48 AM
    Tuesday, July 10, 2012 1:38 AM