32ビット版と64ビット版の管理対象アプリケーションを同じマシン上で実行する必要があり、同じ名前の両方のビット数のアンマネージDLLに依存する(つまり、 ICU 4.2)。WOW64プログラムファイルのリダイレクトが機能しない
だから、私は重い物を持ち上げる行うにはWOW64ファイルシステムのリダイレクトに頼って、そのマッチングプログラムファイルにICUの両方のバージョンを置くことにしました:C:\Program Files (x86)\ICUBins
にC:\Program Files\ICUBins
における64ビット版と32ビット版を、前者は変数PATH
に追加されました。
...それ以外は動作しません。どちらのバージョンのプログラムでも、アンマネージDLLの64ビット版を使用すると、C:\Program Files\ICUBins
を32ビットプロセスで使用しようとする試みがC:\Program Files (x86)\ICUBins
にリダイレクトされない理由を理解できません。
編集追加する:
をここでは、問題を再現し(ただしラッパーコードので代わりにDLLをロードする、それは単にそのbit化をチェックし、巨大であった)最小のコード例です。それは最初に.NET 2.0のために作成されたので、それはWOW64をチェックするために廃止された機能を使用していること 注:私はこのプログラムの32ビットバージョンを実行
using System;
namespace SearchICU
{
/// <summary>
/// Methods for getting the version and date of the assembly that calls them.
/// </summary>
public static class BitnessHelper
{
public enum Machine : short
{
x86=0x14C,
Alpha=0x184,
ARM=0x1C0,
MIPS16R3000=0x162,
MIPS16R4000=0x166,
MIPS16R10000=0x168,
PowerPCLE=0x1F0,
PowerPCBE=0x1F2,
Itanium=0x200,
MIPS16=0x266,
Alpha64=0x284,
MIPSFPU=0x366,
MIPSFPU16=0x466,
x64=unchecked((short)0x8664),
}
public static Machine RetrieveMachine(string filePath)
{
if(string.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath"); }
const int c_PeHeaderOffsetOffset = 60; //Within whole file/IMAGE_DOS_HEADER structure. Equal to 0x003C
const int c_MachineOffset = 4; //Within IMAGE_NT_HEADERS
//Just read "enough" of the file: In modern PE files, the IMAGE_NT_HEADERS structure should never start past 2KiB anyway.
byte[] b = new byte[2048];
System.IO.Stream s = null;
try
{
s = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
s.Read(b, 0, 2048);
}
finally
{
if(s != null)
{
s.Close();
}
}
//First check the MZ header (IMAGE_DOS_HEADER)'s magic.
short mzMagic = ReadInt16LE(b, 0);
if(mzMagic != 0x5A4D) //"MZ" in little-endian
throw new BadImageFormatException("File does not start with MZ header.");
//Get its "next header offset" value and check the PE header (IMAGE_NT_HEADERS)'s magic.
int peHeaderOffset = ReadInt32LE(b, c_PeHeaderOffsetOffset);
int peMagic = ReadInt32LE(b, peHeaderOffset);
if(peMagic != 0x00004550) //"PE\0\0" in little-endian
throw new BadImageFormatException("Header pointed by MZ header is not PE.");
//Read the machine from the PE header (IMAGE_NT_HEADERS).
//We're still in the bitness-agnostic part (the IMAGE_FILE_HEADER structure).
short machine = ReadInt16LE(b, peHeaderOffset + c_MachineOffset);
return (Machine)machine;
}
/// <summary>Reads a 16-bit integer as little-endian from a byte array.</summary>
/// <remarks>Because BitConverter depends on the platform's endianness, and here I need an "always little-endian" code.
/// Made public because some other code has a need for this.</remarks>
public static short ReadInt16LE(byte[] bytes, int offset)
{
if(bytes==null) { throw new ArgumentNullException("bytes"); }
ushort ret = 0;
for(int i=1 ; i>=0 ; i--) { ret <<= 8; ret |= bytes[offset+i]; }
return unchecked((short)ret);
}
/// <summary>Reads a 32-bit integer as little-endian from a byte array.</summary>
/// <remarks>Because BitConverter depends on the platform's endianness, and here I need an "always little-endian" code.
/// Made public because some other code has a need for this.</remarks>
public static int ReadInt32LE(byte[] bytes, int offset)
{
if(bytes==null) { throw new ArgumentNullException("bytes"); }
uint ret = 0;
for(int i=3 ; i>=0 ; i--) { ret <<= 8; ret |= bytes[offset+i]; }
return unchecked((int)ret);
}
#region Win64/WOW64 methods
/// <summary>
/// Win32 function <c>IsWow64Process</c>: Determines whether the specified process is running under WOW64.
/// </summary>
/// <param name="hProcess">[in] Process handle with enough access rights.</param>
/// <param name="Wow64Process">[out] set to <c>true</c> if running under WOW64, <c>false</c> for Win32 and Win64.</param>
/// <returns><c>true</c> if succeeded.</returns>
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError=true)]
extern static bool IsWow64Process(IntPtr hProcess, ref bool Wow64Process);
/// <summary>
/// Wrapper for <c>IsWow64Process</c>, so the calling function may throw <c>SecurityException</c> when calling it
/// rather than be completely prevented from running by <c>LinkDemand</c>.
/// </summary>
static bool CallIsWow64Process(IntPtr hProcess, ref bool Wow64Process)
{
//P/Invoke has a LinkDemand for full trust, so this function won't even start
//if partially trusted.
return IsWow64Process(hProcess, ref Wow64Process);
}
/// <summary>
/// Wrapper for <c>Process.GetCurrentProcess</c>, so the calling function may throw <c>SecurityException</c> when calling it
/// rather than be completely prevented from running by <c>LinkDemand</c>.
/// </summary>
static IntPtr GetProcessHandle()
{
//GetCurrentProcess() has a LinkDemand for full trust, so this function won't even start
//if partially trusted.
return System.Diagnostics.Process.GetCurrentProcess().Handle;
}
/// <summary>
/// Wrapper for <c>Marshal.GetLastWin32Error</c>, so the calling function may throw <c>SecurityException</c> when calling it
/// rather than be completely prevented from running by <c>LinkDemand</c>.
/// </summary>
static int CallGetLastWin32Error()
{
//GetLastWin32Error() has a LinkDemand for UnmanagedCode, so this function won't even start
//if partially trusted.
return System.Runtime.InteropServices.Marshal.GetLastWin32Error();
}
/// <summary>
/// Test whether the current process is running under Win32, Win64 or WOW64.
/// </summary>
/// <param name="message">[out] Human-readable message describing the situation.</param>
/// <returns><c>true</c> if succeeded, <c>false</c> if couldn't determine (security or IsWow64Process failure).</returns>
/// <exception cref="Exception">For any other error with the P/Invoke call.</exception>
public static bool TestWow64(out string message)
{
//Note on exceptions: Apparently, on a full .Net Framework P/Invoke can throw EntryPointNotFoundException,
//ExecutionEngineException (if incorrectly declared) or DllNotFoundException.
//(the former two replaced with MissingMethodException and NotSupportedException on the Compact Framework).
//Since we're hitting Kernel32.dll, using the correct declaration, and not planning for an embedded version,
//only EntryPointNotFoundException will be handled here.
try
{
bool isWow64 = false;
//Call wrapper functions to avoid security exceptions being thrown before the try block.
if(CallIsWow64Process(GetProcessHandle(), ref isWow64))
{
if(isWow64)
message = "Running as a 32-bit process on a Win64 machine.";
else if(IntPtr.Size==4)
message = "Running on Win32.";
else if(IntPtr.Size==8)
message = "Running on Win64.";
else
message = string.Format("Something weird: Not WOW64, but pointer size is {0}.", IntPtr.Size);
return true;
}
else
{
message = string.Format("IsWow64Process was correctly called, but failed with error {0}", CallGetLastWin32Error());
return false;
}
}
catch(EntryPointNotFoundException)
{
message = "Running on Win32, WOW64 not supported.";
return true;
}
catch(System.Security.SecurityException)
{
message = "Running in a sandbox, process information inaccessible.";
return false;
}
//catch(Exception e)
//{
// log.Warn("IsWow64Process call failed:", e); //test
//}
}
/// <summary>
/// Wrapper method for determining whether the current process is 64-bit.
/// Useful for determining which version of a library to load.
/// </summary>
public static bool IsWin64
{
get { return IntPtr.Size==8; } //In V10, use Environment.Is64BitProcess
}
#endregion
}
}
using System;
using System.IO;
namespace SearchICU
{
class Program
{
static void Main(string[] args)
{
string bitness;
if(BitnessHelper.TestWow64(out bitness)) { Console.WriteLine(bitness); }
string icuDir = FindDirInPath(new string[] { "icudt42.dll", "icuuc42.dll", "icuin42.dll" });
if(icuDir==null)
{
Console.WriteLine("ICU DLLs not found in PATH.");
return;
}
Console.WriteLine("ICU DLLs found in PATH:{1}\t{0}", icuDir, Environment.NewLine);
string dllPath = Path.Combine(icuDir, "icuin42.dll");
BitnessHelper.Machine machine = BitnessHelper.RetrieveMachine(dllPath);
switch(machine)
{
case BitnessHelper.Machine.x86:
Console.WriteLine("DLL in path is 32-bit DLL.");
break;
case BitnessHelper.Machine.x64:
Console.WriteLine("DLL in path is 64-bit DLL.");
break;
default:
Console.WriteLine("DLL in path is unknown (machine={0}).", machine);
break;
}
}
public static string FindDirInPath(string[] filesToFind)
{
if(filesToFind==null || filesToFind.Length==0)
throw new ArgumentException("filesToFind must be a non-empty array of file names.", "filesToFind");
string pathEnvVariable = Environment.GetEnvironmentVariable("PATH");
if(!string.IsNullOrEmpty(pathEnvVariable))
{
foreach(string pathDirectory in pathEnvVariable.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
{
bool allFound = true;
foreach(string fileName in filesToFind)
{
string filePath = Path.Combine(pathDirectory, fileName);
if(!File.Exists(filePath))
{
allFound = false;
break;
}
}
if(allFound)
return pathDirectory;
}
}
return null;
}
}
}
、出力はこうです:
Running as a 32-bit process on a Win64 machine.
ICU DLLs found in PATH:
C:\Program Files\ICUBins
DLL in path is 64-bit DLL.
これは私が何を言うことができる...です。私は、どこかに隠されたWow64DisableWow64FsRedirection()が大声で叫ぶだけです。これをしないでください。PATHはすでにそれほど醜いので、必要なDLLをクライアントアプリケーションと同じディレクトリに展開してください。 –