Locking a drive with FSCTL_LOCK_VOLUME - c++

I'm having trouble locking my C drive so I can extract some file information later.
#define wszDrive L"\\\\.\\PhysicalDrive0"
HANDLE targetVol = INVALID_HANDLE_VALUE;
DWORD stats;
targetVol = CreateFile(wszDrive,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
/*FILE_FLAG_NO_BUFFERING | FILE_FLAG_RANDOM_ACCESS*/0,
NULL);
if (targetVol == INVALID_HANDLE_VALUE) // cannot open the drive
{
cout << "error in ioControl with volume handler" << endl;
system("pause");
}
if (DeviceIoControl(targetVol,
FSCTL_LOCK_VOLUME,
NULL, 0, NULL, 0,
&stats,
NULL) ==0)
{
cout << "Error with targetVol DeviceIo" << endl;
ErrorExit(TEXT("GetProcessId"));
system("pause");
}
The Error exit below returns "GetProcessID faile with error 1: Incorrect function."
void ErrorExit(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
ExitProcess(dw);
}
Do you guys have any idea what's going on wrong?

The MSDN docs for FSCTL_LOCK_VOLUME say right off the bat that
Locks a volume if it is not in use
The C: drive is almost always in use. The only time it's not in use is if you've booted from different media.

Related

Failed with error 87: The parameter is incorrect. How to determine which parameter is incorrect?

I'm trying to create a win32 window as simple as possible, in a unit test, but I get an error 87: how do I get which parameter is incorrect ?
#include <windows.h>
#include <strsafe.h>
LPTSTR GetErrorMessage(wstring fnName)
{
LPTSTR messageBuffer{};
LPTSTR displayBuffer{};
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&messageBuffer, 0, 0);
displayBuffer = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, lstrlen(messageBuffer) + (fnName.size() + 40) * sizeof(TCHAR));
StringCchPrintf(displayBuffer, LocalSize(displayBuffer) / sizeof(TCHAR), L"%s failed with error %d: %s", fnName.c_str(), dw, messageBuffer);
return displayBuffer;
}
TEST_METHOD(WinTest)
{
auto hwnd = CreateWindowExW(WS_EX_APPWINDOW, 0, L"test w", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 800, 600, 0, 0, 0, 0);
Assert::IsNotNull(hwnd, GetErrorMessage(L"CreateWindowExW"));
ShowWindow(hwnd, SW_SHOWDEFAULT);
Sleep(1000);
}
Assert failed. CreateWindowExW failed with error 87: The parameter is incorrect.
Reference: createwindowexw on learn.microsoft.com
To answer the specific question you asked - the Win32 API does not tell you WHICH parameter is invalid. You have to read the documentation for the function that failed, and then debug your code to compare the values you are actually passing to the function to see how they differ from the acceptable values the function is expecting.
In this particular example, you are passing a NULL pointer to the lpClassName parameter of CreateWindowEx(), which is not allowed. You must specify the name of the window class you want to create.
On a side note, your GetErrorMessage() function is leaking memory, as it does not free the memory allocated by either FormatMessage() or LocalAlloc(). Both messageBuffer and displayBuffer need to be freed with LocalFree().
I strongly advise you to make GetErrorMessage() return a wstring instead of a raw TCHAR* pointer, eg:
wstring GetErrorMessage(const wstring &fnName)
{
DWORD dw = GetLastError();
wostringstream displayBuffer;
displayBuffer << fnName << L" failed with error " << dw;
LPWSTR messageBuffer{};
if (FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&messageBuffer,
0,
0))
{
displayBuffer << L": " << messageBuffer;
LocalFree(messageBuffer);
}
return displayBuffer.str();
}

When error 1224: ERROR_USER_MAPPED_FILE occurs?

