2013-02-03 35 views
7

के लिए मूल डीएलएल लपेटें मैंने एक सी ++ डीएलएल लिखा और अब मुझे एक प्रबंधित ऐप से मूल फ़ंक्शन कॉल करने की आवश्यकता है।सी #

निर्यात देशी समारोह इस प्रकार दिखेगा:

extern "C" __declspec(dllexport) 
bool NativeMethod(char *param1, char *param2, char *result); 

तो, सी # से मुझे लगता है कि समारोह 2 इनपुट पैरामीटर, 1 उत्पादन परम गुजर फोन करता हूँ और स्पष्ट रूप से मैं वापसी bool मूल्य पढ़ेंगे।

मैंने इसे कई तरीकों से लपेटने की कोशिश की, लेकिन हमेशा मुझे PInvokeStackImbalance अपवाद मिलता है। .NET फ़ंक्शन घोषणा पर CallingConvention = CallingConvention.Cdecl लागू करके मूल कार्य को कॉल करने का एकमात्र तरीका है। हालांकि इस तरह से मैं आउटपुट param (यह हमेशा खाली स्ट्रिंग है) को पढ़ने में सक्षम नहीं हूं और वापसी मूल्य हमेशा सत्य है।

+1

क्या आयात यू की कोशिश की है

मैं एक साधारण सी के साथ एक परीक्षण देशी DLL किया ++? –

+0

मैंने कुछ ऐसा करने की कोशिश की: [DllImport ("MyDll", EntryPoint = "NativeMethod")] सार्वजनिक स्थैतिक बाहरी बूलियन मूलभूत विधि (स्ट्रिंग param1, स्ट्रिंग param2, स्ट्रिंग param3); इसके अलावा param3 या स्ट्रिंगबिल्डर या मार्शलएएस (UnmanagedType.LPStr) के साथ] – bit

+0

आपको एहसास है कि यह आउटपुट पैरामीटर काम नहीं करेगा, है ना? सी # तार ** अपरिवर्तनीय ** हैं। – antonijn

उत्तर

12

सबसे पहले, मैं आपके मूल कार्य के प्रोटोटाइप को समायोजित करूंगा।

चूंकि इस फ़ंक्शन में सी इंटरफ़ेस है, तो आपको बूलियन के लिए सी प्रकार का उपयोग करना चाहिए, सी ++ प्रकार जैसे bool। आप Win32 के BOOL प्रकार का उपयोग करना चाह सकते हैं।

इसके अलावा, के रूप में यह वर्तमान में है, अपने समारोह बफर लगने होने का खतरा है: यह गंतव्य result स्ट्रिंग बफर का अधिकतम आकार निर्दिष्ट करने के लिए दूसरा पैरामीटर जोड़ें बेहतर है।

भी ध्यान रखें कि एक व्यापक शुद्ध सी इंटरफ़ेस कार्यों निर्यात DLLs के लिए सम्मेलन (Win32 एपीआई कार्यों के बहुत सारे की तरह) बुला __stdcall (नहीं __cdecl) है। मैं इसका भी उपयोग करूंगा।

अंतिम, चूंकि पहले दो पैरामीटर इनपुट स्ट्रिंग्स हैं, तो आप इसे स्पष्ट और लागू करने के लिए const का उपयोग करना चाह सकते हैं।

extern "C" __declspec(dllexport) 
BOOL __stdcall NativeFunction(
    const char *in1, 
    const char *in2, 
    char *result, 
    int resultMaxSize); 

फिर, सी # तरफ, आप उपयोग कर सकते हैं निम्नलिखित पी/आह्वान:

तो, मैं इस तरह का निर्यात देशी समारोह के प्रोटोटाइप बनाने चाहते हैं

[DllImport(
     "NativeDll.dll", 
     CharSet = CharSet.Ansi, 
     CallingConvention = CallingConvention.StdCall)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool NativeFunction(
     string in1, 
     string in2, 
     StringBuilder result, 
     int resultMaxSize); 

ध्यान दें कि आउटपुट स्ट्रिंग के लिए, StringBuilder का उपयोग किया जाता है।

भी ध्यान रखें कि CharSet = CharSet.Ansi एएनएसआई (तथ्य यह है कि रूपांतरण हानिपूर्ण है पर ध्यान देने की सी # के यूनिकोड UTF-16 तार मार्शल करने के लिए प्रयोग किया जाता है - आप एक गैर हानिपूर्ण रूपांतरण, बस सी पर wchar_t* तार का उपयोग करना चाहते हैं ++ साथ ही साथ)।

// NativeDll.cpp 

#include <string.h> 
#include <windows.h> 

extern "C" __declspec(dllexport) 
BOOL __stdcall NativeFunction(
    const char *in1, 
    const char *in2, 
    char *result, 
    int resultMaxSize) 
{ 
    // Parameter check 
    if (in1 == nullptr 
     || in2 == nullptr 
     || result == nullptr 
     || resultMaxSize <= 0) 
     return FALSE; 

    // result = in1 + in2 
    strcpy_s(result, resultMaxSize, in1); 
    strcat_s(result, resultMaxSize, in2); 

    // All right 
    return TRUE; 
} 

और यह निम्नलिखित सी # कंसोल अनुप्रयोग कोड द्वारा सफलतापूर्वक कहा जाता है::

using System; 
using System.Runtime.InteropServices; 
using System.Text; 

namespace CSharpClient 
{ 
    class Program 
    { 
     [DllImport(
      "NativeDll.dll", 
      CharSet = CharSet.Ansi, 
      CallingConvention = CallingConvention.StdCall)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     static extern bool NativeFunction(
      string in1, 
      string in2, 
      StringBuilder result, 
      int resultMaxSize); 

     static void Main(string[] args) 
     { 
      var result = new StringBuilder(200); 
      if (! NativeFunction("Hello", " world!", result, result.Capacity)) 
      { 
       Console.WriteLine("Error."); 
       return; 
      } 

      Console.WriteLine(result.ToString()); 
     } 
    } 
} 
+0

बिल्कुल सही। अब सब ठीक काम करता है। आपका बहुत बहुत धन्यवाद!! – bit

+0

@bit: आपका स्वागत है। –

1

क्यों नेट कोड dllimport का उपयोग कर मार्शलिंग का उपयोग कर टिप्पणी जैसे

[DllImport(@"C:\TestLib.dll")] 
     public static extern void ProtectDocument(
      out [MarshalAs(UnmanagedType.LPStr)]string validToDate); 

निम्नलिखित और उसके बाद आप निम्नलिखित

string x=string.empty; 
ProtectDocument(out x); 
+0

डीएलएल आयात सिर्फ वही है जो मैं उपयोग कर रहा हूं लेकिन मुझे उपर्युक्त अपवाद मिल रहा है। साथ ही, मैं तीसरे पैरा को कैसे घोषित कर सकता हूं जिसे मैं "आउट" प्रकार के रूप में उपयोग करना चाहता हूं? – bit

+0

आप चर के –

0
[DllImport("MyDll.dll", EntryPoint = "NativeMethod", CallingConvention = CallingConvention.Cdecl)] 
    static extern bool NativeMethod(
     [MarshalAs(UnmanagedType.LPStr)]string param1, 
     [MarshalAs(UnmanagedType.LPStr)]string param2, 
     [MarshalAs(UnmanagedType.LPStr)]string param3); 

के रूप में स्थानीय समारोह के रूप में समारोह कॉल कर सकते हैं साथ LPStr बदलें LPWStr यदि आप विस्तृत वर्णों के साथ काम कर रहे हैं। के बाद से सी # तार अपरिवर्तनीय हैं

0
[DllImport("MyLibrary.dll", EntryPoint = "NativeMethod")] 
public static unsafe extern bool NativeMethod(
    [MarshalAs(UnmanagedType.LPStr)] string param1, 
    [MarshalAs(UnmanagedType.LPStr)] string param2, 
    [MarshalAs(UnmanagedType.LPStr)] char *param3); 

उत्पादन पैरामीटर, एक char * हो गया है।

[DllImport("MyLibrary.dll", EntryPoint = "NativeMethod")] 
public static unsafe extern bool NativeMethod(
    [MarshalAs(UnmanagedType.LPStr)] string param1, 
    [MarshalAs(UnmanagedType.LPStr)] string param2, 
    out char param3); 

: जब तक उत्पादन पैरामीटर एक स्ट्रिंग लेकिन केवल एक ही चरित्र है, जो मामले में आप सिर्फ यह कर सकते हैं नहीं है

char[] output = new char[100]; 
fixed (char *param = &output[0]) 
{ 
    NativeMethod("blahblah", "blahblah", param); 
} 

: आप विधि (एक असुरक्षित संदर्भ में) इस तरह फोन और तुम सिर्फ इस तरह इसका इस्तेमाल कर सकते हैं:

char output; 
NativeMethod("blahblah", "blahblah", out output); 
+0

के आगे का उपयोग कर सकते हैं मुझे खेद है, लेकिन मुझे अभी भी अपवाद मिलता है। – bit

+0

@bit अब के बारे में कैसे? – antonijn

+0

@ अपवाद क्या है? –

3

आप अगर आप सिर्फ COM इंटरॉप बजाय का उपयोग अपने आप को पी का एक बहुत/बचा सकते हैं सिर दर्द आह्वान। एक COM इंटरफेस में विधि रखो और COM परंपराओं का पालन करने के लिए हस्ताक्षर बदलने के लिए:

interface ISomeInterface : IUnknown 
{ 
    HRESULT NativeMethod([in] BSTR bstrParam1, [in] BSTR bstrParam2, 
         [out] BSTR* pbstrParam3, [out, retval] VARIANT_BOOL* pvbResult); 
} 

मैं बदल चार *BSTR और bool करने के लिएVARIANT_BOOL क्योंकि उन के लिए COM द्वारा इस्तेमाल किया प्रकार के होते हैं करने के लिए क्रमशः तार और बूल। साथ ही, सभी COM विधियों को HRESULT वापस करना होगा। यदि आप "वास्तविक" वापसी मान चाहते हैं तो आपको इसे पैरामीटर के रूप में जोड़ना होगा और रेटवल विशेषता के साथ इसे चिह्नित करना होगा।

तो सी # परियोजना से COM घटक के लिए एक संदर्भ जोड़ सकते हैं और आप अनुमान लगा करने के लिए कैसे सी # प्रकार के साथ सी ++ प्रकार से मिलान करने के बिना एक सहज ज्ञान युक्त सी # हस्ताक्षर मिल जाएगा: (

bool NativeMethod(string bstrParam1, string bstrParam2, out string pbstrParam3) 

कि वह कैसी दिखाई देती है ऑब्जेक्ट ब्राउज़र में।)

+0

मैं आपसे सहमत हूं कि COM सी # ग्राहकों को सुविधा और सादगी प्रदान करता है (वास्तव में, मैंने आपका उत्तर +1 वोट दिया)। हालांकि, एटीएल के साथ सी ++ में COM सर्वर _building_ को मूल डीएलएल से शुद्ध-सी-इंटरफ़ेस फ़ंक्शंस निर्यात करने की तुलना में सीखने की वक्र होती है। यदि ओपी सी ++ में COM घटकों का निर्माण कर सकता है, तो मैं मानता हूं कि यह एक अच्छा सुझाव है। लेकिन अगर वह नहीं कर सकता है, तो शायद मूल सी-इंटरफ़ेस डीएलएल के लिए उचित पी/Invoke लिखने की कोशिश कर रहा है। –

+0

+1 उसी मशीन पर सीएलआर और मूल कोड के बीच गंभीर कार्य के लिए, COM जाने का रास्ता है। लेकिन अगर आप केवल एक चीज कॉल करने की कोशिश कर रहे हैं तो ओवरकिल करें। –