C++ How to get MailSlot Handle via MailSlotName - c++

We are using window's mailslots in one of our Windows 10 application.
Usually windows is very good at managing them, but we recently came across an issue where the MailSlot does not close anymore, meaning every time our application is started it leads to a crash.
Usually we would diagnose the issue to know exactly where it comes from, but in this case it would require paralysing the production line for several days, which we can't afford.
So we decided to create a script/application to close the mailslot if it exists when we start the program, since the program is currently being launched through a batch file.
I have tried this :
HANDLE OpenProcessByName(LPCTSTR Name, DWORD dwAccess)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
ZeroMemory(&pe, sizeof(PROCESSENTRY32));
pe.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnap, &pe);
do
{
if (!lstrcmpi(pe.szExeFile, Name))
{
return OpenProcess(dwAccess, 0, pe.th32ProcessID);
}
} while (Process32Next(hSnap, &pe));
}
return INVALID_HANDLE_VALUE;
}
As you can expect, this return process names not mailslot names
Is there any way to modify the code snippet above to work with mailslot names (for the sake of examples we can assume that the mailslot is located here : \Device\Mailslot\sample_mailslot with sample_mailslot being its name)
Or is there a different way to go about things ?
PS :
I know that the best way would be to store the HANDLE that's being returned when we create the mailslot, the issue is we don't have access to the source code, so we are forced to work outside it.

Related

I'm using QDir().isReadable to check if a drive is readable. In the Qt Creator it runs fine, but when I run the exe it keeps giving me errors

I'm using it like this:
if(QDir("G:/").isReadable()){
qDebug("G Is readable!"); //Do something with G:/
}
As I said, in Qt Creator it runs fine without a problem, it checks if the drive is readable, and if so it prints it to the console, if not, it does nothing.
But when I run the .exe file, it keeps giving me errors each time it does the check (every 2 seconds) if the drive isn't readable.
"There is no disk in the drive. Please insert a disk into drive G:."
I don't want this error to keep appearing, what do I do?
Edit: I think it's the isReadable function that causes the problem, is there any other way to do what I want to do? Or maybe should I write the code myself?
This message is generated by Windows.
There is a workaround for users that have applications that cannot be fixed. The error messages may be suppressed by setting 2 to registry key ErrorMode in:
Computer\HKEY_LOCAL\MACHINE\SYSTEM\CurrentControlSet\Control\Windows
It looks that if QDir::isReadable() is called after removing the media it triggers that error. QDir::exists() always returns true if the drive letter is present in the system, so it cannot be used here.
For now I see that it is possible to check removable media using native Windows API, see the answer to How to detect if media is inserted into a removable drive/card reader
The following code is able to detect that the media is removed without triggering the error:
#include <windows.h>
HANDLE hDevice = CreateFile (L"\\\\.\\G:", // like "\\.\G:"
FILE_READ_ATTRIBUTES, // read access to the attributes
FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
// not valid device
return;
}
WORD cbBytesReturned;
bool bSuccess = DeviceIoControl (hDevice, // device to be queried
IOCTL_STORAGE_CHECK_VERIFY2,
NULL, 0, // no input buffer
NULL, 0, // no output buffer
(LPDWORD)&cbBytesReturned, // # bytes returned
NULL); // synchronous I/O
CloseHandle(hDevice); // close handle
if (bSuccess && QDir("G:/").isReadable()) {
// G is readable
}

Finding cluster info of a file

