2

Getting an error:

enter image description here

C:

#include <stdio.h>

const char *print(const char *message)
{
    if (message != 0) {
        const char *message1 = "Connected";
        return message1;
        message = "";
    }
    return "Message empty";
}

C#:

     public partial class Form1 : Form
     {
         /*Declaration*/
         bool T;
         string a;
         
         [DllImport("DLLC.dll")]
         static extern string print(string message);
 
         public Form1()
         {
             InitializeComponent();
         }
                 
         private void button1_Click(object sender, EventArgs e)
         {
             a = print("Send");
             if (T)
             {
                 label1.Text = a ;
                 T=false;
             }
             else{
                 label1.Text = "BAD";
                 T=true;
             }
             
         }
     }

The idea is learn how to use functions from c in c#.

Also I would like use open62541 library for OPC UA SERVER and make UI with windows forms.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
Klasik
  • 872
  • 1
  • 9
  • 29
  • You need to export the `print` function (`__declspec(dllimport)`). Also be careful about your calling convention. – canton7 Mar 14 '19 at 13:53
  • Also, since `message` can be changed, although you never actually do that, you'll need to pass it in as `ref` from the C# side. – canton7 Mar 14 '19 at 13:54
  • Can you explain more about what are you mean? because I'm really new to that... – Klasik Mar 14 '19 at 13:59
  • 1
    The code will not work as is. In c a string is byte array terminated with a '\0'. In c# a string is a two byte object. So you have to convert like this : Encoding.UTF8.GetBytes("Send\0") You also need to change definition : static extern byte[] print(byte[] message); – jdweng Mar 14 '19 at 14:02
  • @jdweng marshaling will take care of this ... – Selvin Mar 14 '19 at 14:03
  • This is bad, bad code ... you should not return pointer to local variable outside the function (ok now it's literal so there should be no problem, but with "real" variable.. ) ... [this question was similar - check my answer](https://stackoverflow.com/questions/53198213/calling-c-function-with-lpstr-return-value-from-c-sharp/53201035#53201035) – Selvin Mar 14 '19 at 14:04
  • @jdweng the marshaller should do that – canton7 Mar 14 '19 at 14:05
  • okay after exporting getting different error after a = print("Send"); Program just stops working with error message Form1 program has stopped working. – Klasik Mar 14 '19 at 14:06
  • @jdweng maybe you can write how its should look like? – Klasik Mar 14 '19 at 14:20
  • There is no marshaling so it is needed. – jdweng Mar 14 '19 at 15:03
  • @jdweng of course there is - the runtime does the marshaling as part of the p/invoke – canton7 Mar 14 '19 at 15:40
  • @canton7 so show send string to dll do something with it and get it back? – Klasik Mar 14 '19 at 15:49
  • No it doesn't without some instructions. – jdweng Mar 14 '19 at 16:00
  • @jdweng I can promise you that string marshaling to a `char*` works. See e.g. https://learn.microsoft.com/en-us/dotnet/framework/interop/default-marshaling-for-strings – canton7 Mar 14 '19 at 16:10
  • @jdweng calm down, please. You said that you can't pass a `string` into a p/invoked method, and need to instead to it into a byte array. I'm telling you that that is incorrect, because it is. That is all. – canton7 Mar 14 '19 at 16:17
  • @jdweng is indeed wrong here. Default marshaling is used. Note however that default marshaling for a string return type assumes that the null terminated buffer was allocated on the COM heap and the marshaler will destroy it by calling CoTaskMemFree. – David Heffernan Mar 19 '19 at 07:12
  • Where does it say on following page that a string get cast to a byte[]? https://learn.microsoft.com/en-us/dotnet/framework/interop/default-marshaling-behavior – jdweng Mar 19 '19 at 09:05

1 Answers1

4

You need to mark the function in the DLL as exported. There are two ways of doing this. You may either create a .def file and name the exported functions, or add the specifier __declspec(dllexport) to the function signature.

To create a .def file, in Visual Studio with the C DLL project open, right click on "Source Files" and then under "Visual C++" -> "Code", select "Module-Definition File (.def)". In the newly created .def file, you can list the functions you wish to export, like so:

LIBRARY mydll
EXPORTS
    function1
    function2
    function3

Then, when you build the DLL, function1, function2, and function3 are available.

Also, keep in mind that unless you manually specify a calling convention (e.g. int __stdcall function1(int a, int b);), the calling convention is __cdecl by default, and so when you add the line to import the function through P/Invoke, you must also have the attribute CallingConvention = CallingConvention.CDecl. Failing to match calling conventions will cause stack corruption in the calling code.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85