c# एलट एक सी#.NET अनुप्रयोग से डेल्फी डीएलएल को कॉल करना




वाल्ट सॉफ्टवेयर अपडेट (4)

डेल्फी 200 9 में कोड बेहतर काम करता है यदि आप स्पष्ट रूप से एक एसएसआईस्ट्रिंग के रूप में वेरिएबल टाइप करते हैं:

var s : Ansistring;

कॉल के बाद सी # से अपेक्षित परिणाम दे रहा है:

outputInt = 2, outputString = "This is a test 2"

के बजाय

outputInt = 2, outputString = "T"

संपादित करें: मैंने नीचे, इसके बेहतर कार्यान्वयन को पोस्ट किया है। मैंने इसे यहां छोड़ दिया ताकि प्रतिक्रियाएं समझ सकें।

मैंने डेल्फी में डीएलएल लिखने के लिए सही विधि के लिए कई खोज की हैं, और इसे सी # से गुजरने और तारों को वापस करने में सक्षम होने में सक्षम हैं। बहुत सारी जानकारी अपूर्ण या गलत थी। बहुत परीक्षण और त्रुटि के बाद, मुझे समाधान मिला।

इसे डेल्फी 2007 और वीएस 2010 का उपयोग करके संकलित किया गया था। मुझे संदेह है कि यह अन्य संस्करणों में भी ठीक काम करेगा।

डेल्फी कोड यहाँ है। परियोजना में संस्करण जानकारी शामिल करना याद रखें।

library DelphiLibrary;

uses SysUtils;

// Compiled using Delphi 2007.

// NOTE: If your project doesn't have version information included, you may
// receive the error "The "ResolveManifestFiles" task failed unexpectedly"
// when compiling the C# application.

{$R *.res}

// Example function takes an input integer and input string, and returns
// inputInt + 1, and inputString + ' ' + IntToStr(outputInt) as output
// parameters. If successful, the return result is nil (null), otherwise it is
// the exception message string.


// NOTE: I've posted a better version of this below. You should use that instead.

function DelphiFunction(inputInt : integer; inputString : PAnsiChar;
                        out outputInt : integer; out outputString : PAnsiChar)
                        : PAnsiChar; stdcall; export;
var s : string;
begin
  outputInt := 0;
  outputString := nil;
  try
    outputInt := inputInt + 1;
    s := inputString + ' ' + IntToStr(outputInt);
    outputString := PAnsiChar(s);
    Result := nil;
  except
    on e : exception do Result := PAnsiChar(e.Message);
  end;
end;

// I would have thought having "export" at the end of the function declartion
// (above) would have been enough to export the function, but I couldn't get it
// to work without this line also.
exports DelphiFunction;

begin
end.

यहां सी # कोड है:

using System;
using System.Runtime.InteropServices;

namespace CsharpApp
{
    class Program
    {
        // I added DelphiLibrary.dll to my project (NOT in References, but 
        // "Add existing file"). In Properties for the dll, I set "BuildAction" 
        // to None, and "Copy to Output Directory" to "Copy always".
        // Make sure your Delphi dll has version information included.

        [DllImport("DelphiLibrary.dll", 
                   CallingConvention = CallingConvention.StdCall, 
                   CharSet = CharSet.Ansi)]
        public static extern 
            string DelphiFunction(int inputInt, string inputString,
                                  out int outputInt, out string outputString);

        static void Main(string[] args)
        {
            int inputInt = 1;
            string inputString = "This is a test";
            int outputInt;
            string outputString;


// NOTE: I've posted a better version of this below. You should use that instead.


            Console.WriteLine("inputInt = {0}, intputString = \"{1}\"",
                              inputInt, inputString);
            var errorString = DelphiFunction(inputInt, inputString,
                                             out outputInt, out outputString);
            if (errorString != null)
                Console.WriteLine("Error = \"{0}\"", errorString);
            else
                Console.WriteLine("outputInt = {0}, outputString = \"{1}\"",
                                  outputInt, outputString);
            Console.Write("Press Enter:");
            Console.ReadLine();
        }
    }
}

