这里的情况是,我用我的dot.net申请一个基于C的DLL。 有2个DLL文件,一个是32位叫MyDll32.dll,另一个是名为MyDll64.dll 64位版本。
有一个静态变量持有的DLL文件名:字符串DLL_FILE_NAME。
并且在使用方式如下:
[DllImport(DLL_FILE_NAME, CallingConvention=CallingConvention.Cdecl, EntryPoint=Func1")]
private static extern int is_Func1(int var1, int var2);
简单为止。
你可以想像,软件编译打开“任何CPU”。
我也有下面的代码,以确定系统应使用64位文件或32位文件。
#if WIN64
public const string DLL_FILE_NAME = "MyDll64.dll";
#else
public const string DLL_FILE_NAME = "MyDll32.dll";
#endif
现在,你应该看到这个问题.. DLL_FILE_NAME在编译时间定义,而不是在执行时间,以便正确的dll是根据执行上下文不加载。
什么是解决这个问题的正确方法是什么? 我不想要两个可执行文件(一个用于32位,另一个用于64位)? 如何设置DLL_FILE_NAME它在的DllImport语句中使用过吗?
Answer 1:
我发现这样做最简单的方法是将两种方法具有不同名称导入,并调用正确的。 该DLL将不会被加载,直到呼叫被制成所以它的罚款:
[DllImport("MyDll32.dll", EntryPoint = "Func1", CallingConvention = CallingConvention.Cdecl)]
private static extern int Func1_32(int var1, int var2);
[DllImport("MyDll64.dll", EntryPoint = "Func1", CallingConvention = CallingConvention.Cdecl)]
private static extern int Func1_64(int var1, int var2);
public static int Func1(int var1, int var2) {
return IntPtr.Size == 8 /* 64bit */ ? Func1_64(var1, var2) : Func1_32(var1, var2);
}
当然,如果你有很多的进口,这可以成为相当繁琐手工维护。
Answer 2:
下面是要求两个DLL具有相同的名称和被放在不同的文件夹中另一种选择。 例如:
-
win32/MyDll.dll
-
win64/MyDll.dll
关键是要手动加载DLL LoadLibrary
的CLR不前。 然后,它会看到一个MyDll.dll
已加载并使用它。
这可以很容易地在父类的静态构造函数来完成。
static class MyDll
{
static MyDll()
{
var myPath = new Uri(typeof(MyDll).Assembly.CodeBase).LocalPath;
var myFolder = Path.GetDirectoryName(myPath);
var is64 = IntPtr.Size == 8;
var subfolder = is64 ? "\\win64\\" : "\\win32\\";
LoadLibrary(myFolder + subfolder + "MyDll.dll");
}
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("MyDll.dll")]
public static extern int MyFunction(int var1, int var2);
}
编辑2017年2月1日 :使用Assembly.CodeBase
使其作品即使阴影复制启用。
Answer 3:
在这种情况下,我应该做这样的(做2个文件夹,x64和x86 +把相应的DLL,具有相同的名称,在这两个文件夹):
using System;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
class Program {
static void Main(string[] args) {
var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
path = Path.Combine(path, IntPtr.Size == 8 ? "x64" : "x86");
bool ok = SetDllDirectory(path);
if (!ok) throw new System.ComponentModel.Win32Exception();
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
}
Answer 4:
有一个静态变量持有的DLL文件名
它不是一个静态变量。 这是一个常数,在编译时。 你不能改变一个编译时在运行时不变。
什么是解决这个问题的正确方法是什么?
老实说,我会建议只是针对x86和遗忘的64位版本都在一起,并让在WOW64应用程序运行,除非你的应用程序有一个迫切需要为64位运行。
如果有需要的X64,您可以:
Answer 5:
什么你描述被称为“并排侧组装件”(同一程序集的两个版本,一个32和其他64位)......我想你会发现这些有用的:
- 使用侧面并排组件加载DLL的64或32倍的版本
- http://blogs.msdn.com/b/gauravseth/archive/2006/03/07/545104.aspx
- http://www.thescarms.com/dotnet/Assembly.aspx
在这里你可以找到你的确切方案(.NET DLL环绕C ++ / CLI DLL引用本地DLL)的演练。
建议:
只是打造为x86和用它做......或有2个建立(一个x86和一个64位)......作为上述技术相当复杂...
Answer 6:
一种替代方法可以是
public static class Sample
{
public Sample()
{
string StartupDirEndingWithSlash = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) + "\\";
string ResolvedDomainTimeFileName = StartupDirEndingWithSlash + "ABCLib_Resolved.dll";
if (!File.Exists(ResolvedDomainTimeFileName))
{
if (Environment.Is64BitProcess)
{
if (File.Exists(StartupDirEndingWithSlash + "ABCLib_64.dll"))
File.Copy(StartupDirEndingWithSlash + "ABCLib_64.dll", ResolvedDomainTimeFileName);
}
else
{
if (File.Exists(StartupDirEndingWithSlash + "ABCLib_32.dll"))
File.Copy(StartupDirEndingWithSlash + "ABCLib_32.dll", ResolvedDomainTimeFileName);
}
}
}
[DllImport("ABCLib__Resolved.dll")]
private static extern bool SomeFunctionName(ref int FT);
}
Answer 7:
我已经使用vcsjones meantioned的方法之一:
“更改DLL文件具有相同的名称,如将myDll.dll,并在安装/部署时间,落实到位是正确的。”
这种方式需要维护两个构建平台,虽然看到此链接了解详情: https://stackoverflow.com/a/6446638/38368
Answer 8:
我使用的窍门V8.Net是这样的:
- 创建所有的定义了不同的体系结构之间切换一个新的C#“代理接口”项目。 在我的情况下,项目被命名为
V8.Net-ProxyInterface
; 例:
public unsafe static class V8NetProxy
{
#if x86
[DllImport("V8_Net_Proxy_x86")]
#elif x64
[DllImport("V8_Net_Proxy_x64")]
#else
[DllImport("V8_Net_Proxy")] // (dummy - NOT USED!)
#endif
public static extern NativeV8EngineProxy* CreateV8EngineProxy(bool enableDebugging, void* debugMessageDispatcher, int debugPort);
这是你将引用该项目。 不引用下两个:
创建两个项目生成库的x64和x86版本。 这是很容易:只要复制正粘贴复制.csproj
在同一个文件夹中的文件和他们改名。 在我的情况下,项目文件更名为V8.Net-ProxyInterface-x64
和V8.Net-ProxyInterface-x86
,然后我添加项目到我的解决方案。 在Visual Studio中打开为他们每个人的项目设置,确保Assembly Name
在名称中包含任何的x64或x86。 在这一点上,你有3个项目:第一个“占位符”项目,并在2特定架构的。 对于2个新项目:
a)打开64接口项目设置,转到Build
选项卡,选择All Platforms
对Platform
顶部,然后输入x64
在Conditional compilation symbols
。
B)打开了x86接口项目设置,转到Build
选项卡,选择All Platforms
对Platform
顶部,然后输入x86
在Conditional compilation symbols
。
打开Build->Configuration Manager...
,并确保x64
被选中作为平台,x64的项目, x86
选择为x86项目,对于这两种Debug
和Release
配置。
确保2个新的界面项目(用于x64和x86)输出到主机项目的同一位置(见项目设置Build->Output path
)。
最终魔术:在我的引擎静态构造函数我迅速连接到集解析器:
static V8Engine()
{
AppDomain.CurrentDomain.AssemblyResolve += Resolver;
}
在Resolver
的方法,我只是加载基于当前进程表示当前平台上的文件(注意:此代码是一个精简版和未测试):
var currentExecPath = Assembly.GetExecutingAssembly().Location;
var platform = Environment.Is64BitProcess ? "x64" : "x86";
var filename = "V8.Net.Proxy.Interface." + platform + ".dll"
return Assembly.LoadFrom(Path.Combine(currentExecPath , fileName));
最后,进入到你的主机项目在解决方案资源管理器中,展开References
,选择在步骤1中创建的第一虚设项目,右键单击它,打开属性,设置Copy Local
到false
。 这可以让你用一个名字来为每一个P /调用功能,同时采用了旋找出哪一个实际加载。
请注意,必要时组装装载机只运行。 它仅是通过在第一次接触到发动机类CLR系统触发(对我来说)自动。 那如何转化为你要看你的主机项目是如何设计的。
文章来源: Using a 32bit or 64bit dll in C# DllImport