我试图将我现有的Windows桌面应用程序(在Windows-7上运行正常)移植到Windows-10(通用Windows平台) 在Windows-10上,MapViewOfFile返回
ERROR_INVALID_PARAMETER
,当我设置访问类型为FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE
。
我的代码如下:
HANDLE mhandle = NULL;
HANDLE g_hfile;
LARGE_INTEGER ms_size;
size_t file_size = 0;
void* map = NULL;
CREATEFILE2_EXTENDED_PARAMETERS ms_param;
ms_param.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
ms_param.dwFileAttributes = GENERIC_WRITE | GENERIC_EXECUTE;
ms_param.dwFileFlags = FILE_FLAG_NO_BUFFERING;
ms_param.dwSecurityQosFlags = SECURITY_DELEGATION;
ms_param.lpSecurityAttributes = NULL;
ms_param.hTemplateFile = NULL;
g_hfile = CreateFile2(filename, GENERIC_WRITE | GENERIC_EXECUTE, FILE_SHARE_READ|FILE_SHARE_WRITE, OPEN_EXISTING, &ms_param);
if (g_hfile == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
if (GetFileSizeEx(g_hfile, &ms_size) == 0)
{
return GetLastError();
}
file_size = ms_size.u.LowPart | ((unsigned long long)ms_size.u.HighPart << 32 );
mhandle = CreateFileMapping(g_hfile, NULL, PAGE_EXECUTE_READWRITE, (unsigned long long)ms_size.u.HighPart, ms_size.u.LowPart, NULL);
if (mhandle == NULL)
{
return GetLastError();
}
map = MapViewOfFile(mhandle, FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE, 0, 0, file_size);
if (map == NULL)
{
return GetLastError();
}
被映射的文件大小约为1KB。如果我将访问类型设置为FILE_MAP_READ | FILE_MAP_WRITE
或FILE_MAP_READ | FILE_MAP_EXEC
MapViewOfFile
按预期工作。
但是,如果我使用FILE_MAP_READ | FILE_MAP_EXEC | FILE_MAP_EXECUTE
或FILE_MAP_EXEC | FILE_MAP_EXECUTE
MapViewOfFile
失败。
我没有找到任何关于此api的Windows-10特定文档。我在这里阅读了这个API的可用MSDN文档:https://msdn.microsoft.com/en-us/library/windows/desktop/aa366761(v=vs.85).aspx
此外,为UWP设置的API似乎不包含此api:https://msdn.microsoft.com/en-us/library/windows/desktop/mt186421(v=vs.85).aspx
任何建议将受到高度赞赏
我认为你的问题不再适用,但希望我的回答对那些面临同样问题的人有所帮助。您正在使用正确的UWP API来创建文件,但用于文件映射的API是错误的。你需要使用CreateFileMappingFromApp而不是CreateFileMapping
和MapViewOfFileFromApp而不是MapViewOfFile
。仔细看看,UWP CreateFileMappingFromApp
的PageProtection类型根本不允许EXECUTE。
这里是代码示例,其中包含大量描述非明显片段的注释:
#include <windows.h>
#include <string>
#include <iostream>
// you may combine access in the same was as pageFileAccessMode allows
enum class AccessMode {
READ,
READ_WRITE
};
DWORD openFileForMapping(AccessMode accessMode, std::wstring const & filepath, HANDLE * fileHandler, std::size_t & fileSize, HANDLE * fileMappingHandler) {
DWORD fileAccessRegularMode;
DWORD fileAccessSharedMode;
DWORD pageFileAccessMode;
HANDLE localFileHandler;
HANDLE localFileMappingHandler;
switch (accessMode) {
case AccessMode::READ:
fileAccessRegularMode = GENERIC_READ;
fileAccessSharedMode = FILE_SHARE_READ;
pageFileAccessMode = PAGE_READONLY;
break;
case AccessMode::READ_WRITE:
fileAccessRegularMode = GENERIC_READ | GENERIC_WRITE;
fileAccessSharedMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
pageFileAccessMode = PAGE_READWRITE;
break;
}
// parameters MUST be initialized with zero and size
CREATEFILE2_EXTENDED_PARAMETERS createFile2ParametersEx{ 0 };
createFile2ParametersEx.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
createFile2ParametersEx.dwFileAttributes = fileAccessRegularMode;
// parameters options, depends on your requirements
createFile2ParametersEx.dwFileFlags = FILE_FLAG_NO_BUFFERING;
createFile2ParametersEx.lpSecurityAttributes = NULL;
createFile2ParametersEx.hTemplateFile = NULL;
localFileHandler = CreateFile2(filepath.c_str(), fileAccessRegularMode, fileAccessSharedMode, OPEN_EXISTING, &createFile2ParametersEx);
if (localFileHandler == INVALID_HANDLE_VALUE) {
return GetLastError();
}
LARGE_INTEGER msSize;
if (GetFileSizeEx(localFileHandler, &msSize) == 0) {
return GetLastError();
}
fileSize = msSize.QuadPart;
localFileMappingHandler = CreateFileMappingFromApp(localFileHandler, NULL, pageFileAccessMode, fileSize, NULL);
if (localFileMappingHandler == nullptr) {
return GetLastError();
}
*fileHandler = localFileHandler;
*fileMappingHandler = localFileMappingHandler;
return S_OK;
}
DWORD getView(AccessMode accessMode, HANDLE fileMappingHandler, std::uint64_t beginIndex, std::uint64_t lengthOfView, void ** mapView) {
DWORD mapViewAccessMode;
switch (accessMode) {
case AccessMode::READ:
mapViewAccessMode = FILE_MAP_READ;
break;
case AccessMode::READ_WRITE:
mapViewAccessMode = FILE_MAP_READ | FILE_MAP_WRITE;
break;
}
*mapView = MapViewOfFileFromApp(fileMappingHandler, mapViewAccessMode, beginIndex, lengthOfView);
if (*mapView == nullptr) {
return GetLastError();
}
return S_OK;
}
DWORD getFileMapViewAndPrint() {
DWORD errorCode;
// don't forget, UWP app have write access only inside container local folder
std::wstring filename = L"test.txt";
// open file with desired acces and create file mapping
HANDLE fileHandle;
HANDLE fileMappingHandle;
std::size_t fileSize;
errorCode = openFileForMapping(AccessMode::READ, filename.c_str(), &fileHandle, fileSize, &fileMappingHandle);
if (errorCode != S_OK) {
return errorCode;
}
// using created file mapping project map view to file
void * mapView;
errorCode = getView(AccessMode::READ, fileMappingHandle, 0, fileSize, &mapView);
if (errorCode != S_OK) {
return errorCode;
}
// mapView now contains row data from file, in my case it was txt
// with UTF8 text so I just need to cast void to char
OutputDebugStringA(static_cast<char*>(mapView));
OutputDebugStringA("\n");
// cleanup
UnmapViewOfFile(mapView);
mapView = nullptr;
CloseHandle(fileMappingHandle);
CloseHandle(fileHandle);
return S_OK;
}