मुझे आशा है कि यह जानकारी किसी और को अपने बालों को खींचने की ज़रूरत नहीं है जितना मैंने किया था।


जैसा कि जेरोइन प्लूइमर ने अपनी टिप्पणी में कहा था, आपको ध्यान रखना चाहिए कि डेल्फी तार संदर्भित हैं।

आईएमओ, ऐसी परिस्थितियों में जिन्हें आप विषम वातावरण में एक स्ट्रिंग वापस करना चाहते हैं, आपको कॉलर से परिणाम के लिए बफर प्रदान करने के लिए कहा जाना चाहिए, और फ़ंक्शन को उस बफर को भरना चाहिए। इस तरह, कॉलर बफर बनाने और इसे करने के दौरान इसे निपटाने के लिए ज़िम्मेदार है। यदि आप Win32 API फ़ंक्शंस को देखते हैं, तो आप देखेंगे कि जब वे कॉलर को स्ट्रिंग वापस करने की आवश्यकता होती है तो वे वही करते हैं।

ऐसा करने के लिए, आप फ़ंक्शन पैरामीटर के प्रकार के रूप में पीसीहर (या तो पैन्सीचर या पीवाइडचर) का उपयोग कर सकते हैं, लेकिन आपको बफर के आकार को प्रदान करने के लिए कॉलर से भी पूछना चाहिए। नमूना स्रोत कोड के लिए नीचे दिए गए लिंक में मेरे उत्तर पर एक नज़र डालें:

एक फ्रीपास्कल संकलित डीएलएल और डेल्फी संकलित EXE के बीच स्ट्रिंग्स (पीसीहर) का आदान-प्रदान

प्रश्न विशेष रूप से फ्रीपास्कल और डेल्फी के बीच स्ट्रिंग का आदान-प्रदान करने के बारे में है, लेकिन विचार और उत्तर आपके मामले पर भी लागू होता है।


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

डेल्फी डीएलएल स्रोत:

library DelphiLibrary;

uses SysUtils;

// Compiled using Delphi 2007.

// NOTE: If your project doesn't have version information included, you may
// receive the error "The "ResolveManifestFiles" task failed unexpectedly"
// when compiling the C# application.

{$R *.res}

// A note on returing strings. I had originally written this so that the
// output string was just a PAnsiChar. But several people pointed out that
// since Delphi strings are reference-counted, this was a bad idea since the
// memory for the string could get overwritten before it was used.
//
// Because of this, I re-wrote the example so that you have to pass a buffer for
// the result strings. I saw some examples of how to do this, where they
// returned the actual string length also. This isn't necessary, because the
// string is null-terminated, and in fact the examples themselves never used the
// returned string length.


// Example function takes an input integer and input string, and returns
// inputInt + 1, and inputString + ' ' + IntToStr(outputInt). If successful,
// the return result is true, otherwise errorMsgBuffer contains the the
// exception message string.
function DelphiFunction(inputInt : integer;
                        inputString : PAnsiChar;
                        out outputInt : integer;
                        outputStringBufferSize : integer;
                        var outputStringBuffer : PAnsiChar;
                        errorMsgBufferSize : integer;
                        var errorMsgBuffer : PAnsiChar)
                        : WordBool; stdcall; export;
var s : string;
begin
  outputInt := 0;
  try
    outputInt := inputInt + 1;
    s := inputString + ' ' + IntToStr(outputInt);
    StrLCopy(outputStringBuffer, PAnsiChar(s), outputStringBufferSize-1);
    errorMsgBuffer[0] := #0;
    Result := true;
  except
    on e : exception do
    begin
      StrLCopy(errorMsgBuffer, PAnsiChar(e.Message), errorMsgBufferSize-1);
      Result := false;
    end;
  end;
end;

// I would have thought having "export" at the end of the function declartion
// (above) would have been enough to export the function, but I couldn't get it
// to work without this line also.
exports DelphiFunction;

begin
end.

सी # कोड:

using System;
using System.Runtime.InteropServices;

namespace CsharpApp
{
    class Program
    {
        // I added DelphiLibrary.dll to my project (NOT in References, but 
        // "Add existing file"). In Properties for the dll, I set "BuildAction" 
        // to None, and "Copy to Output Directory" to "Copy always".
        // Make sure your Delphi dll has version information included.

