尝试写入内存映射文件时出现问题,在两个进程之间共享(32 位 -> 64 位)
Issue when trying to write to memory mapped file, shared between two processes (32 bit -> 64 bit)
作为临时解决方案,我正在实现一种通过 32 位 DLL 将一些数据获取到 64 位应用程序的方法。
我尽量保持简单,不需要高性能或最漂亮的解决方案。这个想法是不要在花哨的握手等上浪费太多时间
为此,我的 64 位应用程序加载了一个我自己制作的 64 位 DLL(它具有与 32 位 DLL 相同的导出函数)。因此,在主应用程序中,没有任何变化。
64 位 DLL 通过在命令行上传递内存映射文件的名称和一些其他输入数据来创建内存映射文件并启动 32 位帮助程序。
辅助可执行文件加载 32 位 DLL,调用 DLL 函数,将数据复制到共享内存映射文件中,退出,然后......Bob 是你的叔叔。
也就是说 .. Bob 今天过得很糟糕,它不起作用。 WriteFile()
到内存映射文件失败并出现 Windows API 错误 6 (ERROR_INVALID_HANDLE
),如 GetLastError()
.
所报告
除了写入内存映射文件外一切正常(读取也可能失败,但还没有成功)。
我确信问题出在我创建内存映射文件的方式上,我在这里完全无法理解,所以我很感激一双新的眼睛。
64位DLL中的相关代码:
char MemoryFileName[] = "unique_name_with_extra_random_chars";
HANDLE MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_EXECUTE_READWRITE, 0, (256 * 1024), MemoryFileName) ;
if (MemoryFile)
{
void *View = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0) ;
char Exe[] = "Hlpr.exe" ;
char Cmd[2048] = "Hlpr.exe " ;
strcat(Cmd, "\"") ;
strcat(Cmd, MemoryFileName) ;
strcat(Cmd, "\" \"") ;
strcat(Cmd, "262144") ; // (256 * 1024)
strcat(Cmd, "\" \"") ;
strcat(Cmd, file_name_path_of_data_the_dll_needs_to_parse) ;
strcat(Cmd, "\"") ;
STARTUPINFO StartupInfo = {sizeof StartupInfo} ; // Init
PROCESS_INFORMATION ProcessInfo ;
if (CreateProcess(Exe, Cmd, NULL, NULL, false, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE) == WAIT_OBJECT_0)
{
DWORD ExitCode ;
if (GetExitCodeProcess(ProcessInfo.hProcess, &ExitCode))
{
Status = (ExitCode >> 24) ; // Feedback from the dll function
if (Status == DLL_FUNCTION_OK)
{
DWORD Size = (ExitCode & 0x00FFFFFF) ;
if (Size)
{
BYTE *Buffer = new BYTE[Size] ;
Dll_function_return_Data =
(Dll_function_return_Data_Type*)Buffer ;
SetFilePointer(MemoryFile, 0, 0, FILE_BEGIN) ;
DWORD BytesCopied ;
ReadFile(MemoryFile, Buffer, Size, &BytesCopied, NULL) ;
if (BytesCopied != Size)
Status = MY_ERROR ;
}
}
}
}
CloseHandle(ProcessInfo.hProcess) ;
CloseHandle(ProcessInfo.hThread) ;
}
UnmapViewOfFile(View) ;
}
CloseHandle(MemoryFile) ;
32位中的相关代码Hlpr.exe
:
if (ParamCount() >= 3)
{
String DllPath = StringReplace(ParamStr(0), L"Hlpr.exe",
L"the_32bit_dll.dll", TReplaceFlags() << rfReplaceAll) ;
DllHandle = LoadLibraryExW(DllPath.c_str(), NULL, 0) ;
if (DllHandle)
{
// Here the dll exported function pointers are collected (GetProcAddress())
if (dll_function_pointer)
{
MemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false,
ParamStr(1).c_str()) ;
if (MemoryFile)
{
void *View = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
DWORD SizeOfMappedFile = ParamStr(2).ToInt() ;
if (SizeOfMappedFile)
{
AnsiString ImageFileNameA(ParamStr(3)) ;
DWORD Size ;
Dll_function_return_Data_Type *Dll_function_return_Data ;
Status = dll_function_pointer(ImageFileNameA.c_str(),
Dll_function_return_Data, Size) ;
if (Status == DLL_FUNCTION_OK)
{
if (SizeOfMappedFile >= Size)
{
SetFilePointer(MemoryFile, 0, 0, FILE_BEGIN) ;
if (WriteFile(MemoryFile, (BYTE*)Dll_function_return_Data,
Size, &BytesCopied, NULL)) // FAILS
{
if (Size != BytesCopied)
Status = MY_ERROR ;
}
else
{
LOG("Error: %u", GetLastError()) ; // Returns error 6
Status = MY_ERROR ;
}
}
else
Status = MY_ERROR ;
}
}
UnmapViewOfFile(View) ;
}
}
}
}
程序退出,退出代码为:
return ((Status << 24) | BytesCopied) ;
根据我意识到的评论,我误解了 FileMapping HANDLE
的使用和 MapViewOfFile()
.
的用途
我可以简单地在 MapViewOfFile()
[=20= 返回的指针上使用 memcpy()
而不是在 memory-mapped 文件上使用 ReadFile()
和 WriteFile()
]
固定代码如下:
64位DLL中的相关代码:
char MemoryFileName[] = "unique_name_with_extra_random_chars";
HANDLE MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_EXECUTE_READWRITE, 0, (256 * 1024), MemoryFileName) ;
if (MemoryFile)
{
void *Mem = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0) ;
char Exe[] = "Hlpr.exe" ;
char Cmd[2048] = "Hlpr.exe " ;
strcat(Cmd, "\"") ;
strcat(Cmd, MemoryFileName) ;
strcat(Cmd, "\" \"") ;
strcat(Cmd, "262144") ; // (256 * 1024)
strcat(Cmd, "\" \"") ;
strcat(Cmd, file_name_path_of_data_the_dll_needs_to_parse) ;
strcat(Cmd, "\"") ;
STARTUPINFO StartupInfo = {sizeof StartupInfo} ; // Init
PROCESS_INFORMATION ProcessInfo ;
if (Mem && CreateProcess(Exe, Cmd, NULL, NULL, false, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE) == WAIT_OBJECT_0)
{
DWORD ExitCode ;
if (GetExitCodeProcess(ProcessInfo.hProcess, &ExitCode))
{
Status = (ExitCode >> 24) ; // Feedback from the dll function
if (Status == DLL_FUNCTION_OK)
{
DWORD Size = (ExitCode & 0x00FFFFFF) ;
if (Size)
{
BYTE *Buffer = new BYTE[Size] ;
Dll_function_return_Data =
(Dll_function_return_Data_Type*)Buffer ;
memcpy(Buffer, Mem, Size) ;
}
}
}
}
CloseHandle(ProcessInfo.hProcess) ;
CloseHandle(ProcessInfo.hThread) ;
}
UnmapViewOfFile(Mem) ;
}
CloseHandle(MemoryFile) ;
32位中的相关代码Hlpr.exe
:
if (ParamCount() >= 3)
{
String DllPath = StringReplace(ParamStr(0), L"Hlpr.exe",
L"the_32bit_dll.dll", TReplaceFlags() << rfReplaceAll) ;
DllHandle = LoadLibraryExW(DllPath.c_str(), NULL, 0) ;
if (DllHandle)
{
// Here the dll exported function pointers are collected (GetProcAddress())
if (dll_function_pointer)
{
MemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false,
ParamStr(1).c_str()) ;
if (MemoryFile)
{
void *Mem = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0) ;
DWORD SizeOfMappedFile = ParamStr(2).ToInt() ;
if (Mem && SizeOfMappedFile)
{
AnsiString ImageFileNameA(ParamStr(3)) ;
DWORD Size ;
Dll_function_return_Data_Type *Dll_function_return_Data ;
Status = dll_function_pointer(ImageFileNameA.c_str(),
Dll_function_return_Data, Size) ;
if (Status == DLL_FUNCTION_OK)
{
if (SizeOfMappedFile >= Size)
{
memcpy(Mem, (BYTE*)Dll_function_return_Data, Size) ;
BytesCopied = Size ;
}
else
Status = MY_ERROR ;
}
}
UnmapViewOfFile(Mem) ;
}
}
}
}
程序退出,退出代码为:
return ((Status << 24) | BytesCopied) ;
作为临时解决方案,我正在实现一种通过 32 位 DLL 将一些数据获取到 64 位应用程序的方法。
我尽量保持简单,不需要高性能或最漂亮的解决方案。这个想法是不要在花哨的握手等上浪费太多时间
为此,我的 64 位应用程序加载了一个我自己制作的 64 位 DLL(它具有与 32 位 DLL 相同的导出函数)。因此,在主应用程序中,没有任何变化。
64 位 DLL 通过在命令行上传递内存映射文件的名称和一些其他输入数据来创建内存映射文件并启动 32 位帮助程序。
辅助可执行文件加载 32 位 DLL,调用 DLL 函数,将数据复制到共享内存映射文件中,退出,然后......Bob 是你的叔叔。
也就是说 .. Bob 今天过得很糟糕,它不起作用。 WriteFile()
到内存映射文件失败并出现 Windows API 错误 6 (ERROR_INVALID_HANDLE
),如 GetLastError()
.
除了写入内存映射文件外一切正常(读取也可能失败,但还没有成功)。
我确信问题出在我创建内存映射文件的方式上,我在这里完全无法理解,所以我很感激一双新的眼睛。
64位DLL中的相关代码:
char MemoryFileName[] = "unique_name_with_extra_random_chars";
HANDLE MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_EXECUTE_READWRITE, 0, (256 * 1024), MemoryFileName) ;
if (MemoryFile)
{
void *View = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0) ;
char Exe[] = "Hlpr.exe" ;
char Cmd[2048] = "Hlpr.exe " ;
strcat(Cmd, "\"") ;
strcat(Cmd, MemoryFileName) ;
strcat(Cmd, "\" \"") ;
strcat(Cmd, "262144") ; // (256 * 1024)
strcat(Cmd, "\" \"") ;
strcat(Cmd, file_name_path_of_data_the_dll_needs_to_parse) ;
strcat(Cmd, "\"") ;
STARTUPINFO StartupInfo = {sizeof StartupInfo} ; // Init
PROCESS_INFORMATION ProcessInfo ;
if (CreateProcess(Exe, Cmd, NULL, NULL, false, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE) == WAIT_OBJECT_0)
{
DWORD ExitCode ;
if (GetExitCodeProcess(ProcessInfo.hProcess, &ExitCode))
{
Status = (ExitCode >> 24) ; // Feedback from the dll function
if (Status == DLL_FUNCTION_OK)
{
DWORD Size = (ExitCode & 0x00FFFFFF) ;
if (Size)
{
BYTE *Buffer = new BYTE[Size] ;
Dll_function_return_Data =
(Dll_function_return_Data_Type*)Buffer ;
SetFilePointer(MemoryFile, 0, 0, FILE_BEGIN) ;
DWORD BytesCopied ;
ReadFile(MemoryFile, Buffer, Size, &BytesCopied, NULL) ;
if (BytesCopied != Size)
Status = MY_ERROR ;
}
}
}
}
CloseHandle(ProcessInfo.hProcess) ;
CloseHandle(ProcessInfo.hThread) ;
}
UnmapViewOfFile(View) ;
}
CloseHandle(MemoryFile) ;
32位中的相关代码Hlpr.exe
:
if (ParamCount() >= 3)
{
String DllPath = StringReplace(ParamStr(0), L"Hlpr.exe",
L"the_32bit_dll.dll", TReplaceFlags() << rfReplaceAll) ;
DllHandle = LoadLibraryExW(DllPath.c_str(), NULL, 0) ;
if (DllHandle)
{
// Here the dll exported function pointers are collected (GetProcAddress())
if (dll_function_pointer)
{
MemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false,
ParamStr(1).c_str()) ;
if (MemoryFile)
{
void *View = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
DWORD SizeOfMappedFile = ParamStr(2).ToInt() ;
if (SizeOfMappedFile)
{
AnsiString ImageFileNameA(ParamStr(3)) ;
DWORD Size ;
Dll_function_return_Data_Type *Dll_function_return_Data ;
Status = dll_function_pointer(ImageFileNameA.c_str(),
Dll_function_return_Data, Size) ;
if (Status == DLL_FUNCTION_OK)
{
if (SizeOfMappedFile >= Size)
{
SetFilePointer(MemoryFile, 0, 0, FILE_BEGIN) ;
if (WriteFile(MemoryFile, (BYTE*)Dll_function_return_Data,
Size, &BytesCopied, NULL)) // FAILS
{
if (Size != BytesCopied)
Status = MY_ERROR ;
}
else
{
LOG("Error: %u", GetLastError()) ; // Returns error 6
Status = MY_ERROR ;
}
}
else
Status = MY_ERROR ;
}
}
UnmapViewOfFile(View) ;
}
}
}
}
程序退出,退出代码为:
return ((Status << 24) | BytesCopied) ;
根据我意识到的评论,我误解了 FileMapping HANDLE
的使用和 MapViewOfFile()
.
我可以简单地在 MapViewOfFile()
[=20= 返回的指针上使用 memcpy()
而不是在 memory-mapped 文件上使用 ReadFile()
和 WriteFile()
]
固定代码如下:
64位DLL中的相关代码:
char MemoryFileName[] = "unique_name_with_extra_random_chars";
HANDLE MemoryFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
PAGE_EXECUTE_READWRITE, 0, (256 * 1024), MemoryFileName) ;
if (MemoryFile)
{
void *Mem = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0) ;
char Exe[] = "Hlpr.exe" ;
char Cmd[2048] = "Hlpr.exe " ;
strcat(Cmd, "\"") ;
strcat(Cmd, MemoryFileName) ;
strcat(Cmd, "\" \"") ;
strcat(Cmd, "262144") ; // (256 * 1024)
strcat(Cmd, "\" \"") ;
strcat(Cmd, file_name_path_of_data_the_dll_needs_to_parse) ;
strcat(Cmd, "\"") ;
STARTUPINFO StartupInfo = {sizeof StartupInfo} ; // Init
PROCESS_INFORMATION ProcessInfo ;
if (Mem && CreateProcess(Exe, Cmd, NULL, NULL, false, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
if (WaitForSingleObject(ProcessInfo.hProcess, INFINITE) == WAIT_OBJECT_0)
{
DWORD ExitCode ;
if (GetExitCodeProcess(ProcessInfo.hProcess, &ExitCode))
{
Status = (ExitCode >> 24) ; // Feedback from the dll function
if (Status == DLL_FUNCTION_OK)
{
DWORD Size = (ExitCode & 0x00FFFFFF) ;
if (Size)
{
BYTE *Buffer = new BYTE[Size] ;
Dll_function_return_Data =
(Dll_function_return_Data_Type*)Buffer ;
memcpy(Buffer, Mem, Size) ;
}
}
}
}
CloseHandle(ProcessInfo.hProcess) ;
CloseHandle(ProcessInfo.hThread) ;
}
UnmapViewOfFile(Mem) ;
}
CloseHandle(MemoryFile) ;
32位中的相关代码Hlpr.exe
:
if (ParamCount() >= 3)
{
String DllPath = StringReplace(ParamStr(0), L"Hlpr.exe",
L"the_32bit_dll.dll", TReplaceFlags() << rfReplaceAll) ;
DllHandle = LoadLibraryExW(DllPath.c_str(), NULL, 0) ;
if (DllHandle)
{
// Here the dll exported function pointers are collected (GetProcAddress())
if (dll_function_pointer)
{
MemoryFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, false,
ParamStr(1).c_str()) ;
if (MemoryFile)
{
void *Mem = MapViewOfFile(MemoryFile, FILE_MAP_ALL_ACCESS, 0, 0, 0) ;
DWORD SizeOfMappedFile = ParamStr(2).ToInt() ;
if (Mem && SizeOfMappedFile)
{
AnsiString ImageFileNameA(ParamStr(3)) ;
DWORD Size ;
Dll_function_return_Data_Type *Dll_function_return_Data ;
Status = dll_function_pointer(ImageFileNameA.c_str(),
Dll_function_return_Data, Size) ;
if (Status == DLL_FUNCTION_OK)
{
if (SizeOfMappedFile >= Size)
{
memcpy(Mem, (BYTE*)Dll_function_return_Data, Size) ;
BytesCopied = Size ;
}
else
Status = MY_ERROR ;
}
}
UnmapViewOfFile(Mem) ;
}
}
}
}
程序退出,退出代码为:
return ((Status << 24) | BytesCopied) ;