这就是我想要的:我有一个为 POSIX 编写的巨大的遗留 C/C++ 代码库,包括一些非常 POSIX 特定的东西,比如 pthreads。这可以在 Cygwin/GCC 上编译并作为可执行文件在 Windows 下使用 Cygwin DLL 运行。
我想做的是将代码库本身构建到一个 Windows DLL 中,然后我可以从 C# 引用它并围绕它编写一个包装器以编程方式访问它的某些部分。
我在 http://www.cygwin.com/cygwin-ug-net/dll.html 上用非常简单的“hello world”示例尝试了这种方法。它似乎不起作用。
#include <stdio.h>
extern "C" __declspec(dllexport) int hello();
int hello()
{
printf ("Hello World!\n");
return 42;
}
我相信我应该能够在 C# 中引用使用上述代码构建的 DLL,方法如下:
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int hello();
static void Main(string[] args)
{
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "helloworld.dll");
IntPtr pDll = LoadLibrary(path);
IntPtr pAddressOfFunctionToCall = GetProcAddress(pDll, "hello");
hello hello = (hello)Marshal.GetDelegateForFunctionPointer(
pAddressOfFunctionToCall,
typeof(hello));
int theResult = hello();
Console.WriteLine(theResult.ToString());
bool result = FreeLibrary(pDll);
Console.ReadKey();
}
但是这个方法好像行不通。 LoadLibrary 返回 null。它可以找到DLL(helloworld.dll),就像它无法加载它或找不到导出的函数一样。
我确信,如果我让这个基本案例正常工作,我可以通过这种方式引用我的代码库的其余部分。任何建议或指示,或者有人知道我想要的东西是否可能吗?谢谢。
编辑: 使用 Dependency Walker(很棒的工具,谢谢)检查了我的 DLL,它似乎正确地导出了函数。问题:我应该引用它作为 Dependency Walker 似乎找到的函数名称 (_Z5hellov) 吗?
Edit2:只是为了向您展示我已经尝试过,直接链接到相对或绝对路径的 dll(即不使用 LoadLibrary):
[DllImport(@"C:\.....\helloworld.dll")]
public static extern int hello();
static void Main(string[] args)
{
int theResult = hello();
Console.WriteLine(theResult.ToString());
Console.ReadKey();
}
这失败了: “无法加载 DLL 'C:.....\helloworld.dll':对内存位置的访问无效。(HRESULT 异常:0x800703E6)
*****编辑 3:***** Oleg 建议在我的 dll 上运行 dumpbin.exe,这是输出:
Dump of file helloworld.dll
File Type: DLL
Section contains the following exports for 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 helloSummary
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 感谢大家的帮助,我设法让它工作了。 Oleg 的回答为我提供了找出我做错了什么所需的信息。
有 2 种方法可以做到这一点。一种是使用 gcc -mno-cygwin 编译器标志构建,它构建没有 cygwin dll 的 dll,基本上就像您在 MingW 中构建它一样.以这种方式构建它让我的 hello world 示例开始工作!但是,MingW 没有安装程序中 cygwin 的所有库,因此如果您的 POSIX 代码依赖于这些库(我的库有堆),您不能这样做。如果您的 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();
}
感谢大家的回答~~
最佳答案
您遇到的主要问题如下。在您可以使用您的 helloworld.dll 之前,必须初始化一个 cygwin 环境(参见 http://cygwin.com/faq/faq.programming.html#faq.programming.msvs-mingw)。因此, native C++ 中的以下代码将起作用:
#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();
}
当然必须找到 cygwin1.dll 的路径。您可以将 C:\cygwin\bin 设置为当前目录,使用 SetDllDirectory 函数或简单地将 C:\cygwin\bin 包含在全局 PATH 环境变量中(在计算机上单击鼠标右键,选择属性然后“高级系统设置”,“环境变量...”,然后选择系统变量 PATH 并附加“;C:\cygwin\bin”)。
接下来如果你编译你的 DLL,你最好使用 DEF 文件在编译过程中定义 DLL 的 BASE 地址,并使你导出的所有函数名称更清晰可读(参见 http://www.redhat.com/docs/manuals/enterprise/RHEL-4-Manual/gnu-linker/win32.html)
如果您安装了 Visual Studio,您可以使用 dumpbin.exe mydll.dll/exports 验证结果。 (不要忘记从“Visual Studio 命令提示符(2010)”启动命令提示符以设置所有 Visual Studio)。
更新:因为你没有写成功,我认为存在一些问题。在 Win32/Win64 世界(非托管世界)中它有效。我发布的代码已经过测试。在 .NET 中加载 CygWin DLL 可能会出现一些问题。在 http://cygwin.com/faq/faq.programming.html#faq.programming.msvs-mingw可以阅读“确保堆栈底部有 4K 的暂存空间”。此要求在 .NET 中可能是错误的。堆栈是线程的一部分,而不是进程。因此,您可以尝试在新的 .NET 线程中使用 CygWin DLL。从 .NET 2.0 开始,可以为线程定义最大堆栈大小。另一种方法是尝试理解 http://cygwin.com/cgi-bin/cvsweb.cgi/~checkout~/src/winsup/cygwin/how-cygtls-works.txt?rev=1.1&content-type=text/plain&cvsroot=src和 http://old.nabble.com/Cygwin-dll-from-C--Application-td18616035.html#a18616996 中描述的代码.但真正有趣的是我找到了两种没有任何技巧的方法:
附言如果您在最后选择的其中一种或另一种方式中取得成功,请在您的问题文本中写下简短的内容。独立于声誉和赏金对我来说很有趣。
关于c# - 从 C#/NET 引用针对 Cygwin 在 GCC 中构建的 GNU C (POSIX) DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2710465/
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里