Windows System Programming OpenFile function - c++

The documentation for OpenFile function in Windows is located here. And I am trying to do this:
#include "Tchar.h"
#include <windows.h>
int main(int argc, TCHAR *argv[]){
LPOFSTRUCT _buffer;
HFILE _hfile_ = OpenFile("E:\\mozunit.txt", _buffer, OF_READ);
LPVOID _buffer_read;
LPDWORD _bytes_read;
bool flag = ReadFile(_buffer, _buffer_read, 5, _bytes_read, NULL);
CloseHandle(_buffer);
return 0;
}
Now, when I run this I get an error that I have not initialized the _buffer. So to counter that I initialized _buffer like this:
LPOFSTRUCT _buffer = NULL;
Which gives me an access violation error. Why is that?

According to the documentation, the second argument is...
A pointer to the OFSTRUCT structure that receives information about a file when it is first opened.
By setting it to NULL you're attempting to write to memory with the address of zero.
Try this instead:
OFSTRUCT buffer;
HFILE hfile = OpenFile("E:\\mozunit.txt", &buffer, OF_READ);
char buffer_read[6];
DWORD bytes_read = 0;
bool flag = ReadFile(hfile, &buffer_read, 5, &bytes_read, NULL);
CloseHandle(hfile);

You need to pass a pointer to an allocated LPOFSTRUCT object to OpenFile. You are passing NULL to a function that expects a valid memory, not NULL. You declare an OFSTRUCT object and pass a pointer to it to OpenFile
You have the same issue for the parameters that you pass in ReadFile. And you need to call CloseFile on the _hFile_ file handle, not on the _buffer. The same goes for ReadFile Finally you shouldn't be using OpenFile anyway - you should be using CreateFile as the documentation states.
Your code should be something more like:
#include "Tchar.h"
#include <windows.h>
int main(int argc, TCHAR *argv[]){
OFSTRUCT _buffer = {0}; // Create an OFSTRUCT structure local variable and initialize it to zero.
HFILE _hfile_ = OpenFile("E:\\mozunit.txt", &_buffer, OF_READ);
char _buffer_read[5];
DWORD _bytes_read;
bool flag = ReadFile(_hfile_ , _buffer_read, 5, &_bytes_read, NULL);
CloseHandle(_hfile_ );
return 0;
}

Related

MultiByteToWideChar doesn't work properly

I'm trying to use MultiByteToWideChar api. for lpWideCharStr, when I use a pointer with dynamic memory allocation, it works properly. but now I should use a pointer with static memory allocation as you see in the code. and it doesn't work properly, return 0.
what's wrong with it?
how should I use a static memory allocated pointer for lpWideCharStr in MultiByteToWideChar?
thank's for your solutions.
#include <windows.h>
#include <iostream>
#include "Shlwapi.h"
#pragma comment(lib,"shlwapi.lib")
void main(int argc, char *argv[]){
int iToSizeB = 0;
iToSizeB = MultiByteToWideChar(CP_UTF8, 0, argv[1], -1 , NULL, 0);
LPWSTR lpFileAddress[260] = {0};
int nResult = 0;
//MultiByteToWideChar function reurns 0 !!!
nResult = MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, lpFileAddress[0], iToSizeB);
}
Probably you mean this:
WCHAR lpFileAddress[260] = {0};
nResult = MultiByteToWideChar(CP_UTF8, 0, argv[1], -1, lpFileAddress, iToSizeB);
In your code, you define array of WCHAR pointers: LPWSTR lpFileAddress[260] instead of WCHAR array, as required: WCHAR lpFileAddress[260] = {0};

WriteConsole access violation in function call but not from main()

