3

I try to make a DLL out of a C/C++ Program that was written for Linux. I got it running in the Cygwin shell and made an interface for the DLL. I also used this to call the function but now the DLL hangs when it wants to allocate memory in a c file.

I broke the problem down to this simple program: The malloctest.cpp locks like this

#include <stdlib.h>
#include "test.h"
extern "C" __declspec(dllexport) int malloctest();

int malloctest(){
    int check = test();
    return check;
}

test.h

#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
int test();
#ifdef __cplusplus
}
#endif

test.c

#include "test.h"
int test(){
    int * array = malloc(42 * sizeof(int));
    free(array);
    return 42;
}

I compiled it like this in the Cygwin shell

gcc -c malloctest.cpp test.c
gcc -shared -o malloctest.dll malloctest.o test.o

and I called it in C# like this:

class Program
{

    [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
    static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

    [DllImport("kernel32", SetLastError = true)]
    static extern IntPtr LoadLibrary(string lpFileName);


    public delegate int test();
    static void Main(string[] args)
    {
        IntPtr pcygwin = LoadLibrary("cygwin1.dll");
        IntPtr pcyginit = GetProcAddress(pcygwin, "cygwin_dll_init");
        Action init = (Action)Marshal.GetDelegateForFunctionPointer(pcyginit, typeof(Action));
        init();

        IntPtr libptr = LoadLibrary("malloctest.dll");
        IntPtr funcptr = GetProcAddress(libptr, "malloctest");
        test malloctest = (test)Marshal.GetDelegateForFunctionPointer(funcptr, typeof(test));
        int check = malloctest(); //hold
        Console.WriteLine(check);
    }
}

Now it just hangs without an Error. It works if I use malloc in malloctest.cpp but as soon as I call a C file that uses malloc the dll just hangs.

Edit: this is my real interface.h

extern "C" {
  typedef struct det det_t;
  struct det{
     int id;
     int hamming;
     float goodness;
     float decision_margin;
     double c[2];
     double lu[2];
     double ld[2];
     double ru[2];
     double rd[2];
 };
  __declspec(dllexport) int scanJPGfromBUF(det_t * dets, uint8_t *, char *);
  __declspec(dllexport) int test ();
}
Haldoryn
  • 31
  • 5
  • use the mingw compiler or cross compiler not the cygwin one as you are writing a windows program and not a Unix one (cygwin is a unix) – matzeri Jul 16 '18 at 20:30
  • The Problem is that the C/C++ program uses POSIX. Last time I checked, mingw doesn't work with that. I could run it with cygwin thou. I thought it should work if I use the cygwin DLL like in this [Post](https://stackoverflow.com/questions/2710465/reference-a-gnu-c-posix-dll-built-in-gcc-against-cygwin-from-c-net?noredirect=1&lq=1). – Haldoryn Jul 16 '18 at 21:23
  • Have you tried run any Cygwin program from C# ? May be your problem is the missing PATH to `C:\cygwin\bin` to load the `cygwin1.dll` – matzeri Jul 17 '18 at 05:26
  • I have the cygwin1.dll in the same directory, as my exe. And yes the Hello World program from this [Post](https://stackoverflow.com/questions/2710465/reference-a-gnu-c-posix-dll-built-in-gcc-against-cygwin-from-c-net?noredirect=1&lq=1) works fine. – Haldoryn Jul 17 '18 at 13:10
  • try adding -O0 or -O3 to the gcc flags – LachoTomov Dec 10 '21 at 12:00

1 Answers1

1

Try changing the delegate to:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int test();

The default for .NET should be Stdcall, but the default in C is Cdecl.

I would translate the C struct to:

struct det
{
    int id;
    int hamming;
    float goodness;
    float decision_margin;
    double c1;
    double c2;
    double lu1;
    double lu2;
    double ld1;
    double ld2;
    double ru1;
    double ru2;
    double rd1;
    double rd2;
}

So I would remove all the arrays and transform them to multiple elements. The signature of the C method can be translated in multiple ways in C#.

Each parameter with a * could be a ref, a out or a [] (but not a ref [])... So it could be:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int scanJPGfromBUF(ref det_t dets, byte[] bytes1, byte[] chars1);
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • This worked on the example, but not on the real software I want to use. I just noticed that it also hangs if I use malloc in the C++ File on my real program. But I don't see a difference between the sample and the real one. – Haldoryn Jul 17 '18 at 14:25
  • sorry I made a mistake. This isn't working for the example. But I will keep it in my code. – Haldoryn Jul 17 '18 at 15:50
  • @Haldoryn Show the signature of the C method you want to call. – xanatos Jul 17 '18 at 16:04
  • [UnmanagedFunctionPointer(CallingConvention.Cdecl)] delegate int scanJPGfromBUF(out det[] det, Byte[] buffer, string famname); – Haldoryn Jul 17 '18 at 17:55
  • [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int test(); – Haldoryn Jul 17 '18 at 17:56
  • @Haldoryn No chance an `out byte[]` will work. Show me the C signature, not the C# signature – xanatos Jul 18 '18 at 05:13
  • I added my interface.h to the post – Haldoryn Jul 19 '18 at 22:03