簡體   English   中英

如何在Java和C#之間為JNA包裝它時,在非托管C ++中創建托管對象?

[英]How to create managed object in unmanaged C++ while wrapping it for JNA between Java and C#?

我試圖使用JNA在C#和Java之間建立一個回調接口。

C# < - CLI - > Visual C ++ 2010 < - JNA - > Java

在Java和C ++之間我使用非托管結構來獲得回調功能。 在C ++中,我試圖將具有回調指針的結構包裝到托管對象中。

在Java和C ++之間,一切正常,直到我嘗試使用gcroot在非托管代碼中生成托管對象。

更新它甚至沒有gcroot失敗。 只需使用“Logger ^ logger = gcnew Logger(logStruct);”

我目前的解決方案如下:

Java的

LoggerStruct.java

package jnatest;

import com.sun.jna.Callback;
import com.sun.jna.Structure;
import java.util.logging.Logger;

public class LoggerStruct extends Structure {
    private Logger logger;

    public interface GetLevelCallback extends Callback {
        int callback();
    }

    public GetLevelCallback getLevel;

    public LoggerStruct(Logger log) {
        super();
        this.log = log;

        getLevel = new GetLevelCallback() {
            public int callback() {
                return logger.getLevel().intValue();
            }
        }

        setFieldOrder(new String[] {"getLevel"});
    }
}

ITestLib.java

package jnatest;

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface ITestLib extends Library {
    ITestLib INSTANCE = (ITestLib) Native.loadLibrary("JNATestC", ITestLib.class);
    int callbackTest(LoggerStruct logStruct);
}

Main.java

package jnatest;

import com.sun.jna.NativeLibrary;
import java.util.logging.Logger;
import java.util.logging.FileHandler;

public class MainClass {
    public static void main(String[] args) throws Exception  {
        NativeLibrary.addSearchPath("JNATestC", "C:\\JNATest");

        Logger log = Logger.getLogger("Test");
        FileHandler fileTxt = new FileHandler("Logging.txt");
        log.addHandler(fileTxt);

        LoggerStruct logStruct = new LoggerStruct(log);

        ITestLib.INSTANCE.callbackTest(logStruct);
    }
}

C ++

JNATestC.h

#pragma once

extern "C" {
    struct LoggerStruct {
        int (*getLevel)();
    }
    __declspec(dllexport) void callbackTest(LoggerStruct * logStruct);
}

namespace JnaWrapperTypes {
    public ref class Logger { // "public ref" because I have to use it in C# as well
        private:
            LoggerStruct * logStruct;
        public:
            Logger(LoggerStruct * logStruct);
            ~Logger() {} 
            int getLevel();
    };
}

JNATestC.cpp

#include "stdafx.h"
#include <vcclr.h>
#include "JNATestC.h"

namespace JnaWrapperTypes {
    Logger::Logger(LoggerStruct * logStruct) {
        this->logStruct = logStruct;
    }
    Logger::getLevel() {
        return logStruct->getLevel();
    }
}

using namespace JnaWrapperTypes;
using namespace StaticCSharpNamespace; // Just an example. Not existing C# lib.

extern "C" {
    __declspec(dllexport) void callbackTest(LoggerStruct * logStruct) {
        int level = logStruct->getLevel();

        gcroot<Logger^> logger = gcnew Logger(logStruct); // IF I ADD "gcroot" FOR "Logger" THEN WHOLE INVOKE FAILS
        level = logger->getLevel();

        StaticCSharpClass::staticMethod(logger); // I want to pass Managed object to C# later

        gcroot<System::String^> str = gcnew System::String(""); // This doesn't generate error
    }
}

我在飛行中寫了這些。 我希望這些也可以驗證。

我究竟做錯了什么? 例如,如果我使用...

gcroot<System::String^> str = gcnew System::String("");

......一切正常

是否有另一種方法將托管對象傳遞給C#?

記錄此錯誤日志

UPDATE

似乎任何我自己的Class用法都會讓我失敗。

UPDATE

我自己管理的對象或函數的Anykind使我失敗。

UPDATE

StaticCSharpClass :: STATICMETHOD(); 也失敗了。 看起來所有與托管對象相關的操作都會失敗。

UPDATE

如果我從.NET調用相同的方法,一切正常。

只是為了讓這個問題更容易找到內部錯誤(0xe0434352)

應該用Google搜索錯誤“內部錯誤(0xe0434352)”。

http://jira.talendforge.org/browse/TDI-19427

這導致我必須為GAC(全局程序集緩存)注冊dll,因為Java只搜索GAC和Application Base目錄中的dll。 並且因為Java.exe路徑不可配置。

==解決方案==

使用post build事件為GAC注冊程序集:

gacutil /i "$(TargetPath)"

偉大的獨白! =)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM