2008-09-26 17 views
11

मेरे पास एक तृतीय पक्ष .NET असेंबली और एक बड़ा जावा एप्लिकेशन है। मुझे जावा एप्लिकेशन से .NET क्लास लाइब्रेरी द्वारा प्रदान किए गए मोथोड्स को कॉल करने की आवश्यकता है। असेंबली COM-सक्षम नहीं है। मैं शुद्ध खोज की है और अब तक मैं निम्नलिखित है:जावा से .NET असेंबली को कॉल करना: JVM क्रैश

सी # कोड (cslib.cs):

using System; 

namespace CSLib 
{ 
    public class CSClass 
    { 
     public static void SayHi() 
     { 
      System.Console.WriteLine("Hi"); 
     } 
    } 
} 

(.net का उपयोग कर 3.5, लेकिन एक ही जब 2.0 प्रयोग किया जाता है होता है) के साथ संकलित :

csc /target:library cslib.cs 

सी ++ कोड (clib.cpp):

#include <jni.h> 
#using <CSLib.dll> 

using namespace CSLib; 

extern "C" _declspec(dllexport) void Java_CallCS_callCS(JNIEnv* env, jclass cls) { 
    CSLib::CSClass::SayHi(); 
} 

(कुलपति 2008 उपकरण का उपयोग कर के साथ संकलित है, लेकिन वें ई एक ही होता है 2003 उपकरणों का इस्तेमाल किया जाता है):

cl /clr /LD clib.cpp 
mt -manifest clib.dll.manifest -outputresource:clib.dll;2 

जावा कोड (CallCS.java):

class CallCS { 
    static { 
     System.loadLibrary("clib"); 
    } 
    private static native void callCS(); 
    public static void main(String[] args) { 
     callCS(); 
    } 
} 

