2012-02-19 9 views
40

मैं कर दिया है, एक से अधिक अवसर पर, लोगों को इंटरॉप प्रयोजनों के लिए प्रकार WideString की वापसी मान का उपयोग करने की सलाह दी।इंटरऑप के लिए फ़ंक्शन रिटर्न वैल्यू के रूप में वाइडस्ट्रिंग का उपयोग क्यों नहीं किया जा सकता है?

विचार है कि एक WideString एक BSTR रूप में ही है। क्योंकि एक BSTR साझा कॉम ढेर पर आवंटित किया जाता है तो यह एक अलग मॉड्यूल में एक मॉड्यूल और पुनःआवंटन में आवंटित करने के लिए कोई समस्या नहीं है। ऐसा इसलिए है क्योंकि सभी पार्टियां एक ही ढेर, COM ढेर का उपयोग करने के लिए सहमत हो गई हैं।

हालांकि, ऐसा लगता है कि WideString इंटरॉप के लिए एक समारोह वापसी मान के रूप में नहीं किया जा सकता।

निम्नलिखित डेल्फी DLL पर विचार करें।

library WideStringTest; 

uses 
    ActiveX; 

function TestWideString: WideString; stdcall; 
begin 
    Result := 'TestWideString'; 
end; 

function TestBSTR: TBstr; stdcall; 
begin 
    Result := SysAllocString('TestBSTR'); 
end; 

procedure TestWideStringOutParam(out str: WideString); stdcall; 
begin 
    str := 'TestWideStringOutParam'; 
end; 

exports 
    TestWideString, TestBSTR, TestWideStringOutParam; 

begin 
end. 

और निम्नलिखित सी ++ कोड:

typedef BSTR (__stdcall *Func)(); 
typedef void (__stdcall *OutParam)(BSTR &pstr); 

HMODULE lib = LoadLibrary(DLLNAME); 
Func TestWideString = (Func) GetProcAddress(lib, "TestWideString"); 
Func TestBSTR = (Func) GetProcAddress(lib, "TestBSTR"); 
OutParam TestWideStringOutParam = (OutParam) GetProcAddress(lib, 
        "TestWideStringOutParam"); 

BSTR str = TestBSTR(); 
wprintf(L"%s\n", str); 
SysFreeString(str); 
str = NULL; 

TestWideStringOutParam(str); 
wprintf(L"%s\n", str); 
SysFreeString(str); 
str = NULL; 

str = TestWideString();//fails here 
wprintf(L"%s\n", str); 
SysFreeString(str); 

TestWideString करने के लिए कॉल इस त्रुटि के साथ विफल:

Unhandled exception at 0x772015de in BSTRtest.exe: 0xC0000005: Access violation reading location 0x00000000.

इसी प्रकार, यदि हम पी के साथ सी # से कॉल करने के लिए कोशिश/आह्वान , हमारे पास विफलता है:

[DllImport(@"path\to\my\dll")] 
[return: MarshalAs(UnmanagedType.BStr)] 
static extern string TestWideString(); 

त्रुटि है:

An unhandled exception of type 'System.Runtime.InteropServices.SEHException' occurred in ConsoleApplication10.exe

Additional information: External component has thrown an exception.

कॉलिंग TestWideString पी के माध्यम से/आह्वान काम करता है के रूप में उम्मीद।

तो, उपयोग पारित-दर-संदर्भ WideString मानकों के साथ और उन्हें मानचित्रण BSTR पर पूरी तरह से अच्छी तरह से काम करने के लिए प्रकट होता है। लेकिन फ़ंक्शन रिटर्न मानों के लिए नहीं। मैंने डेल्फी 5, 2010 और एक्सई 2 पर इसका परीक्षण किया है और सभी संस्करणों पर एक ही व्यवहार का निरीक्षण किया है।

निष्पादन डेल्फी प्रवेश करती है और लगभग तुरंत विफल रहता है। Result असाइनमेंट System._WStrAsg के लिए एक कॉल में बदल जाता है, जो की पहली पंक्ति में लिखा है:

 
CMP  [EAX],EDX 

अब, EAX$00000000 है और स्वाभाविक रूप से वहाँ एक पहुँच उल्लंघन है।

क्या कोई इसे समझा सकता है? क्या मुझसे कुछ गलत हो रही है? क्या मैं WideString फ़ंक्शन मानों को BSTR के व्यवहार्य होने की अपेक्षा करने में अनुचित हूं? या यह सिर्फ एक डेल्फी दोष है?

+5

डेविड, हो सकता है कि 'सी जोड़ने ++', 'सी #' भी टैग? – kobik

+0