I want to really understand when the ERROR_USER_MAPPED_FILE occurs. So I wrote some snippets. To reproduce the error. But it did not work. Please help me fix my code
Process 1:
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hMapFile == INVALID_HANDLE_VALUE)
return GetLastError();
mapHandles.push_back(hMapFile);
viewHandles.push_back(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0));
I am Halting the process and I have not closed any view of the map and file handles yet in this process so that when the other process tries to open the file. I thought error 1224 will be thrown.
Process 2:
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
cout << "Error Code : " << GetLastError() << endl;
char buffer[1025];
DWORD bytesRead;
if (!ReadFile(hFile, buffer, 1024, &bytesRead, 0))
cout << "Error Code : " << GetLastError() << endl;
The CreateFile and ReadFile succeeds in the process 2.
Actually I am trying to handle this error 1224 separately. Which means when the file fails with error 32 I want to do something. and if the file fails with error 1224 I want to do something.
Now I must test those cases. In order to test those scenarios I should reproduce the error 1224.
I want to really understand when the ERROR_USER_MAPPED_FILE occurs
if really understand let some extra info.
at first this error returned from kernel. so it was initially NTSTATUS error code, which than translated to win32 error by RtlNtStatusToDosError. api for reverse translation not exist - because it not uniquely, but possible yourself write code, which create reverse translation map. two NTSTATUS codes is translated to ERROR_USER_MAPPED_FILE : STATUS_USER_MAPPED_FILE and STATUS_PURGE_FAILED:
if (
RtlNtStatusToDosError(STATUS_USER_MAPPED_FILE) != ERROR_USER_MAPPED_FILE
||
RtlNtStatusToDosError(STATUS_PURGE_FAILED) != ERROR_USER_MAPPED_FILE
)
{
__debugbreak();
}
for completely understand when this codes returned need look File System source code. we have fastfat example. if search for STATUS_USER_MAPPED_FILE - we can found that this code returned from 4 place:
FatSupersedeOrOverwriteFile - when we try call
ZwCreateFile with FILE_OVERWRITE_IF or FILE_SUPERSEDE
CreateOption or when we call CreateFile with CREATE_ALWAYS
FatSetEndOfFileInfo - when we call ZwSetInformationFile
with FileEndOfFileInformation or SetEndOfFile function
FatSetValidDataLengthInfo- when we call
ZwSetInformationFile with
FileValidDataLengthInformation or SetFileValidData
function (we need have SE_MANAGE_VOLUME_PRIVILEGE for this)
FatSetAllocationInfo - when we use ZwSetInformationFile
with FileAllocationInformation (no win32 api shell)
and you can note common pattern here:
if (!MmCanFileBeTruncated()) return STATUS_USER_MAPPED_FILE;
about demo code for reproduce this error - for what you need two processes ?!? single routine in single process - more than enough.
void test()
{
// for simplicity, i have access to this location as admin
STATIC_OBJECT_ATTRIBUTES(oa, "\\systemroot\\temp\\.tmp");
HANDLE hFile, hSection, hFile2;
IO_STATUS_BLOCK iosb;
LARGE_INTEGER AllocationSize = { PAGE_SIZE };
NTSTATUS status;
if (0 <= NtCreateFile(&hFile, FILE_GENERIC_WRITE|FILE_GENERIC_READ, &oa, &iosb, &AllocationSize, 0,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, 0, 0))
{
status = NtCreateSection(&hSection, SECTION_MAP_READ|SECTION_MAP_WRITE, 0, &AllocationSize, PAGE_READWRITE, SEC_COMMIT, hFile);
if (0 <= status)
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = 0;
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READONLY);
NtClose(hSection);
if (0 <= status)
{
LARGE_INTEGER Eof = {};
// SetEndOfFile win32 api
status = ZwSetInformationFile(hFile, &iosb, &Eof, sizeof(Eof), FileEndOfFileInformation);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
// no win32 api
status = ZwSetInformationFile(hFile, &iosb, &Eof, sizeof(Eof), FileAllocationInformation);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
// SetFileValidData win32 api
// we need have SE_MANAGE_VOLUME_NAME privilege, otherwise STATUS_PRIVILEGE_NOT_HELD
status = ZwSetInformationFile(hFile, &iosb, &Eof, sizeof(Eof), FileValidDataLengthInformation);
switch (status)
{
case STATUS_USER_MAPPED_FILE:
case STATUS_PRIVILEGE_NOT_HELD:
break;
default: __debugbreak();
}
//CreateFileW(L"\\\\?\\c:\\windows\\temp\\.tmp", FILE_GENERIC_READ|FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0, CREATE_ALWAYS, 0, 0);
status = NtCreateFile(&hFile2, FILE_GENERIC_WRITE|FILE_GENERIC_READ, &oa, &iosb, 0, 0,
FILE_SHARE_VALID_FLAGS, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
status = NtCreateFile(&hFile2, FILE_GENERIC_WRITE|FILE_GENERIC_READ, &oa, &iosb, 0, 0,
FILE_SHARE_VALID_FLAGS, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_NONALERT, 0, 0);
if (status != STATUS_USER_MAPPED_FILE) __debugbreak();
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
}
NtClose(hFile);
}
}
about STATUS_PURGE_FAILED - look like in can be returned when we call WriteFile - look here - but i can not reproduce it in test. however very rarely this error can occur - "STATUS_PURGE_FAILED" error when you perform VM replications by using SCVMM in Windows Server 2012 R2
ERROR_USER_MAPPED_FILE or error 1224 occurs when you try to delete or overwrite a file which has been mapped by other process.
Process #1
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return GetLastError();
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (hMapFile == INVALID_HANDLE_VALUE)
return GetLastError();
mapHandles.push_back(hMapFile);
viewHandles.push_back(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0));
Process #2
HANDLE hFile = CreateFile("C:\\test\\full.exe", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
if(GetLastError() == 1224)
// File has been mapped by other process
else
// some other issue
}
In Process #2, CREATE_ALWAYS tries to overwrite a file which has been mapped. So it ends up throwing error 1224.