        [DllImport("DelphiLibrary.dll", 
                   CallingConvention = CallingConvention.StdCall, 
                   CharSet = CharSet.Ansi)]
        public static extern bool 
            DelphiFunction(int inputInt, string inputString,
                           out int outputInt,
                           int outputStringBufferSize, ref string outputStringBuffer,
                           int errorMsgBufferSize, ref string errorMsgBuffer);

        static void Main(string[] args)
        {
            int inputInt = 1;
            string inputString = "This is a test";
            int outputInt;
            const int stringBufferSize = 1024;
            var outputStringBuffer = new String('\x00', stringBufferSize);
            var errorMsgBuffer = new String('\x00', stringBufferSize);

            if (!DelphiFunction(inputInt, inputString, 
                                out outputInt,
                                stringBufferSize, ref outputStringBuffer,
                                stringBufferSize, ref errorMsgBuffer))
                Console.WriteLine("Error = \"{0}\"", errorMsgBuffer);
            else
                Console.WriteLine("outputInt = {0}, outputString = \"{1}\"",
                                  outputInt, outputStringBuffer);

            Console.Write("Press Enter:");
            Console.ReadLine();
        }
    }
}

और यहां एक अतिरिक्त कक्षा है जो दिखाती है कि डीएलएल को गतिशील रूप से कैसे लोड किया जाए (लंबी लाइनों के लिए खेद है):

using System;
using System.Runtime.InteropServices;

namespace CsharpApp
{
    static class DynamicLinking
    {
        [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")]
        static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);

        [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")]
        static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

        [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")]
        static extern bool FreeLibrary(int hModule);

        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)]
        delegate bool DelphiFunction(int inputInt, string inputString,
                                     out int outputInt,
                                     int outputStringBufferSize, ref string outputStringBuffer,
                                     int errorMsgBufferSize, ref string errorMsgBuffer);

        public static void CallDelphiFunction(int inputInt, string inputString,
                                              out int outputInt, out string outputString)
        {
            const string dllName = "DelphiLib.dll";
            const string functionName = "DelphiFunction";

            int libHandle = LoadLibrary(dllName);
            if (libHandle == 0)
                throw new Exception(string.Format("Could not load library \"{0}\"", dllName));
            try
            {
                var delphiFunctionAddress = GetProcAddress(libHandle, functionName);
                if (delphiFunctionAddress == IntPtr.Zero)
                    throw new Exception(string.Format("Can't find function \"{0}\" in library \"{1}\"", functionName, dllName));

                var delphiFunction = (DelphiFunction)Marshal.GetDelegateForFunctionPointer(delphiFunctionAddress, typeof(DelphiFunction));

                const int stringBufferSize = 1024;
                var outputStringBuffer = new String('\x00', stringBufferSize);
                var errorMsgBuffer = new String('\x00', stringBufferSize);

                if (!delphiFunction(inputInt, inputString, out outputInt,
                                    stringBufferSize, ref outputStringBuffer,
                                    stringBufferSize, ref errorMsgBuffer))
                    throw new Exception(errorMsgBuffer);

                outputString = outputStringBuffer;
            }
            finally
            {
                FreeLibrary(libHandle);
            }
        }
    }
}

-Dan


PString का उपयोग कर एक स्ट्रिंग को सेवानिवृत्त करना आसान है:

function DelphiFunction(inputString : PAnsiChar;
                    var outputStringBuffer : PString;
                    var errorMsgBuffer : PString)
                    : WordBool; stdcall; export;
var 
  s : string;
begin
  try
    s := inputString;
    outputStringBuffer:=PString(AnsiString(s));
    Result := true;
  except
    on e : exception do
    begin
      s:= 'error';
      errorMsgBuffer:=PString(AnsiString(e.Message));
      Result := false;
    end;
  end;
end;

सी # में तब:

    const int stringBufferSize = 1024;

    var  str = new    IntPtr(stringBufferSize);

    string loginResult = Marshal.PtrToStringAnsi(str);




dll