虽然目前32位操作系统的用户已经很少了,但若是你的程序需要兼容x86系统,可以参考一下本文。

首先,.NET 的类库是可以同时兼容x86和x64系统的(编译选项中设置目标CPU为AnyCPU),只要你的类库不包含任何本地代码(C、C++等)、或者针对特定系统的代码。

如果你的程序调用了第三方的类库,并且只能提供 x86\x64 两个版本的话,就需要在执行时设置类库文件的位置。

指定 .NET 类库位置

.NET 中动态加载类库,只需要设置程序域的 PrivatePath 即可。
在程序的初始化函数中(如Main、New、Loading等)调用 AppDomain.AppendPrivatePath,动态添加 PrivatePath 位置。
' 根据指针的长度,来判断当前程序所运行的环境
Dim isX86 = (IntPtr.Size = 4)
Dim isX64 = (IntPtr.Size = 8)

' 根据系统位数,指定类库私有路径的位置,可使用分号进行分隔
Dim privatePath = If(isX86, "x86\bin\;x86\ph\", "x64\bin\;x64\ph\")
AppDomain.CurrentDomain.AppendPrivatePath(privatePath)
var isX86 = IntPtr.Size == 4;
var isX64 = IntPtr.Size == 8;

var privatePath = isX86 ? @"x86\bin\;x86\ph\" : @"x64\bin\;x64\ph\";
AppDomain.CurrentDomain.AppendPrivatePath(privatePath);
我们先根据系统指针的长度来判断程序所处于的运行环境,指针为4表示为x86环境,指针为8表示为x64环境。
之后根据系统版本设置不同的 PrivatePath,只需要设置相对目录即可。如果包含多个路径,可以使用分号来分隔。

指定 Windows 类库位置

如果你调用了C、C++的类库文件,则需要在运行时指定不同的版本,因为它们在编译时就已经指定了操作系统的版本。
调用不同版本的Win类库,需要使用 Windows API 的 SetDllDirectory,用于指定额外的DLL文件加载路径。
Private Declare Auto Function SetDllDirectory Lib "Kernel32.dll" (ByVal lpPathName As String) As Boolean

Dim isX86 = (IntPtr.Size = 4)

' 指定 Win DLL 文件位置
Dim dllPath As String = IO.Path.Combine(Application.StartupPath, If(isX86, "x86\dll\", "x64\dll\"))
SetDllDirectory(dllPath)
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
private static extern bool SetDllDirectory(string lpPathName);

var isX86 = IntPtr.Size == 4;

var dllPath = System.IO.Path.Combine(Application.StartupPath, isX86 ? @"x86\dll\" : @"x64\dll\");
SetDllDirectory(dllPath);
一定要尽早调用 SetDllDirectory,否则有可能无法正确加载WinDLL,类库的路径需要完整路径。
另外,如果你在 SetDllDirectory 之前就已经调用了一个有效的WinAPI,当你重新设置DLL文件夹之后,并不会让程序自动加载新目录下的DLL,因为Windows的DLL加载具有缓存机制,已加载的DLL会被缓存到缓冲区,只有释放过DLL文件,才会重新加载DLL。

另外,还可以通过 AddDllDirectory API实现添加更多DLL目录的功能,但是此API只支持 Windows 8 以上的系统,并且调用前还需要先调用 SetDefaultDllDirectories,使用起来不是很方便。如果不需要支持多目录的功能,不推荐使用。

还是来个示例吧:
Declare Function SetDefaultDllDirectories Lib "Kernel32" (ByVal dirFlags As Integer) As Boolean
' 注意:AddDllDirectory只支持Unicode编码,若未设置正确,则永远返回错误
Declare Unicode Function AddDllDirectory Lib "Kernel32" (ByVal NewDirectory As String) As IntPtr
Declare Function RemoveDllDirectory Lib "Kernel32" (ByVal dircookie As IntPtr) As Boolean

' 需要预先调用 SetDefaultDllDirectories
SetDefaultDllDirectories(&H1000) '使用全部搜索位置

' 添加一个路径,参数需要完整路径,返回值为一个指针,如果为0表示失败
Dim dirCookie = AddDllDirectory(IO.Path.Combine(Application.StartupPath, "newdir\"))

' 删除添加的路径,需要使用一个有效的指针
RemoveDllDirectory(dirCookie)

完整示例

此示例的 .NET DLL 放到 x86\bin\x64\bin\ 文件夹中,Win DLL 放到 x86\dll\x64\dll\ 文件夹中。
Private Declare Auto Function SetDllDirectory Lib "Kernel32" (ByVal lpPathName As String) As Boolean

' 根据指针长度,来判断当前程序所运行的环境
Dim isX86 = (IntPtr.Size = 4)
Dim isX64 = (IntPtr.Size = 8)

' 根据系统位数,指定类库私有路径的位置,可使用分号进行分隔
Dim privatePath As String = If(isX86, "x86\bin\", "x64\bin\")
AppDomain.CurrentDomain.AppendPrivatePath(privatePath)

' 指定 Win DLL 文件位置
Dim dllPath As String = IO.Path.Combine(Application.StartupPath, If(isX86, "x86\dll\", "x64\dll\"))
SetDllDirectory(dllPath)
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
private static extern bool SetDllDirectory(string lpPathName);

var isX86 = IntPtr.Size == 4;
var isX64 = IntPtr.Size == 8;

var privatePath = isX86 ? @"x86\bin\" : @"x64\bin\";
AppDomain.CurrentDomain.AppendPrivatePath(privatePath);

var dllPath = System.IO.Path.Combine(Application.StartupPath, isX86 ? @"x86\dll\" : @"x64\dll\");
SetDllDirectory(dllPath);