2012-12-27 13 views
5

मैं जावा प्रोग्राम से डेल्फी संकलित * .so फ़ाइल से फ़ंक्शंस कॉल करने पर काम कर रहा हूं। कुछ शोध के बाद ऐसा लगता है कि JNA वह जाने का रास्ता है। कुछ जटिल डेल्फी कोड में डाइविंग से पहले, मैं कुछ "हैलो वर्ल्ड" कोड के साथ खेलने की कोशिश कर रहा हूं लेकिन मुझे डेल्फी फ़ंक्शन द्वारा लौटाई गई स्ट्रिंग प्राप्त करने में समस्या हो रही है।मैं डेल्फी फ़ंक्शन को कैसे कॉल कर सकता हूं जो जेएनए का उपयोग करके स्ट्रिंग देता है?

डेल्फी कोड (helloworld.pp):

library HelloWorldLib; 

function HelloWorld(const myString: string): string; stdcall; 
begin 
    WriteLn(myString); 
    Result := myString; 
end; 

exports HelloWorld; 

begin 
end. 

मैं "पांचवें वेतन आयोग -Mdelphi helloworld.pp" के साथ कमांड लाइन है, जो libhelloworld.so का उत्पादन से यह संकलन।

अब मेरी जावा वर्ग:

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

public class HelloWorld { 
    public interface HelloWorldLibrary extends Library { 
     HelloWorldLibrary INSTANCE = (HelloWorldLibrary) Native.loadLibrary("/full/path/to/libhelloworld.so", HelloWorldLibrary.class); 

     String HelloWorld(String test); 
    } 

    public static void main(String[] args) { 
     System.out.println(HelloWorldLibrary.INSTANCE.HelloWorld("QWERTYUIOP")); 
    } 
} 

लेकिन जब मैं इस जावा कोड चलाने मैं:

# A fatal error has been detected by the Java Runtime Environment: 
# 
# SIGSEGV (0xb) at pc=0x00007f810318add2, pid=4088, tid=140192489072384 
# 
# JRE version: 7.0_10-b18 
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.6-b04 mixed mode linux-amd64 compressed oops) 
# Problematic frame: 
# C [libhelloworld.so+0xbdd2] HelloWorld+0x6fea 

ध्यान दें कि अगर मैं अपने डेल्फी विधि (और संबद्ध जावा इंटरफेस) बदलने के वापस जाने के लिए एक हार्डकोडेड पूर्णांक, सबकुछ बढ़िया काम करता है: जिस स्ट्रिंग को पास किया जाता है वह मुद्रित हो जाता है और मुझे उम्मीद के अनुसार int वापस मिल जाता है।

आश्चर्यजनक रूप से पर्याप्त है, अगर डेल्फी विधि एक char लौटाती है, तो मुझे एक बाइट लौटने के रूप में अपनी जेएनए प्रॉक्सी लिखनी है और इसे मैन्युअल रूप से चार में डालना है (अगर मैं एक चार्ट लौटने के रूप में अपना इंटरफेस घोषित करता हूं तो यह एक कचरा चरित्र प्रिंट करता है)।

कोई विचार क्या गलत हो रहा है?

एफवाईआई, मैं सूर्य जेडीके 1.7.0_10-बी 18, जेएनए 3.5.1 और फ्री पास्कल कंपाइलर संस्करण 2.4.4-3.1 का उपयोग करते हुए उबंटू 12.04, 64 बिट्स पर हूं।

+0

क्या आप पारित किए गए मूल कार्य से अन्य 'स्ट्रिंग' वापस कर सकते हैं? – JimmyB

+0

