Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从C#/NET中,针对Cygwin引用GCC中构建的GNUC(POSIX)DLL_C#_Dll_Gcc_Cygwin_Posix - Fatal编程技术网

从C#/NET中,针对Cygwin引用GCC中构建的GNUC(POSIX)DLL

从C#/NET中,针对Cygwin引用GCC中构建的GNUC(POSIX)DLL,c#,dll,gcc,cygwin,posix,C#,Dll,Gcc,Cygwin,Posix,这就是我想要的:我有一个为POSIX编写的巨大的遗留C/C++代码库,包括一些非常特定于POSIX的东西,比如pthreads。这可以在Cygwin/GCC上编译,并在带有Cygwin DLL的Windows下作为可执行文件运行 我想做的是将代码库本身构建到一个Windows DLL中,然后我可以从C#中引用它,并在它周围编写一个包装器,以编程方式访问它的某些部分。 我在上用非常简单的“hello world”示例尝试了这种方法,但它似乎不起作用 #include <stdio.h>

这就是我想要的:我有一个为POSIX编写的巨大的遗留C/C++代码库,包括一些非常特定于POSIX的东西,比如pthreads。这可以在Cygwin/GCC上编译,并在带有Cygwin DLL的Windows下作为可执行文件运行

我想做的是将代码库本身构建到一个Windows DLL中,然后我可以从C#中引用它,并在它周围编写一个包装器,以编程方式访问它的某些部分。

我在上用非常简单的“hello world”示例尝试了这种方法,但它似乎不起作用

#include <stdio.h>
extern "C" __declspec(dllexport) int hello();

int hello()
{
  printf ("Hello World!\n");
 return 42;
}
但这种方法似乎不起作用LoadLibrary返回空值。它可以找到DLL(helloworld.DLL),就像它无法加载它或找到导出的函数一样

我确信,如果这个基本案例能够正常工作,我可以用这种方式引用我的代码库的其余部分。有什么建议或建议,或者有人知道我想要的东西是否可能吗?谢谢

编辑:使用Dependency Walker(非常好的工具,谢谢)检查了我的DLL,它似乎正确地导出了函数。问:我是否应该引用它作为依赖项Walker似乎找到的函数名(Z5hellov)?

Edit2:仅向您展示我已经尝试过,直接链接到dll的相对或绝对路径(即不使用LoadLibrary):

这在以下情况下失败: “无法加载DLL'C:…\helloworld.DLL':对内存位置的访问无效。(HRESULT的异常:0x800703E6)

*****编辑3:***** Oleg建议在我的dll上运行dumpbin.exe,这是输出:

文件helloworld.dll的转储

00000000 characteristics
4BD5037F time date stamp Mon Apr 26 15:07:43 2010
    0.00 version
       1 ordinal base
       1 number of functions
       1 number of names

ordinal hint RVA      name

      1    0 000010F0 hello
文件类型:DLL

第节包含以下内容 helloworld.dll的导出

00000000 characteristics
4BD5037F time date stamp Mon Apr 26 15:07:43 2010
    0.00 version
       1 ordinal base
       1 number of functions
       1 number of names

ordinal hint RVA      name

      1    0 000010F0 hello
总结

    1000 .bss
    1000 .data
    1000 .debug_abbrev
    1000 .debug_info
    1000 .debug_line
    1000 .debug_pubnames
    1000 .edata
    1000 .eh_frame
    1000 .idata
    1000 .reloc
    1000 .text




编辑4谢谢大家的帮助,我设法让它工作起来。奥列格的回答给了我必要的信息,让我知道我做错了什么

有两种方法可以做到这一点。一种是使用gcc-mno cygwin编译器标志构建dll,该标志构建dll时不使用cygwin dll,基本上就像是在MingW中构建的一样。通过这种方式构建dll可以让我的hello world示例正常工作!但是,MingW在安装程序中没有cygwin拥有的所有库,因此如果您的POSIX code对这些库有依赖关系(我的库有堆),你不能这样做。如果你的POSIX代码没有这些依赖关系,为什么不从一开始就为Win32构建。所以这没有多大帮助,除非你想花时间正确设置MingW

