Ok, i have a problem in my program. I made a question about it before, but no one really understood my problem, so im trying a new approach to it this time.
If you're curious this is my problem:
My program takes arguments in the form of char* argv[] , and im having trouble making a pointer to whatever is on argv[1] using LPWSTR, since it only point to const wchar_t* objects.
This is a new thing im trying to solve my problem (i've tried multiple things but i need to know how to do what im thinking, or if its possible)
Basicly, my idea is to #define some sort of function that take whatever is on argv[1] and defines a const wchar_t* with that value.
Something like this:
#define path ((const wchar_t*)argv[1])
Im not sure that is the correct way (or even if this is possible) to do what i want to do...
If you have anny better way of solving me problem, please (please) tell me how to and help me out, i've been thinking about this so a really long time!
Explanation of my program:
Im making a program that recieves arguments. The arguments are the name of the drives, for example "F:". It then uses the function CreateFile with the drive letter. If you go here , and see the first parameter of the function, i think you will see what i mean.... the problem is that for me to make a LPWSTR, i would need a const wchat_t* object.... I hope my question is clear this time, last time people didnt really understand what i was trying to do.
Regardless, thanks!
EDIT 1: here are solve lines of my program (this is how i have to do for it to work, without arguments) (i used a fixed value in here)
int main()
{
HANDLE device;
device = CreateFile(L"\\\\.\\F:", // Drive to open
GENERIC_READ | GENERIC_WRITE, // Access mode
FILE_SHARE_READ | FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL);
}
This is with arguments (doesn't work)
int main(int argc, char* argv[])
{
HANDLE device;
device = CreateFile(argv[1], // Drive to open
GENERIC_READ | GENERIC_WRITE, // Access mode
FILE_SHARE_READ | FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
}
^ this shows what im trying to do
EDIT 2: i changed the CreateFile to CreateFileA , and this is the eroor codes it gives me (the drive D is a usb, its not a hard drive)
So unless im typing the wrong way to type a path, it always gives me erros. I think ill try another way to solve the problem, or if someone knows why thoes errors are happening, please tell!
EDIT 2: i changed the CreateFile to CreateFileA , and this is the eroor codes it gives me (the drive D is a usb, its not a hard drive)
This is a completely different question, and has nothing to do with wchar_t.
In your first snipped you passed "\\\\.\\F:" (AKA \\.\F: once we remove the C escaping); in all your tries from the command line you never provided this path, but respectively:
D - so it tried to open a file named D in the current directory, and it didn't find it (error 2, aka ERROR_FILE_NOT_FOUND);
D:\ - the root directory, which cannot be opened with CreateFile (error 3, aka ERROR_PATH_NOT_FOUND),
D: - the current directory on the drive D:, which again cannot be opened with CreateFile (error 5, aka ERROR_ACCESS_DENIED);
\D: - a file named "D:" in the root of the current drive, which cannot be created given that D: is not a valid file name (error 123, aka ERROR_INVALID_NAME).
To open a drive as a device, you must use the \\.\X: path (where X is the drive letter); you cannot just throw whatever floats in your mind and hope that it'll work. Call your program from the command line passing "\\.\D:" and it'll work fine.
Of course if you want to keep it simpler for the user you can accept just the drive letter on the command line and write some code to create the string required by CreateFile based on it.
if(argc<1) {
printf("Not enough arguments\n");
return 1;
}
const char *drive = argv[1];
char d = drive[0];
// accept both `d` and `d:` as argument for the drive
if(!((d>='a' && d<='z') || (d>='A' && d<='Z')) ||
(drive[1]!=0 && drive[1]!=':') ||
drive[2]!=0) {
printf("Invalid drive specifier: `%s`\n", drive);
return 2;
}
char path[]="\\\\.\\X:";
path[4] = d;
// now you can use path as argument to CreateFileA
What follows was the original answer, which is still valid but it addresses a completely different problem, unrelated to the actual problem OP is experiencing
You cannot make LPWSTR point to a char *, especially not by brutally casting the pointer - casting a pointer just makes the compiler shut up, it doesn't change the fact that what you are pointing at is not a wchar_t string. If you want to pass a char * to a function expecting a wchar_t * you have to perform an actual conversion of the pointed data.
Now, you have several possible solutions:
you can use _wmain and receive your command line arguments directly as wide characters;
you can convert your local-encoding strings to UTF-16 strings by using a function such as the MultiByteToWideChar; this can be encapsulated in a function returning a std::wstring;
you can just invoke the ANSI version of the API and let it deal with it; almost all Win32 APIs have both an ANSI and Unicode version, suffixed with A and W (CreateFile is just a macro that expands to CreateFileA or CreateFileW depending on the _UNICODE macro). So, you can use CreateFileA and pass it your string as-is.
The last two solutions are not great because using local-encoding strings as command line arguments precludes your program from opening files using arbitrary Unicode characters. OTOH, using wchar_t almost everywhere is quite a dread, since they "infect" virtually every string-processing corner of your application. The correct (IMHO) way out is to use UTF-8 everywhere, and convert on the fly when talking to the operating systems; see here for details.
Related
I am trying to use Win API ReadConsole(...) and I want to pass in a delimiter char to halt the input from the console.
The below code works but it only stops reading the input on \r\n.
I would like it to stop reading the console input on '.' for instance.
void read(char *cIn, char delim)
{
HANDLE hFile;
DWORD charsRead;
DWORD charsToRead = MAX_PATH;
CONSOLE_READCONSOLE_CONTROL cReadControl;
cReadControl.nLength = sizeof(CONSOLE_READCONSOLE_CONTROL);
cReadControl.nInitialChars = 0;
cReadControl.dwCtrlWakeupMask = delim;
cReadControl.dwControlKeyState = NULL;
DWORD lpMode;
// char cIn[MAX_PATH]; //-- buffer to hold data from the console
hFile = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
GetConsoleMode(hFile,&lpMode);
// lpMode &= ~ENABLE_LINE_INPUT; //-- turns off this flag
// SetConsoleMode(hFile, lpMode); //-- set the mode with the new flag off
bool read = ReadConsole(hFile, cIn, charsToRead * sizeof(TCHAR), &charsRead, &cReadControl);
cIn[charsRead - 2] = '\0';
}
I know there are other easy ways to do this but I am just trying to understand some of the win api functions and how to use them.
Thank you.
I saw this question and assumed it would be trivial, but spent the last 30 minutes trying to figure it out and finally have something.
That dwCtrlWakeupMask is pretty poorly documented in CONSOLE_READCONSOLE_CONTROL. MSDN says "A user-defined control character used to signal that the read is complete.", but why is it called mask? Why is it a ULONG instead of a TCHAR or something like that? I tried feeding it chars and wchars and nothing happened, so there must be more to the story.
I took to the web searching for that particular variable and found this link:
https://groups.google.com/forum/#!topic/golang-codereviews/KSp37ITmcUg It is a random Go library coder asking for help and the answer is that tab is 1 << '\t'. I tried it, and it works!
So, for future web searchers, dwCtrlWakeupMask is a bitmask of ASCII control characters that will cause ReadConsole to return. You can | together as many 1 << ctrl_chars as you like... but it cannot be arbitrary characters, since it is a bitmask in a 32 bit value, only the chars 1-31 (inclusive) are possible (this group btw is called control characters, it includes things like tab, backspace, bell; things that do not represent printable characters per se).
Thus, this mask:
cReadControl.dwCtrlWakeupMask = (1 << '\t') | (1 << 0x08);
Will cause ReadConsole to return when tab (\t) OR when backspace (0x08) is pressed.
The characters represented by ctrl+ some_ascii_value are the number of that letter in the english alphabet, starting at a == 1. So, ctrl+d is 4, and ctrl+z is 26.
Therefore, this will return when the user hits ctrl+d or ctrl+z:
cReadControl.dwCtrlWakeupMask = (1 << 4) | (1 << 26);
Note that the Linux terminal driver also returns on read when the user hits ctrl+d so this might be a nice compatibility thing.
I believe the point of this argument is to allow easier tab-completion in processed input mode; otherwise, you'd have to turn processed input off and process keys one by one to do that. Now you don't have to.... though tbh, I still prefer taking my input with ReadConsoleInput for interactive programs since you get much better control over it all.
But while there are a lot of other ways to do what you want - and using . as a delimiter is impossible here, since it has a value >= 32, so you need to do it yourself... understanding what this does is interesting to me anyway, and there's scarce resources on the web so I'm writing this up just for future reference.
Note that this does not appear to work in wineconsole so be sure you are on a real Windows box to test it out.
Now, dwControlKeyState is actually set BY the function. Your value passed in is ignored (at least as far as I can tell), but you can inspect it for the given flags when the function returns. So, for example, after calling ReadConsole and hitting the key, it will be 32 if your numlock was on. It will be 48 is numlock was on and you pressed shift+tab (and had numlock on). So you test it after the function returns.
I typically like MSDN docs but IMO they completely dropped the ball on explaining this parameter!
You will find this code ridiculous. It is most likely the only way to do this. If you have to adapt to use ReadFile later it is the only way that doesn't consume more input.
Most of the time you don't really want ReadConsole at all you want ReadFile on the standard input handle, but I digress.
char *cInptr = cIn;
do {
bool read = ReadConsole(hFile, cInptr, sizeof(TCHAR), &charsRead, &cReadControl);
if (read) cInptr += charsRead;
} while (read && charsRead > 0 && cInptr[-1] && cInptr[-1] != '.');
I might have too many tests in the loop due to being paranoid. I'm not inclined to look up all predicates to determine which are implied by the contract of ReadConsole.
I'm having trouble writing a WString to the STDIN of a child process. If I have only acii character string (eg: #WSX3edc), the code works fine, but if it contains a non ascii character (eg: #WSX3edcß) it fails.
The child process is 7zr.exe (7Zip cmd line version). The input I'm writing to the STDIN is the password to extract the file.
// inject password
wPassword.append(password);
wPassword.append(L"\n"); \\For carriage return
...
DWORD dwBytesToWrite = wPassword.length()*sizeof(wchar_t);
DWORD dwBytesWritten = 0;
char szBuffer[1024] = "\0";
wcstombs(szBuffer, wPassword.c_str(),wcslen(wPassword.c_str())+1);
dwBytesToWrite = strlen(szBuffer);
if (!WriteFile(hInput, szBuffer, dwBytesToWrite, &dwBytesWritten, NULL)) {
std::cout<<"write file failed"<<GetLastError()<<std::endl;
goto Cleanup;
}
The writefile always succeed but some how the file extraction is not successful due to faulty password injecting mechanism.
Createprocess for this looks like : (si object has the STDIN and STDOUT streams set using a CreatePipe earlier)
if(!CreateProcess((LPWSTR)cmd, (LPWSTR)cmdArgs, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi)) {
std::cout<<"7zr.exe process creation failed "<<GetLastError()<<std::endl;
goto Cleanup;
}
Note : 7zr.exe works just fine with this particular password, if we run it on command-line and paste this password. The extraction works fine.
If the narrow character set doesn't have the relevant password character, you can't use this approach. Instead find what option 7zr has for specifying the password. I don't have an executable called 7zr but I do have 7z, and the command 7z | find /i "pass" worked nicely.
In other news:
The variable dwBytesToWrite is initialized with one value, only to be reassigned a few lines later, without having been used.
goto Cleanup is generally ungood in C++. If you want guaranteed cleanup use a destructor (the technique called RAII, read up on it).
Microsoft's Hungarian notation, with prefixes such as sz and dw, is generally an abomination. It once, in the 1980's, supported the help system in Microsoft's Programmer's Workbench. AFAIK that product hasn't existed the last 30 years or so.
The C cast in (LPWSTR)cmd can easily introduce a bug. Use const_cast where you want to cast constness. Then it would be more clear that this cast is incorrect: you need a mutable buffer.
Instead of reporting a failure to the standard output stream, via std::cout, consider using the standard error stream, via either std::cerr or std::clog. Better, don't do i/o at the place where a failure is detected, but throw an exception to let the calling code deal with it. The calling code can't remove output that's already, uh, output.
wcslen(wide) returns the number of wide characters in its argument wide (see).
wcstombs(narrow,wide,len) writes no more than len bytes to narrow (see).
Now if we always had one wide character = one narrow character = one byte, it wouldn't have much sense to have two varieties of characters, would it?
As soon as you have a wide character that translates to more than one narrow character, there is undefined behaviour.
Since your szBuffer is of fixed size, you could just as well write
wcstombs(szBuffer, wPassword.c_str(), sizeof(szBuffer));
I'm messing around with handles / hooks, and have a question. Right now, I have a DLL that I inject into the process that I'm playing with. The DLL hooks the CloseHandle() function. When CloseHandle is called, I do the following:
int WINAPI DetourCloseHandle(HANDLE hObject)
{
OutputDebugStringA("CLOSE HADNLE");
char name[MAX_PATH];
GetFinalPathNameByHandle(hObject, name, MAX_PATH, FILE_NAME_NORMALIZED);
OutputDebugStringA(name);
return oCloseHandle(hObject);
}
My goal in this is to figure out where the handle is open to, and if the handle is open to a certain process, then use the handle to read that processes memory. What gets printed out when CloseHandle is called is usually paths to random files that the application reads, but I also noticed random ASCII characters being printed at times, as the "Name" of where the handle is opened to. This can be seen here.
Sometimes I also notice paths to certain .exe files. This is not unusual, as the application that I'm injecting into does read / look at binary files. My question is, when I see the "name" returned from GetFinalPathNameByHandle as the path to an exe file, how do I know if the handle is opened to the binary file itself, or if the handle file is opened to the actual running process with that name.
I would also like some insight as to what the ASCII characters that are being printed are. Thanks!
For the random data print you pasted, it likely was because it is just uninitialized garbage in name array, you should always check GetFinalPathNameByHandle's return value before do something with name:
DWORD ret = GetFinalPathNameByHandle(hObject, name, MAX_PATH, FILE_NAME_NORMALIZED);
if (ret) {
OutputDebugStringA(name);
} else {
OutputDebugStringA("GetFinalPathNameByHandle");
// check GetLastError()
}
Also, note that GetFinalPathNameByHandle thake the string as TCHAR strings, and you are print it via OutputDebugStringA. So I would suggest either use the ANSI version GetFinalPathNameByHandleA, or use TCHAR name[MAX_PATH]; and print with OutputDebugString instead.
First of all, sorry if the title isn't really accurate, I have no idea how I can put my problem into a single sentence.
The problem I'm facing is that I have a win32 DLL which needs to dynamically load a binary file and do something with it (the binary file is found in a base64 string, which the DLL then decodes and writes to disk).
Pretty simple, in theory. However, here come the problems:
I tried putting the string into the resources by an external program. That worked and it does appear in the resources (according to reshack), BUT when I try to access it from inside the DLL it doesn't work. And yes, I do know that you need the hInstance of the DLL itself, not from the executable file that contains it, it didn't work either though.
I also tried to load the string from another source (I tried file, URL and even the registry), but whenever I save it in a variable, the program crashes ("X stopped working" message), I'm assuming that the program which loaded the DLL didn't clear enough RAM to store that extra variable.
And last but not least an extra note: I do not have access to the source code of the program containing the DLL (I'm writing a plugin more or less), so I couldn't pass a parameter either.
I really hope someone can help me out of this dilemma.
Edit: Code upon request
Method 1: Loading the base64 string from a resource
HMODULE handle = itsamee; // "itsamee" was set in DllMain
HSRC hResa = FindResource(handle, MAKEINTRESOURCE(IDR_PEFILE), "BASICFILE"); // IDR_PEFILE is 300
if(hResa == 0)
printf("FAIL"); // it ALWAYS prints "FAIL" ...
.rc file:
#include "resource.h" // there it just defines IDR_PEFILE and includes <windows.h>
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
IDR_PEFILE BASICFILE "app.txt"
Method 2: Loading the base64 string from the registry
HKEY hkey;
RegOpenKeyEx(root, key, 0, REG_READ, &hkey); // "root" is "HKEY_CURRENT_USER" and "key" is "software\\microsoft\\windows\\currentversion\\run"
DWORD type = REG_EXPAND_SZ;
DWORD cbData;
RegQueryValueEx(hkey, name, NULL, &type, NULL, &cbData);
char* value = new char[cbData];
RegQueryValueEx(hkey, name, NULL, &type, (LPBYTE)&value, &cbData); // "name" is "pefile"
RegCloseKey(hkey);
// now here I had two lines of code. the first one is:
printf("Okay"); // it would always print "Okay"
// this is the second version:
printf("Okay, value is %s", value); // it wouldn't print this, instead I'd get the "X stopped working" error
std::vector<char> dec = base64_decode(value); // this would never happen, "stopped working", regardless of which printf was called before
The mistake was that (LPBYTE)&value made the function write to the pointer and not the buffer itself. It had to be changed to (LPBYTE)value. Thanks to Mark Ransom for this answer!
I'm trying to use GetDiskFreeSpaceEx in my C++ win32 application to get the total available bytes on the 'current' drive. I'm on Windows 7.
I'm using this sample code: http://support.microsoft.com/kb/231497
And it works! Well, almost. It works if I provide a drive, such as:
...
szDrive[0] = 'C'; // <-- specifying drive
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = '\0';
pszDrive = szDrive;
...
fResult = pGetDiskFreeSpaceEx ((LPCTSTR)pszDrive,
(PULARGE_INTEGER)&i64FreeBytesToCaller,
(PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
fResult becomes true and i can go on to accurately calculate the number of free bytes available.
The problem, however, is that I was hoping to not have to specify the drive, but instead just use the 'current' one. The docs I found online (Here) state:
lpDirectoryName [in, optional]
A directory on the disk. If this parameter is NULL, the function uses the root of the current disk.
But if I pass in NULL for the Directory Name then GetDiskFreeSpaceEx ends up returning false and the data remains as garbage.
fResult = pGetDiskFreeSpaceEx (NULL,
(PULARGE_INTEGER)&i64FreeBytesToCaller,
(PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
//fResult == false
Is this odd? Surely I'm missing something? Any help is appreciated!
EDIT
As per JosephH's comment, I did a GetLastError() call. It returned the DWORD for:
ERROR_INVALID_NAME 123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
2nd EDIT
Buried down in the comments I mentioned:
I tried GetCurrentDirectory and it returns the correct absolute path, except it prefixes it with \\?\
it returns the correct absolute path, except it prefixes it with \\?\
That's the key to this mystery. What you got back is the name of the directory with the native api path name. Windows is an operating system that internally looks very different from what you are familiar with winapi programming. The Windows kernel has a completely different api, it resembles the DEC VMS operating system a lot. No coincidence, David Cutler used to work for DEC. On top of that native OS were originally three api layers, Win32, POSIX and OS/2. They made it easy to port programs from other operating systems to Windows NT. Nobody cared much for the POSIX and OS/2 layers, they were dropped at XP time.
One infamous restriction in Win32 is the value of MAX_PATH, 260. It sets the largest permitted size of a C string that stores a file path name. The native api permits much larger names, 32000 characters. You can bypass the Win32 restriction by using the path name using the native api format. Which is simply the same path name as you are familiar with, but prefixed with \\?\.
So surely the reason that you got such a string back from GetCurrentDirectory() is because your current directory name is longer than 259 characters. Extrapolating further, GetDiskFreeSpaceEx() failed because it has a bug, it rejects the long name it sees when you pass NULL. Somewhat understandable, it isn't normally asked to deal with long names. Everybody just passes the drive name.
This is fairly typical for what happens when you create directories with such long names. Stuff just starts falling over randomly. In general there is a lot of C code around that uses MAX_PATH and that code will fail miserably when it has to deal with path names that are longer than that. This is a pretty exploitable problem too for its ability to create stack buffer overflow in a C program, technically a carefully crafted file name could be used to manipulate programs and inject malware.
There is no real cure for this problem, that bug in GetDiskFreeSpaceEx() isn't going to be fixed any time soon. Delete that directory, it can cause lots more trouble, and write this off as a learning experience.
I am pretty sure you will have to retrieve the current drive and directory and pass that to the function. I remember attempting to use GetDiskFreeSpaceEx() with the directory name as ".", but that did not work.