I am trying to use WriteConsole(..) in a function call but I get access violation. When I un-comment the code in main, it prints my text to the screen with no problem in the main function. When I try to print the string in the function call I get access violation even though it does print the text to the console.
void print(char *_charArray);
int _tmain(int argc, _TCHAR* argv[])
{
HWND hConsole;
// HANDLE hFile;
char myText[] = "This is my text";
char *pMyText = myText;
LPDWORD charsWriten;
// hFile = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_READ, NULL,
// OPEN_EXISTING, 0, NULL);
print(pMyText);
// WriteConsole(hFile, myText, sizeof(myText), charsWriten, NULL);
getch();
return 0;
}
void print(char *text)
{
LPDWORD charsWriten;
HANDLE hFile;
hFile = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
unsigned int strn = strlen(text) + 1;
if(!WriteConsole(hFile, text, (strlen(text) + 1), charsWriten,NULL))
{
printf("Write Failed\n");
}
}
This declaration is wrong:
LPDWORD charsWriten;
The CreateFile function expects the fourth parameter to be a pointer to a variable it can write into. You don't actually allocate memory, though; you just declare a pointer—an uninitialized one at that. That won't work. You need to do:
DWORD charsWritten;
...
WriteConsole(hFile, text, (strlen(text) + 1), &charsWritten, NULL)
That will fix the access violation problem, but it doesn't explain why you are writing one character past the end of your string. You don't need to add 1 to strlen; the terminating NUL doesn't need to be written.
LPDWORD charsWriten;
LPDWORD is DWORD*. So what you have there is an uninitialized pointer. You then pass this pointer to WriteConsole, which writes to the invalid location pointed to. Instead, declare charsWritten as type DWORD, and pass its address to WriteConsole with &charsWritten.
DWORD charsWritten;
WriteConsole(hFile, text, (strlen(text) + 1), &charsWritten, NULL);
If, as you say, it works as you have it in main. That is simply bad luck. It's undefined behavior, which doesn't always have predictable results.

Crash when calling ReadFile after LockFileEx

I have several processes that try to read and write the same file. I want each of them to lock the file so that only one of them accesses it at a time.
I tried this (edit: this is a complete test code this time):
#include "stdafx.h"
#include "Windows.h"
bool test()
{
const char* path = "test.txt";
HANDLE hFile = CreateFileA(path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("ERROR: Cannot open file %s\n", path);
return false;
}
// Lock the file
{
OVERLAPPED overlapped = {0};
BOOL res = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, ~0, &overlapped);
if (!res)
{
printf("ERROR: Cannot lock file %s\n", path);
return false;
}
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize > 0)
{
char* content = new char[fileSize+1];
// Read the file
BOOL res = ReadFile(hFile, content, fileSize, NULL, NULL);
if (!res)
{
printf("ERROR: Cannot read file %s\n", path);
}
delete[] content;
}
const char* newContent = "bla";
int newContentSize = 3;
// Write the file
BOOL res = WriteFile(hFile, newContent, newContentSize, NULL, NULL);
if (!res)
{
//int err = GetLastError();
printf("ERROR: Cannot write to file\n");
}
// Unlock the file
{
OVERLAPPED overlapped = {0};
UnlockFileEx(hFile, 0, ~0, ~0, &overlapped);
}
CloseHandle(hFile);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool res = test();
return 0;
}
This works fine on my computer, which has Windows 8. But on my colleague's computer, which has Windows 7, it crashes. Specifically, the calls to ReadFile and WriteFile crash, always.
Note that it never enters the code paths with the error printfs. This code triggers no error except for a write at location 0x00000000 in ReadFile (when run on Windows 7).
We tried to also pass the overlapped struct to the ReadFile and WriteFile calls. It prevents the crash but the lock doesn't work anymore, the file is all scrambled (not with this test code, with the real code).
What am I doing wrong?
Looks like your problem is:
lpNumberOfBytesRead [out, optional] argument is null in your call.
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Heres your problem :
You are missing a necessary struct-member and:
0 and ~0 and {0} are all bad code, constant expressions like these will always produce unepected results -- WINAPI doesnt work like libc, parameters are not always compared against constants, instead they are tested against/via macros and other preprocessor-definitions themselves so passing constant values or initializing WINAPI structs with constants will often lead to errors like these.
After years of experimenting i have found that there is only one surefire way of avoiding them, i will express it in corrected code :
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent( ........... ); // put valid parameters here!
UnlockFileEx(hFile, 0 /*"reserved"*/, ULONG_MAX, ULONG_MAX, &overlapped);
please read this carefully : http://msdn.microsoft.com/en-us/library/windows/desktop/aa365716%28v=vs.85%29.aspx

C++ read Registry

