Recent

Author Topic: Calling DLL from C# - Passing WideString as parameter  (Read 10413 times)

lainz

  • Hero Member
  • *****
  • Posts: 4470
    • https://lainz.github.io/
Calling DLL from C# - Passing WideString as parameter
« on: April 28, 2015, 06:44:41 am »
Hi, this is the way I find to use unicode strings in a ShowMessage dialog (as a test only of course, it can be used for anything...) stored inside a lazarus .dll under Windows 7 called from C#.

This is the DLL compiled with Lazarus (it uses LCL as dependency in order to enable dialog message...):
Code: [Select]
library csharpdllstring;

{$mode objfpc}{$H+}

uses
  Interfaces, Classes, Dialogs
  { you can add units after this };

procedure ShowDefaultMessage(); stdcall;
begin
  ShowMessage('Example Message.');
end;

procedure ShowStringMessage(const message: PWideChar); stdcall;
begin
  ShowMessage(UTF8Encode(WideString(message)));
end;

exports
ShowDefaultMessage,
ShowStringMessage;

begin
end.
     

There are two functions, one that will display a message that is stored internally in the dll... just a test.
The most important is the second.

This is the C# code to load the DLL and run the methods from the C# application. Is important to configure the Platform Target to x86 since the dll I've compiled is 32 bit.

Code: [Select]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace UsingDLL
{
    public partial class Form1 : Form
    {
        // 32 bit dll, the CPU must be set to 32 bit in the project settings
        [DllImport("csharpdllstring.dll")]
        private static extern void ShowDefaultMessage();
        [DllImport("csharpdllstring.dll")]
        private static extern void ShowStringMessage([MarshalAs(UnmanagedType.LPWStr)]string message);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ShowDefaultMessage(); // working
            ShowStringMessage("Test ñññ string"); // working
        }
    }
}

There are two ways of returning a string, both requires additional code, one in the dll side, other in the c# side.
https://stackoverflow.com/questions/16170360/returning-a-string-from-delphi-dll-to-c-sharp-caller-in-64-bit

Seems that the First approach is hard to write in the dll but is then easier to use in c#. The main problem seems that CoTaskMemAlloc is only available under windows?
Code: [Select]
function CoTaskMemAlloc(cb : ULONG) : PVOID; stdcall; external 'ole32.dll' name 'CoTaskMemAlloc';
procedure CoTaskMemFree(pv : PVOID); stdcall; external 'ole32.dll' name 'CoTaskMemFree';
« Last Edit: April 28, 2015, 06:46:12 am by 007 »

circular

  • Hero Member
  • *****
  • Posts: 4221
    • Personal webpage
Re: Calling DLL from C# - Passing WideString as parameter
« Reply #1 on: April 28, 2015, 07:12:50 am »
That's great.

I would suggest to add a helper function
Code: [Select]
function PWToUtf8(const str: PWideChar): string;
begin
  result := UTF8Encode(WideString(str));
end;
So that the function using the string would be:
Code: [Select]
procedure ShowStringMessage(const message: PWideChar); stdcall;
begin
  ShowMessage(PWToUtf8(message));
end;
Conscience is the debugger of the mind

lainz

  • Hero Member
  • *****
  • Posts: 4470
    • https://lainz.github.io/
Re: Calling DLL from C# - Passing WideString as parameter
« Reply #2 on: April 28, 2015, 07:56:27 am »
Quote
I would suggest to add a helper function

Yes is the way to go.

I've only tested in visual studio, in order to check if it will work in linux and mac a way is using xamarin studio.

For that is the question about using CoTaskMemAlloc (btw I think that there is no bgra funcion that returns a string?)...

Also if the bgrabitmap library will run in java, it must be tested too. Maybe Fred vS know the way of passing the string from java as PWideChar. If not possible, maybe we can define 2 different procedures with different parameters in order to get a single library working.

It will be useful when declaring SaveToFile / LoadFromFile stuff...
« Last Edit: April 28, 2015, 07:58:29 am by 007 »

 

TinyPortal © 2005-2018