Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
265 views
in Technique[技术] by (71.8m points)

c++ - JNA - Mapping int* from 32bits DLL loaded in 64bits Java

I'm facing a problem trying to map a 32bit COM DLL (wrote in OLD C++) method using 64bit Java.

The COM DLL expose this method (I check this using OLEViewer):

void Login(
                [out] int* ResultCode, 
                [out] BSTR* Result, 
                [in] BSTR App, 
                [in, out] BSTR* User, 
                [in] BSTR Module, 
                [in] BSTR Password, 
                [out] BSTR* Permissions, 
                [out] BSTR* Data1, 
                [out] BSTR* Data2, 
                [out] BSTR* Data3, 
                [out] BSTR* Data4, 
                [out] BSTR* Data5, 
                [out] int* UserLevel, 
                [out] int* ExpirationDays, 
                [in] int Authentication);

I was succesfully mapped 'Result' param as BSTRByReference, I run the method and receive in that param the value modified by Login, but I'm not able to map the 'ResultCode' param (or any other [out] int*), it always remains in NULL value.

I tried using IntByReference (type mismatch error), ShortByReference, byte, etc. with no luck.

The creepy part is that DLL is 32bits and I followed these steps to be able to load it in Java using JNA:

https://techtalk.gfi.com/32bit-object-64bit-environment/

Is it possible to load a 32bits DLL in 64bits Java without any consequence, or maybe that's why I'm having troubles with the mapping?

Thanks in advance.

[UPDATE JAVA CLASS]

    /**
     * method Login
     *
     * <p>id(0x3)</p>
     * <p>vtableId(9)</p>
     * @param ResultCode [out] {@code Integer}
     * @param Result [out] {@code String}
     * @param App [in] {@code String}
     * @param User [inout] {@code String}
     * @param Module [in] {@code String}
     * @param Password [in] {@code String}
     * @param Permissions [out] {@code String}
     * @param Data1 [out] {@code String}
     * @param Data2 [out] {@code String}
     * @param Data3 [out] {@code String}
     * @param Data4 [out] {@code String}
     * @param Data5 [out] {@code String}
     * @param UserLevel [out] {@code Integer}
     * @param ExpirationDays [out] {@code Integer}
     * @param Authentication [in] {@code Integer}
     */
    @ComMethod(name = "Login", dispId = 0x3)
    void Login(VARIANT ResultCode,
            BSTRByReference Result,
            String App,
            String User,
            String Module,
            String Password,
            VARIANT Permissions,
            VARIANT Data1,
            VARIANT Data2,
            VARIANT Data3,
            VARIANT Data4,
            VARIANT Data5,
            VARIANT UserLevel,
            VARIANT ExpirationDays,
            Integer Authentication);

That is the JAVA class that TlbCodeGenerator creates from COM DLL. As you can see, ResultCode is detected as VARIANT. I tried using VARIANT.ByReference and didnt work, also tried with ShortByReference, Pointer, short[], ByteByReference, byte, etc.

[UPDATE JAVA Login() CALL]

    Factory factory = new Factory();
    Security isec = factory.createObject(Security.class);

    BSTR bstr_tmp = OleAuto.INSTANCE.SysAllocString("");
    BSTRByReference res = new BSTRByReference(bstr_tmp);
    ShortByReference res_code2 = new ShortByReference();
    
    // I left these fields as VARIANT because I'm not using them in test
    VARIANT.ByReference permisos = new VARIANT.ByReference();
    VARIANT.ByReference data1 = new VARIANT.ByReference();
    VARIANT.ByReference data2 = new VARIANT.ByReference();
    VARIANT.ByReference data3 = new VARIANT.ByReference();
    VARIANT.ByReference data4 = new VARIANT.ByReference();
    VARIANT.ByReference data5 = new VARIANT.ByReference();
    VARIANT.ByReference nivel = new VARIANT.ByReference();
    VARIANT.ByReference exp = new VARIANT.ByReference();

    isec.Login(res_code2, res, "XXXX", "UUUUU", "SSSS", "PPPPP", permisos, data1, data2, data3, data4, data5, nivel, exp, 2);

After isec.Login() call I have 'res' variable filled with a result text (i.e.: "OK.", "ERROR XXX", etc.) and 'res_code2' is 0 (I should have a result code in 'res_code2' like 0x70d1)

[OLE VIEWER DISPLAY] OLEVIEWER

[UPDATE TRYING WITH Connect()]

OLE Method:

[id(0x00000001), helpstring("method Connect")]
    HRESULT Connect(
                    [out] int* ResultCode, 
                    [out] BSTR* Result, 
                    [in] BSTR Host, 
                    [in] short Port);

JAVA Class:

    /**
     * method Connect
     *
     * <p>id(0x1)</p>
     * <p>vtableId(7)</p>
     * @param ResultCode [out] {@code Integer}
     * @param Result [out] {@code String}
     * @param Host [in] {@code String}
     * @param Port [in] {@code Short}
     */
    @ComMethod(name = "Connect", dispId = 0x1)
    void Connect(ShortByReference ResultCode,
            BSTRByReference Result,
            BSTR Host,
            Short Port);

Call:

        Factory factory = new Factory();
        Security isec = factory.createObject(Security.class);
        
        ShortByReference res_code = new ShortByReference();

        BSTR res_bstr = OleAuto.INSTANCE.SysAllocString("");
        BSTRByReference res = new BSTRByReference(res_bstr);
        
        BSTR host = OleAuto.INSTANCE.SysAllocString("XXX.XX.XXX.184");
        Short port = 5000;

        isec.Connect(res_code, res, host, port);
        // Here I can see that the connect() works fine, but I did not receive
        // the res_code value
question from:https://stackoverflow.com/questions/66066718/jna-mapping-int-from-32bits-dll-loaded-in-64bits-java

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...