另一个选项是使用Cygwin DLL构建。Cygwin DLL需要先调用初始化函数init(),然后才能使用。这就是我的代码以前无法工作的原因。下面的代码加载并运行我的hello world示例

    //[DllImport(@"hello.dll", EntryPoint = "#1",SetLastError = true)]
    //static extern int helloworld(); //don't do this! cygwin needs to be init first

    [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 MyFunction();

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

        IntPtr phello = LoadLibrary("hello.dll");
        IntPtr pfn = GetProcAddress(phello, "helloworld");
        MyFunction helloworld = (MyFunction)Marshal.GetDelegateForFunctionPointer(pfn, typeof(MyFunction));

        Console.WriteLine(helloworld());
        Console.ReadKey();
    }

感谢所有回答~~

的人,标准MS C编译器支持大多数POSIX接口,包括pthreads。 有时作为单独的实现,但通常作为将POSIX语法转换为windows库调用的宏


如果您的C代码没有太多的“Gnuism”,您应该能够使用标准的Visual C编译器编译它。

您应该能够引用针对Cygwin构建的DLL,而无需创建新的DLL。唯一的要求是您需要确保“Cygwin.DLL”和“Cygwin.DLL”都“并且您尝试加载的DLL位于适当的路径中。您可能需要在调用“LoadLibrary”之前使用它。

您应该首先尝试运行简单的hello world示例。如果您甚至没有正确使用前一个代码库,那么尝试使用基于Cygwin为POSIX编写的大型遗留C/C++代码库就没有多大意义。请注意,如果您在中链接Cygwin,则必须获得库的GPL许可

为此,请查看文档(例如,如果您正在使用Cdecl(您当前没有做的事情),则需要在hello world示例中明确指定):

在本机端,您必须初始化Cygwin(请参阅winsup/Cygwin/cygtls如何工作。txt)

使用p/Invoke直接调用您的库。PInvoking进入Win32库(如LoadLibrary)然后调用库是没有意义的。这只会为错误添加另一层,而不会给您带来任何好处

确保架构正确(.Net应用程序在64位计算机上默认运行64位)。因此,请确保您的DLL匹配/支持该功能,或者将.Net限制为32位


如果可行,试着让你的另一个库工作。(如果你希望使用两种完全不同的线程模型的函数),你就必须有一些运气。

< P>编写的代码将无法工作,导出的函数名由C++编译器修饰,不再类似于“hello”。您通常会声明函数extern“C”来抑制装饰

但是,你还没走那么远。LoadLibrary()调用失败,Windows错误998,错误为“无效访问内存位置”。最典型的情况是,如果某个DLL中的DllMain()入口点依赖于具有AccessViolation硬件异常的炸弹,则会发生这种情况。这应该在调试器(VisualStudio中的输出窗口)中可见,您应该会看到一个异常代码为0xc0000005的“首次机会异常”


这可能会让人不快,因为您有几个DLL是候选的,它们的调试符号可能与您使用的调试器不匹配。尝试用C编写一个调用LoadLibrary的小测试程序来隔离这种情况。将调试器配置为在第一次出现异常时停止。在VisualStudio中,您可以使用Debug+异常来执行此操作,并抛出复选框。祝你好运

您遇到的主要问题如下。在使用helloworld.dll之前,必须初始化cygwin环境(请参阅)。所以下面的公司
    //[DllImport(@"hello.dll", EntryPoint = "#1",SetLastError = true)]
    //static extern int helloworld(); //don't do this! cygwin needs to be init first

    [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 MyFunction();

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

        IntPtr phello = LoadLibrary("hello.dll");
        IntPtr pfn = GetProcAddress(phello, "helloworld");
        MyFunction helloworld = (MyFunction)Marshal.GetDelegateForFunctionPointer(pfn, typeof(MyFunction));

        Console.WriteLine(helloworld());
        Console.ReadKey();
    }
#include <windows.h>

typedef int (*PFN_HELLO)();
typedef void (*PFN_CYGWIN_DLL_INIT)();

int main()
{
    PFN_HELLO fnHello;
    HMODULE hLib, h = LoadLibrary(TEXT("cygwin1.dll")); 
    PFN_CYGWIN_DLL_INIT init = (PFN_CYGWIN_DLL_INIT) GetProcAddress(h,"cygwin_dll_init");
    init(); 

    hLib = LoadLibrary (TEXT("C:\\cygwin\\home\\Oleg\\mydll.dll"));
    fnHello = (PFN_HELLO) GetProcAddress (hLib, "hello");
    return fnHello();
}