【问题标题】:JNA COM pass 2-Dimensional VARIANT*JNA COM 通过二维变体*
【发布时间】:2021-08-30 09:20:48
【问题描述】:

我有一个包含此函数声明的COM interface

HRESULT _stdcall mgAPI::IMGGeocoding::GetCoordinates([in] BSTR Postcode,
                                                     [in] BSTR Location,
                                                     [in] BSTR Street,
                                                     [in] VARIANT_BOOL SearchFuzzy,
                                                     [out] VARIANT * Values)
                
Parameters
[in] Postcode       Postal code (with or without leading country code), e.g. "D76131"
[in] Location       Town name, e.g. "Karlsruhe"
[in] Street         Street and house number, e.g. "Stumpfstr. 1"
[in] SearchFuzzy    if set to true, the search will be more "tolerant" and will normally give more results.
[out] Values        2-dimensional variant array (0-based in both dimensions).
                
The size of the first dimension is equal to the number of returned search results.
The size of the second dimension is 7.

使用这个example我在JNA中映射了如下函数:

public String[] getCoordinates(String inPostcode, String inLocation, String inStreet, boolean inSearchFuzzy) {
        String[] retVal = null;
        SAFEARRAY safeArray = SAFEARRAY.createSafeArray(new WTypes.VARTYPE(Variant.VT_VARIANT), 7);

        try {
            BSTR postcode = OleAuto.INSTANCE.SysAllocString(inPostcode);
            BSTR location = OleAuto.INSTANCE.SysAllocString(inLocation);
            BSTR street = OleAuto.INSTANCE.SysAllocString(inStreet);
            VARIANT_BOOL searchFuzzy = new VARIANT_BOOL(inSearchFuzzy); 

            PointerByReference pbr = new PointerByReference(safeArray.getPointer());

            VARIANT values = new VARIANT();
            values.setValue(new VARTYPE(Variant.VT_BYREF), new PVOID(pbr.getPointer()));
            values.setVarType((short) (Variant.VT_BYREF | Variant.VT_ARRAY | Variant.VT_VARIANT));

            HRESULT hres = (HRESULT)this._invokeNativeObject(7, new Object[]{this.getPointer(), postcode, location, street, searchFuzzy, values}, HRESULT.class);
            if (COMUtils.SUCCEEDED(hres)) {
                if (!pbr.getValue().equals(safeArray.getPointer())) {
                    safeArray.destroy();
                    safeArray = new SAFEARRAY(pbr.getValue());
                }

                safeArray.read();
                
                Pointer pointer = safeArray.accessData();
                try {
                    retVal = pointer.getStringArray(0, safeArray.getUBound(0) - safeArray.getLBound(0) + 1);
                } finally {
                    safeArray.unaccessData();
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        } finally {
            if (safeArray != null) {
                safeArray.destroy();
            }
        }
        
        return retVal;
    }

Array 中的值始终为null

将 VARIANT* 传递到接口并获取二维变量数组的正确方法是什么?

【问题讨论】:

  • 不了解 java/jna,但是,从您的函数原型中,您只需分配一个空的 VARIANT 结构,并在 调用函数(构建数组不是您的责任)所以这意味着您要首先检查它的类型(它应该是 VT_ARRAY | 类似 VT_ARRAY | VT_VARIANT 或 VT_ARRAY | VT_I4 等)并使用数组成员。读取所有内容后,您应该释放返回的 VARIANT 可能持有的内存。 (使用原生 C++/SDK 它是 VariantClear)

标签: java com jna


【解决方案1】:

我现在已经设法获取这些值,这是我的代码。我认为仍有改进的空间,但它确实有效。

postcode = OleAuto.INSTANCE.SysAllocString(inPostcode);
location = OleAuto.INSTANCE.SysAllocString(inLocation);
street = OleAuto.INSTANCE.SysAllocString(inStreet);
VARIANT_BOOL searchFuzzy = new VARIANT_BOOL(inSearchFuzzy);
VARIANT.ByReference values = new VARIANT.ByReference();

HRESULT hres = (HRESULT)this._invokeNativeObject(7, new Object[]{this.getPointer(), postcode, location, street, searchFuzzy, values}, HRESULT.class);
if (COMUtils.SUCCEEDED(hres)) {             
    if(values.getVarType().intValue() == (Variant.VT_ARRAY | Variant.VT_VARIANT)) {
        SAFEARRAY safeArrayOuter = (SAFEARRAY)values.getValue();
        OleAuto.INSTANCE.SafeArrayLock(safeArrayOuter);

        try {
            for(int x = 0; x <= safeArrayOuter.getUBound(0); x++) {
                SAFEARRAY safeArrayInner = (SAFEARRAY) new VARIANT(safeArrayOuter.ptrOfIndex(x)).getValue();
                OleAuto.INSTANCE.SafeArrayLock(safeArrayInner);

                try {
                    ArrayList<String> innerList = new ArrayList<String>();

                    for(int y = 0; y <= safeArrayInner.getUBound(0) ; y++) {
                        LONG[] idx = new LONG[] {new LONG(y)};
                        VARIANT value = new VARIANT();

                        HRESULT hr = OleAuto.INSTANCE.SafeArrayGetElement(safeArrayInner, idx, value.getPointer());
                        if (COMUtils.SUCCEEDED(hr)) {
                            System.out.println(value.getVarType());

                            if(value.getVarType().intValue() == Variant.VT_BSTR) {
                                System.out.println(value.stringValue());
                            } else if (value.getVarType().intValue() == Variant.VT_I4) {
                                System.out.println(value.intValue());
                            }
                        }
                    }
                } catch(Exception e) {
                    e.printStackTrace();
                    return null;
                } finally {
                    OleAuto.INSTANCE.SafeArrayUnlock(safeArrayInner);
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (safeArrayOuter != null) {
                OleAuto.INSTANCE.SafeArrayUnlock(safeArrayOuter);
                safeArrayOuter.destroy();
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 2018-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多