@ हनो बाइंडर: अगर मैं अपना परिणाम डेल्फी कोड बदलता हूं तो मुझे एक ही त्रुटि मिलती है "परिणाम: = 'हैलो';"। :( –

उत्तर

8

ए डेल्फी या फ्रीपास्कल string एक प्रबंधित प्रकार है जिसे जेएनए प्रकार के रूप में उपयोग नहीं किया जा सकता है। JNA documentation बताता है कि जावा String को 8 बिट वर्णों की एक नल-टर्मिनेटेड सरणी में पॉइंटर पर मैप किया गया है। डेल्फी शर्तों में PAnsiChar है।

तो आप string से PAnsiChar पर अपने पास्कल कोड में इनपुट पैरामीटर बदल सकते हैं।

वापसी मूल्य अधिक समस्याग्रस्त है। आपको यह तय करने की आवश्यकता होगी कि स्मृति आवंटित कौन करेगा। और जो भी इसे आवंटित करता है उसे भी मुक्त करना होगा।

यदि मूल कोड इसे आवंटित करने के लिए ज़िम्मेदार है तो आपको शून्य-समाप्त स्ट्रिंग आवंटित करने की आवश्यकता होगी। और इसके लिए एक सूचक वापस करें। आपको एक डीलोकेटर को भी निर्यात करने की आवश्यकता होगी ताकि जावा कोड मूल कोड को स्मृति के आवंटित ब्लॉक को आवंटित करने के लिए कह सके।

जावा कोड में एक बफर आवंटित करना आमतौर पर अधिक सुविधाजनक होता है। फिर इसे देशी कोड में पास करें और इसे बफर की सामग्री भरने दें। यह स्टैक ओवरफ़्लो सवाल तकनीक दिखाता है, इसके उदाहरण के रूप में Windows API समारोह GetWindowText का उपयोग कर: How can I read the window title with JNI or JNA?

इस पास्कल का उपयोग करने का एक उदाहरण तो जैसा होगा:

function GetText(Text: PAnsiChar; Len: Integer): Integer; stdcall; 
const 
    S: AnsiString = 'Some text value'; 
begin 
    Result := Length(S)+1;//include null-terminator 
    if Len>0 then 
    StrPLCopy(Text, S, Len-1); 
end; 

जावा पक्ष पर, मैं कोड अनुमान इस तरह दिखेगा, इस बात को ध्यान में रखते हुए कि मुझे जावा के बारे में बिल्कुल कुछ नहीं पता है।

public interface MyLib extends StdCallLibrary { 
    MyLib INSTANCE = (MyLib) Native.loadLibrary("MyLib", MyLib.class); 
    int GetText(byte[] lpText, int len); 
} 

.... 

int len = User32.INSTANCE.GetText(null); 
byte[] arr = new byte[len]; 
User32.INSTANCE.GetText(arr, len); 
String Text = Native.toString(arr); 
+0

अहह आप सही हैं। इससे पॉइंटर्स, मॉलोक इत्यादि की यादें सामने आती हैं जो जेवीएम कचरा कलेक्टर के साथ काम करने के वर्षों के दौरान गायब हो गईं ... बीटीडब्ल्यू डेल्फी विधि वाले एक पीएनएसआईआईआरआर को जेएनए मैपिंग के साथ काम करता है । (लेकिन फिर स्मृति आवंटन के मुद्दे खुलता है) वापसी प्रकार के रूप में एक स्ट्रिंग –

+0

जावा वर्ग इस तरह दिखता है: सार्वजनिक वर्ग HelloWorld { \t सार्वजनिक इंटरफ़ेस HelloWorldLibrary फैली लाइब्रेरी { \t \t HelloWorldLibrary उदाहरण = (HelloWorldLibrary) Native.loadLibrary ("/home/clevesque/Desktop/delphi/libhelloworld.so", HelloWorldLibrary.class); \t \t int गेटटेक्स्ट (बाइट [] बफर); \t} \t public static void (String [] args) { \t \t बाइट [] बफर = नए बाइट [512]; \t \t System.out.println (HelloWorldLibrary.INSTANCE.GetText (बफर)); \t \t System.out.println (Native.toString (बफर)); \t} } –

+0

दरअसल, 'पेंसिहर' वापस लौटने से स्मृति मॉड्यूल को ठीक कर दिया गया है। –

0

इसके अलावा, 64-बिट लिनक्स पर stdcall का उपयोग पूरी तरह तार्किक नहीं है। यह शायद काम करता है, क्योंकि आमतौर पर 64-बिट लक्ष्य पर केवल एक कॉलिंग सम्मेलन होता है, लेकिन सही है, यह नहीं है। सीडीईसीएल का प्रयोग करें;

+0

निश्चित रूप से पारंपरिक सजावटकर्ताओं को कॉल करना x64 लक्ष्यों के लिए अनदेखा किया जाता है। यदि x86 के लिए एक ही कोड कभी संकलित किया जाता है तो कॉलिंग सम्मेलन फिर से महत्वपूर्ण हो जाता है। –

+0

ठीक है, यह वही है जो मैं कह रहा हूं, है ना? काम करने के लिए होता है सही से अलग है। –

+0

एक आश्चर्य है कि StdCallLibrary का अर्थ लिनक्स पर क्या है –

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

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