I've been trying to find information on a file by using CreateFile() and DeviceIoControl(). However I keep running into ERROR_HANDLE_EOF which from my understanding means that the starting virtual cluster number is past the end of the file even though I am starting at 0. Here is a few snippets of my code, let me know if you guys have any idea what's going wrong.
HANDLE hFile = INVALID_HANDLE_VALUE; //drive or file to be checked
LPWSTR txtFile = L"Text.txt"; //text file
hFile = CreateFile(txtFile, //target file
GENERIC_READ | GENERIC_WRITE, //read and write
FILE_SHARE_READ|FILE_SHARE_WRITE,//allows sharing of read and writes
NULL, //security prevents child process from inheriting the handle
OPEN_EXISTING, //open file or drive if it exist
FILE_ATTRIBUTE_NORMAL, //default settings for files
NULL); //template file with generiv read access rights
if (hFile == INVALID_HANDLE_VALUE) //error handling
{
cout<<"File does not exist"<<endl;
CloseHandle (hFile);
system("pause");
}
cout<<"you opened the file succesfully: "<<hFile<<endl;
STARTING_VCN_INPUT_BUFFER startVcn;
RETRIEVAL_POINTERS_BUFFER retrievalBuffer;
DWORD error =ERROR_MORE_DATA;
BOOL returns;
startVcn.StartingVcn.QuadPart = 0;
while( error ==ERROR_MORE_DATA){
DWORD bytesReturned;
returns = DeviceIoControl(hFile,
FSCTL_GET_RETRIEVAL_POINTERS,
&startVcn,
sizeof(STARTING_VCN_INPUT_BUFFER),
&retrievalBuffer,
sizeof(RETRIEVAL_POINTERS_BUFFER),
&bytesReturned,
NULL);
error = GetLastError();
switch(error){
case ERROR_HANDLE_EOF:
cout<<"ERROR_HANDLE_EOF"<<endl;
returns = true;
break;
case ERROR_MORE_DATA:
cout<<"ERROR_MORE_DATA"<<endl;
startVcn.StartingVcn = retrievalBuffer.Extents[0].NextVcn;
case NO_ERROR:
cout<<"NO_ERROR, here is some info: "<<endl
<<retrievalBuffer.StartingVcn.QuadPart<<endl
<<retrievalBuffer.Extents[0].Lcn.QuadPart<<endl
<<retrievalBuffer.Extents[0].NextVcn.QuadPart
- retrievalBuffer.StartingVcn.QuadPart<<endl;
returns = true;
break;
default:
cout<<"Error in the code or input error"<<endl;
break;
}
}
I wrote pretty much the same program myself and, like the OP, I found that I was getting ERROR_HANDLE_EOF which I couldn’t explain. When I went looking for an explanation, I never found one but stumbled across this post. The OP’s program looks correct to me so I strongly suspect the explanation for the behaviour is the same as mine. I realize it is way too late to help the OP but for the benefit of anyone else who spends 1 whole day working this out, I think the answer is…
Educated guess: ‘Small files’ don’t get a cluster assigned to them and when you query a ‘small file’ with the above program you will receive ERROR_HANDLE_EOF. This sort of makes sense, but is very unfriendly and useless to a newbie like myself. Experiments on the machine I have led me to believe that a ‘small file’ is 736 bytes or less. 737 bytes or more starts using clusters. I found these limits by performing a binary search on various file sizes using Linux/cygwin ‘dd’ command to generate files of the required size.
At this time, I have not found anyone supporting my claim about 736 vs 737 bytes, but http://www.ntfs.com/ntfs_optimization.htm does say “On NTFS if file is small enough, it can be stored in MFT record itself without using additional clusters.”
My systems are using Windows 10, NTFS simple volumes. I don’t understand NTFS, the MFT or attributes very well. Perhaps someday I will find the appropriate structure that explains why this number comes about (like structure can be up to 1K and already has 288 bytes in use??).

How to check if a process is running or not using C++

I should not display certain context menu options if one process is not running?.
I am checking if the process is running or not using the process name.
But the issue is, the process name is showing different way in different windows platforms.
ie, windows 64 bit process name on windows task bar is " applicationname.exe"
some windows xp machine shows the same process name as "applica~2.exe"
Please let me know the consistent way to check if the process is running or not?
My development environment is C++ and Visual Studio 2010
DWORD getProcessID(const std::wstring& processName)
{
PROCESSENTRY32 info;
info.dwSize = sizeof(info);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if ( snapshot == INVALID_HANDLE_VALUE )
return 0;
Process32First(snapshot, &info);
if ( !processName.compare(info.szExeFile) )
{
CloseHandle(snapshot);
return info.th32ProcessID;
}
while ( Process32Next(snapshot, &info) )
{
if ( !processName.compare(info.szExeFile) )
{
CloseHandle(snapshot);
return info.th32ProcessID;
}
}
CloseHandle(snapshot);
return 0;
}
EnumProcesses is the other way to enumerate active processes.
The difference is that you need to allocate the space for PIDs,call EnumProcesses, open each process with PROCESS_QUERY_INFORMATION access flag and then call GetProcessImageFileName on it's handle and do the comparison.
Using WMI to interrogate instances of Win32_Process allows you to check the fullpath of the running processes for a match on the one you need to see.
Are you the author of the process in question? If so, a more robust design would be to use IPC to interrogate the process directly. That way, you don't necessarily have to poll and you don't have irritating issues such as what happens if you detect the process, create the context menu and then the process goes down?