@ कोबिक मेरा मानना ​​है कि यह वास्तव में एक प्रश्न है कि डेल्फी वापसी मूल्यों को कैसे लागू करता है। मुझे लगता है कि डेल्फी अजीब है। –

+0

@J ... मैंने कभी भी एक COM विधि नहीं देखी है जो 'HRESULT' वापस नहीं लौटा। हालांकि मैं COM में BSTR का उपयोग करने के बारे में बात नहीं कर रहा हूं। मैं इसके बारे में विभिन्न मॉड्यूल के बीच एक ढेर साझा करने के लिए एक सुविधाजनक तरीका के रूप में बात कर रहा हूँ। –

उत्तर

21

नियमित डेल्फी कार्यों में, फ़ंक्शन रिटर्न वास्तव में संदर्भ द्वारा पारित पैरामीटर है, भले ही वाक्य रचनात्मक रूप से यह 'आउट' पैरामीटर जैसा दिखता है और महसूस करता है।आप इस बाहर का परीक्षण कर सकते तो (इस संस्करण निर्भर हो सकता है) की तरह:

function DoNothing: IInterface; 
begin 
    if Assigned(Result) then 
    ShowMessage('result assigned before invocation') 
    else 
    ShowMessage('result NOT assigned before invocation'); 
end; 

procedure TestParameterPassingMechanismOfFunctions; 
var 
    X: IInterface; 
begin 
    X := TInterfaceObject.Create; 
    X := DoNothing; 
end; 

प्रदर्शित करने के लिए कॉल TestParameterPassingMechanismOfFunctions()

आपका कोड डेल्फी और सी ++ के के संबंध में बुला सम्मेलन की समझ के बीच एक बेमेल की वजह से विफल हो रहा है कार्य परिणामों के लिए गुजरने की व्यवस्था। सी ++ में फ़ंक्शन रिटर्न सिंटैक्स की तरह कार्य करता है सुझाव देता है: out पैरामीटर। लेकिन डेल्फी के लिए यह var पैरामीटर है।

ठीक करने के लिए, इस कोशिश: सी # में

function TestWideString: WideString; stdcall; 
begin 
    Pointer(Result) := nil; 
    Result := 'TestWideString'; 
end; 
+5

यह व्यवहार्य लगता है, लेकिन 'सूचक (परिणाम): = nil' स्वयं एक एवी उठाता है। –

+0

कार्यों के लिए, डेल्फी परिणामस्वरूप सूचकांक को ईएक्स में संग्रहीत करता है। यह बहुत कुछ बताता है। डेल्फी के दृष्टिकोण से आप एक var पैरामीटर के रूप में "कोई चर" में पास नहीं कर सकते हैं। –

+0

मुझे यकीन नहीं है कि क्या आप सिर्फ एक व्याख्या या कार्य-आसपास चाहते हैं। आपको शायद काम की आवश्यकता नहीं है क्योंकि, जैसा कि आपने पहले ही कहा है, स्पष्ट आउट पैरामीटर तंत्र काम करता है। –

17

/C++ आप stdcall बुला सम्मेलनों के बाइनरी कोड संगतता को बनाए रखने के क्रम में, out पैरामीटर के रूप में परिणाम को परिभाषित करने की आवश्यकता होगी:

Returning Strings and Interface References From DLL Functions

In the stdcall calling convention, the function’s result is passed via the CPU’s EAX register. However, Visual C++ and Delphi generate different binary code for these routines.

डेल्फी कोड वही रहता है:

function TestWideString: WideString; stdcall; 
begin 
    Result := 'TestWideString'; 
end; 

सी # कोड:

// declaration 
[DllImport(@"Test.dll")]   
static extern void TestWideString([MarshalAs(UnmanagedType.BStr)] out string Result); 
... 
string s; 
TestWideString(out s); 
MessageBox.Show(s); 
+5

+1 हां यह करता है। मैं अभी भी यहां पर वास्तव में क्या चल रहा है के आसपास अपना सिर नहीं मिल सकता !! –

+0

ध्यान दें कि मेरे परीक्षण से ऐसा लगता है कि परिणाम पैरामीटर हमेशा सूची में सबसे पहले होता है यदि आपके पास एकाधिक पैरामीटर हैं, जो कि माना जा सकता है। –

+0

@ जैमीकिटसन मैं उस टिप्पणी को समझ नहीं पा रहा हूं। यदि आपका मतलब है कि डेल्फी फ़ंक्शन रिटर्न मान को वापस करने के लिए उपयोग किए जाने वाले var पैरामीटर को इंगित करता है, तो अतिरिक्त पैरामीटर दूसरों के बाद पारित किया जाता है। यह स्पष्ट रूप से यहां दस्तावेज किया गया है: http://docwiki.embarcadero.com/RADStudio/en/Program_Control#Handling_Function_Results –

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

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