जब मैं जावा वर्ग चलाने का प्रयास, जावा वी एम दुर्घटनाओं विधि (लागू करते हुए यह पुस्तकालय लोड करने में सक्षम) है:

 
# 
# An unexpected error has been detected by Java Runtime Environment: 
# 
# Internal Error (0xe0434f4d), pid=3144, tid=3484 
# 
# Java VM: Java HotSpot(TM) Client VM (10.0-b19 mixed mode, sharing windows-x86) 
# Problematic frame: 
# C [kernel32.dll+0x22366] 
# 
... 
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code) 
j CallCS.callCS()V+0 
j CallCS.main([Ljava/lang/String;)V+0 
v ~StubRoutines::call_stub 

हालांकि, अगर मैं एक सादे सीपीपी अनुप्रयोग है कि clib.dll लोड करता है और निर्यात समारोह Java_CallCS_callCS कॉल बनाने के लिए, सब कुछ ठीक है। मैंने x86 और x64 वातावरण दोनों पर यह कोशिश की है और नतीजा वही है। मैंने जावा के अन्य संस्करणों की कोशिश नहीं की है, लेकिन मुझे कोड 1.5.0 पर चलाने की आवश्यकता है।

इसके अलावा, अगर मैं केवल प्रणाली तरीकों कॉल करने के लिए clib.cpp संशोधित सब कुछ जावा से भी ठीक काम करता है:

#include <jni.h> 
#using <mscorlib.dll> 

using namespace System; 

extern "C" _declspec(dllexport) void Java_CallCS_callCS(JNIEnv* env, jclass cls) { 
    System::Console::WriteLine("It works"); 
} 

लपेट के लिए:

  1. मैं जावा से सिस्टम तरीकों कॉल करने के लिए कर रहा हूँ -> clib.dll -> mscorlib.dll
  2. मैं CPPApp से किसी भी तरीकों कॉल करने के लिए कर रहा हूँ -> clib.dll -> cslib.dll
  3. मैं जावा से किसी भी तरीकों कॉल करने में असमर्थ हूँ -> clib.dll - > सीएस lib.dll

मैं एक समाधान के ऊपर 1. का उपयोग करता है के बारे में पता कर रहा हूँ - मैं केवल सिस्टम कॉल का उपयोग कर assmebly लोड और वांछित विधियां प्रारंभ करने प्रतिबिंब का उपयोग कर सकते हैं, लेकिन कोड गंदा हो जाता है और मैं एक बेहतर करने के लिए आशा करता हूं उपाय।

मुझे डॉटनेटफॉम्वावा प्रोजेक्ट के बारे में पता है, जो प्रतिबिंब विधि का उपयोग करता है, लेकिन आवश्यकता से अधिक जटिलता नहीं जोड़ना पसंद करता है। हालांकि, अगर कोई दूसरा रास्ता नहीं है तो मैं इस तरह कुछ उपयोग करूंगा।

मैंने ikvm.net पर भी देखा है, लेकिन मेरी समझ यह है कि यह जादू करने के लिए अपने स्वयं के JVM (सी # में लिखा गया) का उपयोग करता है। हालांकि, पूरे जावा एप्लिकेशन को अपने वीएम के तहत चलाने के लिए मेरे लिए कोई विकल्प नहीं है।

धन्यवाद।

+0

सी ++ कोड वास्तव में C++/CLI सही है? – Gili

+0

हां,/clr विकल्प निर्दिष्ट किया गया है – Kcats

उत्तर

10

ठीक है, रहस्य हल हो गया है।

जेवीएम क्रैश अनचाहे System.IO.FileNotFoundException के कारण होता है। अपवाद फेंक दिया गया है क्योंकि .NET असेंबली उस फ़ोल्डर में खोजी जाती है जहां कॉलिंग exe फ़ाइल रहता है।

  1. mscorlib.dll वैश्विक असेंबली कैश में है, इसलिए यह काम करता है।
  2. सीपीपी एप्लिकेशन exe असेंबली के समान फ़ोल्डर में है, इसलिए यह भी काम करता है।
  3. cslib.dll असेंबली java.exe के फ़ोल्डर में, जीएसी में एनओआर में नहीं है, इसलिए यह काम नहीं करता है।

ऐसा लगता है मेरी ही एकमात्र विकल्प GAC में नेट विधानसभा (तृतीय-पक्ष dll एक मजबूत नाम है) स्थापित करने के लिए है।

+7

वाह इसे साझा करने के लिए धन्यवाद, मैं इस सटीक समस्या को समझने की कोशिश कर रहा हूं। मैं वास्तव में विभिन्न कारणों से जीएसी से बचना चाहता था, इसलिए मुझे असेंबली रीसोल्व इवेंट का उपयोग करके असेंबली को अपनी पसंद के रास्ते से मैन्युअल रूप से लोड करने का एक तरीका मिला: http://www.devcity.net/Articles/254/1/.aspx । आपको सी ++/सीएलआई परत में इस घटना को संभालना होगा क्योंकि सी # असेंबली अभी तक लोड नहीं हुई हैं। वैसे भी, उम्मीद है कि यह किसी अन्य गूगलर के लिए सहायक होगा ... – Jason

+0

इसे साझा करने के लिए धन्यवाद, वास्तव में मैं वास्तव में असेंबली रीसोल्व घटना का उपयोग कर समाप्त हुआ, लेकिन उत्तर को अपडेट करना भूल गया। – Kcats

2

क्या आपने ikvm.NET पर देखा है, जो .NET और जावा कोड के बीच कॉल की अनुमति देता है?

4

jni4net पर देखें, यह आपके लिए कड़ी मेहनत करेगा।

+0

वाह। अच्छा! लिंक के लिए धन्यवाद। – dthorpe

+0

केवल विंडोज़ पर – eomeroff

0

मैं इस आलेख को ढूंढने में बहुत खुश था क्योंकि मैं अटक गया था और वास्तव में वह समस्या थी। मैं कुछ कोड योगदान देना चाहता हूं, जो इस समस्या को दूर करने में मदद करता है। अपने जावा कन्स्ट्रक्टर में इनिट विधि को कॉल करें, जो हल ईवेंट को जोड़ता है। मेरा अनुभव सी ++ कोड में आपकी लाइब्रेरी में कॉल करने से ठीक पहले इनिट को कॉल करना आवश्यक है, क्योंकि समय की समस्याओं के कारण यह फिर भी क्रैश हो सकता है। मैंने जेएनआई कॉल मैपिंग के अपने जावा क्लास कन्स्ट्रक्टर में इनिट कॉल डाला है, जो बहुत अच्छा काम करता है।

//C# code 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 
using System.Security.Permissions; 
using System.Runtime.InteropServices; 

namespace JNIBridge 
{ 
    public class Temperature 
    { 

     [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode | SecurityPermissionFlag.Assertion | SecurityPermissionFlag.Execution)] 
     [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] 
     [FileIOPermission(SecurityAction.Assert, Unrestricted = true)] 

     public static double toFahrenheit(double value) 
     { 
      return (value * 9)/5 + 32; 
     } 

     [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode | SecurityPermissionFlag.Assertion | SecurityPermissionFlag.Execution)] 
     [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)] 
     [FileIOPermission(SecurityAction.Assert, Unrestricted = true)] 

     public static double toCelsius(double value) 
     { 
      return (value - 32) * 5/9; 
     } 


    } 
} 