Wide Char Version of Get last Error?

This is Microsoft's code:
void ErrorExit(LPCWSTR lpszFunction, DWORD NTStatusMessage)
{
// Retrieve the system error message for the last-error code
DWORD dww = 0;
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
if (NTStatusMessage)
{
dww = NTStatusMessage;
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_FROM_HMODULE,
hdlNtCreateFile,
dww,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR) &lpMsgBuf,
0,
NULL );
}
else
{
dww = GetLastError();
FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dww,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf,0, NULL);
}
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %lu: %s"), lpszFunction, dww, lpMsgBuf);
printf("\a"); //audible bell not working yet
MessageBoxW(NULL, (LPCTSTR)lpDisplayBuf, L"Error", MB_OK);
LocalFree(lpDisplayBuf);
LocalFree(lpMsgBuf);
//ExitProcess(dw);
}
I added a section for NTstatus and changed the arg to LPCWSTR. It's basically nonfunctional as simply changing to StringCchPrintfW segfaults on the LPVOID types. Any way of making it wide char friendly?
This problem was solved by adding _UNICODE and UNICODE to the Preprocessor definitions in C/C++ > Preprocessor.
The MessageBox call in the OP code adjusted a little: thanks to someone knowledgeable on the Microsoft forums.

CreateProcess application not found in cache c++ MFC

i am writing a simple program which calls CreateProcess thousands of times, so its taking a while to run. in my output windows i'm seeing this message each time
application "whatever.exe" not found in cache
i call CreateProcess like this
BOOL result = CreateProcess(NULL, g_minicapcmd,
NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInformation);
if (!result) {
LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
CString strError = (LPTSTR) lpMsgBuf;
TRACE(_T("::executeCommandLine() failed at CreateProcess()\nCommand=%s\nMessage=%s\n\n"), g_minicapcmd, strError);
LocalFree(lpMsgBuf);
return false;
} else {
// Successfully created the process. Wait for it to finish.
WaitForSingleObject( processInformation.hProcess, INFINITE );
// Close the handles.
CloseHandle( processInformation.hProcess );
CloseHandle( processInformation.hThread );
}
is there a way to get it to cache or some way to make it faster? i already tried putting the .exe its loading on ramdisk and that helped a bit

install driver using c++

I'm trying to install driver behind the user:
I've create DLL which call SetupCopyOEMInf using c++ then i call it from VB application:
C++ code:
PBOOL bRebootRequired = false;
PCTSTR szInfFileName = (PCTSTR) "c:\\temp\\ttt\\Driver\\slabvcp.inf";
if(!SetupCopyOEMInf(szInfFileName,NULL, SPOST_PATH, SP_COPY_REPLACEONLY, NULL, 0, NULL, NULL)){;
DWORD dw = GetLastError();
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,0, NULL );
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
}
And when i call this function i receiving error "The system cannot find the file specified."
But the path to my file is correct.
PCTSTR szInfFileName = (PCTSTR) "c:\\temp\\ttt\\Driver\\slabvcp.inf";
A cast is not going to work, it will turn your 8-bit character string into Chinese. Fix:
PCTSTR szInfFileName = _T("c:\\temp\\ttt\\Driver\\slabvcp.inf");