Как создать управляемый объект в неуправляемом C ++, одновременно оборачивая его для JNA между Java и C #? - PullRequest
5 голосов
/ 07 февраля 2012

Я пытаюсь создать интерфейс обратного вызова между C # и Java, используя JNA.

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

Кажется, что любое использование моего Класса приведет меня к провалу.

UPDATE

Любое использование моего управляемого объекта или функции приводит меня к неудаче.

UPDATE

StaticCSharpClass :: STATICMETHOD (); тоже не получается. Похоже, что все операции, связанные с управляемыми объектами, не выполняются.

UPDATE

Если я вызываю тот же метод из .NET, все работает нормально.

только для того, чтобы сделать эту проблему более доступной Внутренняя ошибка (0xe0434352)

1 Ответ

4 голосов
/ 08 февраля 2012

Должен был погуглить на предмет ошибки «Внутренняя ошибка (0xe0434352)».

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

Это приводит к тому, что я должен зарегистрировать dll для GAC (Global Assembly Cache),потому что Java ищет только dll в каталогах GAC и Application Base.И поскольку пути Java.exe не настраиваются.

== Решение ==

Используйте событие после сборки, чтобы зарегистрировать сборку для GAC:

gacutil /i "$(TargetPath)"

Отличный монолог!=)

...