i try to read the Registry in my NPAPI-Plugin:
bool ScriptablePluginObject::Invoke(NPObject* obj, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) {
ScriptablePluginObject *thisObj = (ScriptablePluginObject*) obj;
char* name = npnfuncs->utf8fromidentifier(methodName);
LPCWSTR game_path = getRegKey(L"SOFTWARE\\World of RPG", L"Path");
MessageBox(NULL, game_path, L"Debugging", MB_TOPMOST);
/* ... */
}
LPCWSTR ScriptablePluginObject::getRegKey(LPCWSTR location, LPCWSTR name) {
HKEY hKey;
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
long registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, location, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
long entry = RegQueryValueEx(hKey, name, NULL, REG_NONE, folder, &dwSize);
if(registry != ERROR_SUCCESS) {
return L"Error1";
}
if(entry != ERROR_SUCCESS) {
return L"Error2";
}
RegCloseKey(hKey);
folder[dwSize / sizeof(folder[0])] = '\0';
return (LPCWSTR) folder;
}
But it's returned every call Error2. I've tried a lot of changes:
change the Path (with Start and/or Ending \\)
change parameters
I Want to get the Path of HKEY_LOCAL_MACHINE\SOFTWARE\World of RPG\Path:
Anyone can help me? What i'm doing wrong?
Here's the sample I mentioned in the comments above:
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, DWORD *pBufferSize );
int _tmain(int argc, _TCHAR* argv[])
{
const int BUFFER_SIZE = 1024;
WCHAR sBuffer[BUFFER_SIZE]; // 2048 bytes
DWORD nBufferSize = BUFFER_SIZE * sizeof ( WCHAR );
ZeroMemory ( sBuffer, nBufferSize );
LSTATUS nResult = ReadRegistry ( L"SOFTWARE\\7-Zip", L"Path64",
sBuffer, &nBufferSize );
// check nResult for ERROR_SUCCESS to know if the call succeeded or not
return 0;
}
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, LPDWORD pBufferSize )
{
HKEY hKey;
LSTATUS nResult = ::RegOpenKeyEx ( HKEY_LOCAL_MACHINE, sPath,
0, KEY_READ | KEY_WOW64_64KEY, &hKey );
if ( nResult == ERROR_SUCCESS )
{
nResult = ::RegQueryValueEx ( hKey, sKey, NULL, NULL,
(LPBYTE) pBuffer, pBufferSize );
RegCloseKey ( hKey );
}
return ( nResult );
}
Notice how the ReadRegistry function doesn't allocate memory - it takes a buffer and fills it with data. It's a lot easier to deal with memory if you always have the caller allocate memory. If the callee allocates memory, the caller may not know how memory was allocated and it may not know how to free it. (Of course, you can always assume the use of new and delete but things are simpler if only one side does this consistently. If the caller allocates memory, it'll know how to free it. The callee only needs to put data in the allocated space.
Also, notice how the return value of the API functions is checked before proceeding to the next call - this is important because this tells you if you got a useful registry handle back or not and whether you need to close it or not.
(This sample is really just C, not C++ but it still applies.)
In getRegKey(), your folder variable is a pointer, so sizeof(folder) is 4 (if compiling for 32bit) or 8 (if compiling for 64bit). Thus RegQueryValueEx() fails with an ERROR_MORE_DATA error code.
You are also using the wrong data type for the array. You need to use WCHAR instead of BYTE.
Change this:
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
To this:
LPWSTR folder = new WCHAR[MAX_PATH];
DWORD dwSize = sizeof(WCHAR) * MAX_PATH;
With that said, you are leaking the memory pointed to by folder, since you never delete[] it.

Visual Studio errors and getting a device GUID and path name?

Evening everyone I wondered if some could answer me 2 quick questions.
I made an app to communicate with arm device which works fine, however when I move PC etc, I need to reconfigure the device path. Its a long one like below.
Path: \\?\usb#vid_045e&pid_0040#6&ff454f2&0&3#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
I done some reading up and discovered it's two features SetupDiGetClassDevs and SetupDiGetDeviceInstanceId I need. My question is am I looking in the right place i.e will these 2 functions return the path like above. Also what is the techinical name for this path?
I found what I think is a nice example (always learn better from example) on Microsoft's website cut and paste below but this throws up error C2440: '=' : cannot convert from 'HLOCAL' to 'LPTSTR'
which is a new one on me a pointer error?
This is the code
#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <regstr.h>
int main( int argc, char *argv[ ], char *envp[ ] )
{
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
DWORD i;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return 1;
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i=0;SetupDiEnumDeviceInfo(hDevInfo,i,
&DeviceInfoData);i++)
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_DEVICEDESC,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = LocalAlloc(LPTR,buffersize * 2); // ERROR LINE
}
else
{
// Insert error handling here.
break;
}
}
printf("Result:[%s]\n",buffer);
if (buffer) LocalFree(buffer);
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS )
{
// Insert error handling here.
return 1;
}
// Cleanup
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}
Hope its an easy one thank you.
You need to typecast the return value from LocalAlloc():
buffer = (LPSTR) LocalAlloc(LPTR,buffersize * 2);
For more info, see the LocalAlloc() documentation on MSDN.