सी ++ कोड

// C++ Code 

#include "stdafx.h" 

#include "JNIMapper.h" 
#include "DotNet.h" 
#include "stdio.h" 
#include "stdlib.h" 

#ifdef __cplusplus 
extern "C" { 
#endif 
/* 
* Class:  DotNet 
* Method: toFahrenheit 
* Signature: (D)D 
*/ 

static bool initialized = false; 
using namespace System; 
using namespace System::Reflection; 

/*** 
This is procedure is always needed when the .NET dll's arent in the actual directory of the calling exe!!! 
It loads the needed assembly from a predefined path, if found in the directory and returns the assembly. 
*/ 

Assembly ^OnAssemblyResolve(Object ^obj, ResolveEventArgs ^args) 
{ 
    //System::Console::WriteLine("In OnAssemblyResolve"); 
#ifdef _DEBUG 
      /// Change to your .NET DLL paths here 
    String ^path = gcnew String("d:\\WORK\\JNIBridge\\x64\\Debug"); 
#else 
    String ^path = gcnew String(_T("d:\\WORK\\JNIBridge\\x64\\Release")); 
#endif 
    array<String^>^ assemblies = 
     System::IO::Directory::GetFiles(path, "*.dll"); 
    for (long ii = 0; ii < assemblies->Length; ii++) { 
     AssemblyName ^name = AssemblyName::GetAssemblyName(assemblies[ii]); 
     if (AssemblyName::ReferenceMatchesDefinition(gcnew AssemblyName(args->Name), name)) { 
     // System::Console::WriteLine("Try to resolve "+ name); 
      Assembly ^a = Assembly::Load(name); 
      //System::Console::WriteLine("Resolved "+ name); 
      return a; 
     } 
    } 
    return nullptr; 
} 

/** 
This procedure adds the Assembly resolve event handler 
*/ 
void AddResolveEvent() 
{ 
    AppDomain::CurrentDomain->AssemblyResolve += 
     gcnew ResolveEventHandler(OnAssemblyResolve); 
} 
/* 
* Class:  DotNet 
* Method: init 
* Signature:()Z 
*/ 
JNIEXPORT jboolean JNICALL Java_DotNet_init 
    (JNIEnv *, jobject) 

{ 
    printf("In init\n");  
    AddResolveEvent(); 
    printf("init - done.\n"); 
    return true; 

} 

/* 
* Class:  DotNet 
* Method: toFahrenheit 
* Signature: (D)D 
*/ 

JNIEXPORT jdouble JNICALL Java_DotNet_toFahrenheit 
    (JNIEnv * je, jobject jo, jdouble value) 
{ 
    printf("In Java_DotNet_toFahrenheit\n"); 

     double result = 47; 

     try{   
      result = JNIBridge::Temperature::toFahrenheit(value); 
     } catch (...){ 
      printf("Error caught"); 
     } 
     return result; 
} 

/* 
* Class:  DotNet 
* Method: toCelsius 
* Signature: (D)D 
*/ 
JNIEXPORT jdouble JNICALL Java_DotNet_toCelsius 
    (JNIEnv * je, jobject jo , jdouble value){ 

     printf("In Java_DotNet_toCelsius\n"); 

     double result = 11; 

     try{ 

      result = JNIBridge::Temperature::toCelsius(value); 
     } catch (...){ 
      printf("Error caught"); 
     } 

     return result; 
} 


#ifdef __cplusplus 

} 

जावा कोड

/*** 
    ** Java class file 
    **/ 
public class DotNet {  
    public native double toFahrenheit (double d); 
    public native double toCelsius (double d); 
    public native boolean init(); 

    static { 
     try{    
      System.loadLibrary("JNIMapper"); 
     } catch(Exception ex){ 
      ex.printStackTrace(); 
     } 
    }   

    public DotNet(){ 
     init(); 
    } 

    public double fahrenheit (double v) { 
     return toFahrenheit(v); 
    } 

    public double celsius (double v) { 
     return toCelsius(v); 
    } 

} 
संबंधित मुद्दे