Why is CreateFile failing to open a file across a network share?

I wrote a small program which frequently opens small, user text files and until now haven't encountered any problems with read/write access or any sorts of conflict. The files are selected in another piece of software which I have no control over, and are passed to me as a string.
When attempting to open a file from a mapped network drive I am getting a "The system cannot find the path specified" error (GetLastError() = 3).
The call is shown below, *iNCfileName = "z:\\Validation\\Sample Files\\1_1-4 120MM.CC", where Z: is a mapped folder on our domain.
iNCfile = CreateFile( iNCfileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if ( iNCfile == INVALID_HANDLE_VALUE )
{
string msg; // lots of better ways to get this printed ... but ...
dw = GetLastError();
msg = iNCfileName;
msg += ": ";
msg += _com_error(dw).ErrorMessage();
print_error(dw , (char*)msg.c_str() );
return 102;
}
The file opens from my program if I copy it to the local hard drive. It also opens in notepad from the mapped drive.
Could this be a problem between the "Z:\whatever.txt" mapped representation and the true file name (\mydomain\Validation\S....??)?
If so, how can I convert from one to the other in a programmatic way (assume I won't know the domain/share names ahead of time)?
If it makes any difference I use VS2010 and the application executes on a Win XP machine.
Related: my follow up question
I've encountered this before. When using a path like \\DOMAIN\PATH\FILE.TXT I had to first call WNetAddConnection2().
Here is my code (of course you can exclude the NULL members):
NETRESOURCE nr = {0}; //new structure for network resource
nr.dwType = RESOURCETYPE_ANY; //generic resource (any type allowed)
nr.lpLocalName = NULL; //does not use a device
nr.lpRemoteName = "\\\\DOMAIN\\PATH\\FOLDER"; //For me, this pointed to an account's documents folder, and from there I could use a subfolder
nr.lpProvider = NULL; //no provider
DWORD ret = WNetAddConnection2 (&nr, NULL, NULL, CONNECT_TEMPORARY); //add connection
Don't forget the header and library.
I just had the same issue; trying to create a file using API CreateFileW under a mapped drive ( Z:\folder ) did not worked; howerver, after researching this subject i tried to create the file using the real path ( \\Shared_computer_name\folder\ ) immediately worked successfully.
Now I have to work a function to retrieve the real name of a mapped drive, to use it when necessary... just found WNetGetUniversalName, have to make it to work.

Is it possible to get the WINAPI process handle by the process name without iterating through all processes

Good afternoon, Is it possible to get the WINAPI process handle by its name without walking through all the processes?
I know how to WINAPI process handle by its name by iterating through all the processes:
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE){
while (Process32Next(snapshot, &entry) == TRUE)
{
if (stricmp(entry.szExeFile, ProcessName ) == 0){
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
// measure process memory usage
CloseHandle(hProcess);
}
}
}
CloseHandle(snapshot);
However, it seems like it would take a significant amount of time to iterate through the process snapshot. Thank you.
Each process has a unique ID but not unique name. There could be multiple processes with the same name. So it is impossible, as it is impossible, for example, to get an entry from std::map by value w/o iterating trough everything. What you can do, however, is to write a function that gives you a list of IDs by name, that will be reusable, but still will have to iterate. Why do you worry about performance here? I believe it is nothing comparing to opening of the handle and process memory measurement.