ReadFile/WriteFile crahes - winapi

Something wrong with next ReadFile/WriteFile code.
I need to use copy file by using this functions (yes, it's better to use CopyFile, but now I need it), but it crashed at read/write loop.
What can be wrong?
PS C:\Users\user\Documents\SysLab1\dist\Debug\MinGW-Windows> g++ --version
g++.exe (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project) 4.8.3
I used next code :
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define BLOCK_SIZE 1024
uint32_t copy_c(char* source, char* destination) {...}
uint32_t copy_api_readwrite(char* source, char* destination) {
bool result;
HANDLE input = CreateFile(source, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (input!=INVALID_HANDLE_VALUE) {
HANDLE output = CreateFile(destination, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(output!=INVALID_HANDLE_VALUE) {
DWORD readed;
char block[BLOCK_SIZE];
while(ReadFile(input, block, BLOCK_SIZE * sizeof(char), &readed, NULL)>0) {
WriteFile(output, block, readed, NULL, NULL);
}
if(GetLastError()==ERROR_HANDLE_EOF) {
result = true;
}
else {
result = false;
}
CloseHandle(output);
}
else {
result = false;
}
CloseHandle(input);
}
else {
result = true;
}
if(result) {
return 0;
}
else {
return GetLastError();
}
return result;
}
uint32_t copy_api(char* source, char* destination) {...}
#define COPY_READWRITE
#ifdef COPY_C
#define COPY copy_c
#else
#ifdef COPY_READWRITE
#define COPY copy_api_readwrite
#else
#ifdef COPY_API
#define COPY copy_api
#endif
#endif
#endif
int main(int argc, char** argv) {
if(argc<3) {
std::cout << "Bad command line arguments\n";
return 1;
}
uint32_t result = COPY(argv[1], argv[2]);
if(result==0) {
std::cout << "Success\n";
return 0;
}
else {
std::cout << "Error : " << result << "\n";
return 2;
}
}

From the documentation of WriteFile:
lpNumberOfBytesWritten
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
You are not meeting that requirement. You will have to pass the address of a DWORD variable into which the number of bytes written will be stored.
Another mistake is in the test of the return value of ReadFile. Instead of testing ReadFile(...) > 0 you must test ReadFile(...) != 0, again as described in the documentation.
You don't check the return value of WriteFile which I also would regard as a mistake.
By definition, sizeof(char) == 1. It is idiomatic to make use of that.
When dealing with binary data, as you are, again it is idiomatic to use unsigned char.
More idiom. Write the assignment of result like this:
result = (GetLastError() == ERROR_HANDLE_EOF);

Related

Getting Enviroment Variable with cpp

So I have been trying to figure out how to find an environment variable and print it out on the screen in c++
but for the last 3 hours or so, I have been stuck. When I print out the currentDesktop variable it only prints out "/Desktop". But what I'm looking for is the username in front of it.
I have been reading the documentation on the GetEnviromentVariable function from Microsoft's forum and this is what I have come up with so far.
Help would be greatly appreciated since I'm not so experienced yet, Thx.
#include <iostream>
#include <string>
#include <windows.h>
#include <fstream>
#define BUFSIZE 4096
using namespace std;
int main()
{
LPCWSTR Env = L"%USERPROFILE";
LPTSTR pszOldVal;
string IPADD;
pszOldVal = (LPTSTR)malloc(BUFSIZE * sizeof(TCHAR));
if (NULL == pszOldVal)
{
printf("Out of memory\n");
return FALSE;
}
string currentDesktop = GetEnvironmentVariable(Env,pszOldVal,BUFSIZE) + "\\Desktop";
cout << currentDesktop;
return 0;
}
You are misusing the GetEnvironmentVariable() function. For one thing, you are missing the trailing % on the variable name L"%USERPROFILE". For another thing, the return value is the number of characters copied into the supplied buffer. You are adding that integer to the string literal "\\Desktop", which is not what you want.
Try this instead:
#include <iostream>
#include <string>
#include <windows.h>
std::wstring GetEnv(const std::wstring &varName)
{
std::wstring str;
DWORD len = GetEnvironmentVariableW(varName.c_str(), NULL, 0);
if (len > 0)
{
str.resize(len);
str.resize(GetEnvironmentVariableW(varName.c_str(), &str[0], len));
}
return str;
}
std::wstring GetUserDesktopPath()
{
std::wstring path = GetEnv(L"%USERPROFILE%");
if (!path.empty()) path += L"\\Desktop";
return path;
}
int main()
{
std::wstring currentDesktop = GetUserDesktopPath();
std::wcout << currentDesktop;
return 0;
}
That being said, if you just want the username, use %USERNAME% instead of %USERPROFILE%. Or better, use GetUserName() instead of GetEnvironmentVariable():
#include <iostream>
#include <string>
#include <windows.h>
std::wstring GetUserName()
{
std::wstring str;
DWORD len = 0;
if (!GetUserNameW(NULL, &len))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
str.resize(len);
if (GetUserNameW(&str[0], &len))
str.resize(len-1);
else
str = L"";
}
}
return str;
}
int main()
{
std::wstring currentUser = GetUserName();
std::wcout << currentUser;
return 0;
}
However, the correct way to get the path to the user's desktop is to just ask Windows for that specific path, don't assume it is in the root of the user's profile, or that is is named Desktop. Use SHGetFolderPath() or SHGetKnownFolderPath() for that query, eg:
#include <iostream>
#include <string>
#include <windows.h>
#include <shlobj.h>
std::wstring GetFolderPath(CSIDL folderID)
{
WCHAR path[MAX_PATH] = {};
SHGetFolderPathW(NULL, folderID, NULL, SHGFP_TYPE_CURRENT, path);
return path;
}
/* or:
std::wstring GetFolderPath(REFKNOWNFOLDERID folderID)
{
std::wstring str;
PWSTR path = NULL;
if (SHGetKnownFolderPath(folderID, 0, NULL, &path) == S_OK)
str = path;
CoTaskMemFree(path);
return str;
}
*/
std::wstring GetUserDesktopPath()
{
return GetFolderPath(CSIDL_DESKTOPDIRECTORY);
// or: return GetFolderPath(FOLDERID_Desktop);
}
int main()
{
std::wstring currentDesktop = GetUserDesktopPath();
std::wcout << currentDesktop;
return 0;
}

ReadDirectoryChangesW not notifying when moving the files

I’m new to this windows API. I’m a GUI developer in my project i need to monitor a particular folder . I have followed every steps in the Windows API using ReadDirectoryChangeW but ReadDirectoryChangeW is not notifying me when the file is moved to other directory (cut/paste or delete to move to trash).at least it should notify as FILE_ACTION_RENAMED
It is windows 7 and ReadDirectorChangeW is working on normal copy,paset,shift+delete,rename
this code is written in Qt c++ where QString is char *
this is my code
#include <windows.h>
#include <Winbase.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <qDebug>
#include <QThread>
#define MAX_DIRS 200
#define MAX_FILES 255
#define MAX_BUFFER 4096
#if 0
extern "C" {
WINBASEAPI BOOL WINAPI
ReadDirectoryChangesW( HANDLE hDirectory,
LPVOID lpBuffer, DWORD nBufferLength,
BOOL bWatchSubtree, DWORD dwNotifyFilter,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
}
#endif
class WatcherThread : public QThread
{
Q_OBJECT
public:
WatcherThread(LPCWSTR dir)
{
path = dir;
}
void run() Q_DECL_OVERRIDE {
QString newDirName;
char buf[2048];
DWORD nRet;
BOOL result=TRUE;
char filename[MAX_PATH];
//path = L"K:/Demo/bb";
wchar_t* arr = (wchar_t*)path;
printf("\nThe file directory: [%s] \n", path);
qDebug() << "WatchDirectory Watcher Path " << QString::fromWCharArray(arr);
DirInfo[0].hDir = CreateFile (path, GENERIC_READ|FILE_LIST_DIRECTORY,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if(DirInfo[0].hDir == INVALID_HANDLE_VALUE)
{
qDebug() << "Can not open";
return;
}
lstrcpy( DirInfo[0].lpszDirName, path);
OVERLAPPED PollingOverlap;
FILE_NOTIFY_INFORMATION pNotify[1024];
int offset;
PollingOverlap.OffsetHigh = 0;
PollingOverlap.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
while(result)
{
result = ReadDirectoryChangesW(
DirInfo[0].hDir,// handle to the directory to be watched
(LPVOID)&pNotify,// pointer to the buffer to receive the read results
sizeof(pNotify),// length of lpBuffer
1,// flag for monitoring directory or directory tree
FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE ,
&nRet,// number of bytes returned
&PollingOverlap,// pointer to structure needed for overlapped I/O
NULL);
WaitForSingleObject(PollingOverlap.hEvent,INFINITE);
// if(result)
// {
offset = 0;
int rename = 0;
char oldName[260];
char newName[260];
do
{
//pNotify = (FILE_NOTIFY_INFORMATION*)((char*)buf + offset);
strcpy(filename, "");
int filenamelen = WideCharToMultiByte(CP_ACP, 0, pNotify[offset].FileName, pNotify[offset].FileNameLength/2, filename, sizeof(filename), NULL, NULL);
//filename[pNotify->FileNameLength/2] = ' ';
switch(pNotify[offset].Action)
{
case FILE_ACTION_ADDED:
qDebug() << "The FILE_ACTION_ADDED***********" << QString(filename).left(filenamelen);
emit onFileCopy(QString(filename).left(filenamelen));
break;
case FILE_ACTION_MODIFIED:
qDebug() << "The FILE_ACTION_MODIFIED" << QString(filename).left(filenamelen);
break;
case FILE_ACTION_REMOVED:
qDebug() << "The FILE_ACTION_REMOVED" << QString(filename).left(filenamelen);
emit onFileRemove(QString(filename).left(filenamelen));
break;
case FILE_ACTION_RENAMED_OLD_NAME:
qDebug() << "The FILE_ACTION_RENAMED_OLD_NAME" << QString(filename).left(filenamelen);
break;
case FILE_ACTION_RENAMED_NEW_NAME:
newDirName = QString(filename).left(filenamelen);
qDebug() << "The FILE_ACTION_RENAMED_NEW_NAME" << newDirName;
emit onDirRename(newDirName);
break;
default:
printf("\nDefault error.\n");
break;
}
//qDebug() << "pNotify->NextEntryOffset" << pNotify[offset].NextEntryOffset <<" offset "<< offset << nRet ;
offset += pNotify[offset].NextEntryOffset;
}while(pNotify[offset].NextEntryOffset); //(offset != 0)
ResetEvent(PollingOverlap.hEvent);
}
CloseHandle( DirInfo[0].hDir );
}
public:
signals:
void onDirRename(QString Dir);
void onFileRemove(QString name);
void onFileCopy(QString name);
private:
LPCWSTR path;
typedef struct _DIRECTORY_INFO {
HANDLE hDir;
TCHAR lpszDirName[MAX_PATH];
CHAR lpBuffer[MAX_BUFFER];
DWORD dwBufLength;
OVERLAPPED Overlapped;
}DIRECTORY_INFO, *PDIRECTORY_INFO, *LPDIRECTORY_INFO;
DIRECTORY_INFO DirInfo[MAX_DIRS];
TCHAR FileList[MAX_FILES*MAX_PATH];
DWORD numDirs;
};
It is a Qt based object. the path is the directory i will monitor and update any changes happens.

Possible to capture unhandled exception in win32 user application ? (setunhandledexceptionfilter())

I spent much time to capture unhandled exceptions in my process (win32) using API so called setunhandledexceptionfilter().
But I haven't captured exception when WER(Windows Error Report - which is well know for DR.watson) is showed.
Is impossible to catch all of exceptions without third-party in my APP?
I think that there is method for handling, but I don't get it.
I am not accustomed to Windows DEV environment. that's why I lost my mental in googling.
Below is my test-case in vc110(Visual Studio 2012).
chat test[65];
int main() {
// after attaching unhandled exception call-back using setunhandledexceptionfilter()
// die point (ACCESS_VIOLATION c0000005)
for (int k=0; k<1000000; k++)
test[k]=65;
My callback isn't called after WER(windows Error Report) occurs. It doesn't work as my intend.
*But strcpy(NULL, "TEST") which is okay (SUCCESS)*
Below is my source code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/stat.h>
#include <assert.h>
#include <process.h>
#include <direct.h>
#include <conio.h>
#include <time.h>
#include <Windows.h>
#include <tchar.h>
#include <dbghelp.h>
#include <stdio.h>
#include <crtdbg.h>
#include <WinBase.h>
#pragma comment ( lib, "dbghelp.lib" )
void CreateMiniDump( EXCEPTION_POINTERS* pep );
BOOL CALLBACK MyMiniDumpCallback(
PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput
);
///////////////////////////////////////////////////////////////////////////////
// Minidump creation function
//
#if 0
LONG WINAPI lpTopLevelExceptionFilter(EXCEPTION_POINTERS* ExceptionInfo);
#endif
void CreateMiniDump( EXCEPTION_POINTERS* pep )
{
time_t t;
struct tm *tinfo;
wchar_t dump_name[128];
HANDLE hFile;
time(&t);
tinfo = localtime(&t);
wcsftime(dump_name, 128, L"MiniDump[%Y%m%d][%H_%M_%S].dmp", tinfo);
// file format MiniDump[YYYYMMDD][HH_MM_SEC]
hFile = CreateFile(dump_name, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
{
// Create the minidump
MINIDUMP_EXCEPTION_INFORMATION mdei;
MINIDUMP_CALLBACK_INFORMATION mci;
MINIDUMP_TYPE mdt;
BOOL rv;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pep;
mdei.ClientPointers = FALSE;
mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
mci.CallbackParam = 0;
mdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory| MiniDumpWithThreadInfo);
rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci );
if( !rv )
_tprintf( _T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError() );
else
_tprintf( _T("Minidump created.\n") );
// Close the file
CloseHandle( hFile );
}
else
{
_tprintf( _T("CreateFile failed. Error: %u \n"), GetLastError() );
}
}
///////////////////////////////////////////////////////////////////////////////
// Custom minidump callback
//
BOOL CALLBACK MyMiniDumpCallback(
PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput
)
{
BOOL bRet = FALSE;
// Check parameters
if( pInput == 0 )
return FALSE;
if( pOutput == 0 )
return FALSE;
// Process the callbacks
switch( pInput->CallbackType )
{
case IncludeModuleCallback:
{
// Include the module into the dump
bRet = TRUE;
}
break;
case IncludeThreadCallback:
{
// Include the thread into the dump
bRet = TRUE;
}
break;
case ModuleCallback:
{
// Does the module have ModuleReferencedByMemory flag set ?
if( !(pOutput->ModuleWriteFlags & ModuleReferencedByMemory) )
{
// No, it does not - exclude it
wprintf( L"Excluding module: %s \n", pInput->Module.FullPath );
pOutput->ModuleWriteFlags &= (~ModuleWriteModule);
}
bRet = TRUE;
}
break;
case ThreadCallback:
{
// Include all thread information into the minidump
bRet = TRUE;
}
break;
case ThreadExCallback:
{
// Include this information
bRet = TRUE;
}
break;
case MemoryCallback:
{
// We do not include any information here -> return FALSE
bRet = FALSE;
}
break;
case CancelCallback:
break;
}
return bRet;
}
LONG WINAPI exception_filter_func(EXCEPTION_POINTERS* pep)
{
if (pep == NULL) {
return EXCEPTION_EXECUTE_HANDLER;
}
if (pep->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CreateMiniDump, pep, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
} else {
CreateMiniDump(pep);
}
return EXCEPTION_EXECUTE_HANDLER;
}
char test[65];
int main(int argc, char **argv)
{
int k;
SetUnhandledExceptionFilter(exception_filter_func);
// exception occured (ACCESS_VIOLATION)
for (k=0; k<1000000; k++)
test[k]=65;
}

Convert a char * to inizialite an entity of type LPCTSTR for RegCreateKeyEx

I know I am a Windows programming nob, so I am just learning.
I am writing a Command Line tool to work with some of the Registry Functions of the Windows API, but I need to convert a char * that comes from an argv[] array to initialize a LPCTSTR variable with the content but I don't know how to do that.
This is the code I have so far:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int main(int argc, char *argv [])
{
int count;
DWORD Reserved = 0;
LPTSTR lpClass = NULL;
DWORD dwOptions = REG_OPTION_NON_VOLATILE;
REGSAM samDesired = KEY_ALL_ACCESS;
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
HKEY phkResult;
DWORD lpdwDisposition;
if (argv[1] == 0)
{
printf("There are no arguments, pleas type one at least. \n");
}
else if (std::string(argv[1]) == "-Clave")
{
if (std::string(argv[2]) == "HKCU")
{
printf("You are going to create a HKCU sub-key \n");
HKEY hKey = HKEY_CURRENT_USER;
if (std::string(argv[3]) != "")
{
printf("You are going to create this sub-key: %s \n",argv[3]);
//This is what I tried.
LPCTSTR lpSubKey = TEXT("%s",argv[3]);
RegCreateKeyEx(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired, lpSecurityAttributes, &phkResult, &lpdwDisposition);
if (lpdwDisposition == REG_CREATED_NEW_KEY)
{
printf("The registry key has been created. \n");
}
}
else
printf("No one");
}
else
{
printf("No key has been specified \n");
}
}
system("Pause");
}
Can you help me out?
Thanks a lot.
Have a look at the MultiByteToWideChar function in Windows.h. Here's a nice and quick example:
const char * orig = "text1";
WCHAR buffer[6];
MultiByteToWideChar(0, 0, orig, 5, buffer, 6 );
LPCWSTR text = buffer;
Whoops, that's for LPCWSTR. For LPCTSTR, just use :
LPCTSTR text = _T("text1");
Another possible solution is to change main function declaration in this way :
int _tmain(int argc, TCHAR* argv[])
Quote from MSDN :
You can also use _tmain, which is defined in TCHAR.h. _tmain resolves
to main unless _UNICODE is defined. In that case, _tmain resolves to
wmain.
Second parameter on RegCreateKeyEx is on type* LPCTSTR.
lpSubKey is declared by the same type and will be initialized properly when passed as an argument to the RegCreateKeyEx function .
Here is your source code compiled with Visual C++, and uses Multi-byte Character Set (_MBCS macro is defined) :
// RegCreate.cpp : Defines the entry point for the console application.
// VC++ Compiler Options :
// cl /W3 /MT /O2 /D WIN32 /D _CONSOLE /D _MBCS /EHsc /TP RegCreate.cpp
#include <Windows.h>
#include <iostream>
#include <string>
#include <tchar.h>
#ifndef _MBCS
#define _MBCS
#endif
#pragma comment(lib, "Advapi32.lib")
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
DWORD Reserved = 0;
LPTSTR lpClass = NULL;
DWORD dwOptions = REG_OPTION_NON_VOLATILE;
REGSAM samDesired = KEY_ALL_ACCESS;
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
HKEY phkResult;
DWORD lpdwDisposition;
if(argc < 3)
{
std::cout << "There are no arguments, pleas type one at least. " << std::endl;
return 1;
}
if((std::string(argv[1]) == "-Clave") && (std::string(argv[2]) == "HKCU") && (argc == 4))
{
std::cout << "You are going to create a HKCU sub-key " << std::endl;
HKEY hKey = HKEY_CURRENT_USER;
if(std::string(argv[3]) != "")
{
std::cout << "You are going to create this sub-key: " << argv[3] << std::endl;
//This is what I tried.
LPCTSTR lpSubKey = argv[3];
if(ERROR_SUCCESS != RegCreateKeyEx(hKey, lpSubKey, Reserved, lpClass, dwOptions, samDesired,
lpSecurityAttributes, &phkResult, &lpdwDisposition))
{
return 1;
}
if(lpdwDisposition == REG_CREATED_NEW_KEY)
{
std::cout << "The registry key has been created. " << std::endl;
}
RegCloseKey(phkResult);
}
else
{
std::cout << "No one";
}
}
else
{
std::cout << "No key has been specified " << std::endl;
}
return 0;
}
We can use the TEXT macro to define a string as being Unicode or not, but in the above example this is not necessary .
If you use C++ I suggest you to change printf with std::cout, that works with ASCII characters .
The simplest solution is to explicitly call the Ansi versions of the Registry functions (RegCreateKeyExA, etc) and let Windows handle the conversions for you. You are currently calling the Unicode versions of the functions (RegCreateKeyExW, etc), or you wouldn't be having conversion problems in the first place:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int main(int argc, char *argv [])
{
int count;
HKEY hkResult;
DWORD dwDisposition;
if (argc < 1)
{
printf("There are no arguments, pleas type one at least. \n");
}
else if (strcmp(argv[1], "-Clave") == 0)
{
if (argc < 3)
{
printf("There are not enough arguments typed in. \n");
}
else if (strcmp(argv[2], "HKCU") == 0)
{
if (strcmp(argv[3], "") != 0)
{
printf("You are going to create HKCU sub-key: %s \n", argv[3]);
if (RegCreateKeyExA(HKEY_CURRENT_USER, argv[3], 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkResult, &dwDisposition) == 0)
{
if (dwDisposition == REG_CREATED_NEW_KEY)
{
printf("The registry key has been created. \n");
}
else
{
printf("The registry key already exists. \n");
}
RegCloseKey(hkResult);
}
else
{
printf("Unable to create the registry key. \n");
}
}
else
{
printf("No HKCU sub-key has been specified \n");
}
}
else
{
printf("No root key has been specified \n");
}
}
system("Pause");
return 0;
}
Update: If you want to be politically correct, most Win32 APIs that deal with text data actually deal with TCHAR (which is what you were attempting to use, but not successfully) so that they can be compiled for both Ansi and Unicode with a single codebase, eg:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <tchar.h>
int _tmain(int argc, TCHAR *argv [])
{
int count;
HKEY hkResult;
DWORD dwDisposition;
if (argc < 1)
{
_tprintf(_T("There are no arguments, pleas type one at least. \n"));
}
else if (_tcscmp(argv[1], _T("-Clave")) == 0)
{
if (argc < 3)
{
_tprintf(_T("There are not enough arguments typed in. \n"));
}
else if (_tcsicmp(argv[2], _T("HKCU")) == 0)
{
if (_tcscmp(argv[3], _T("")) != 0)
{
_tprintf(_T("You are going to create HKCU sub-key: %s \n"), argv[3]);
if (RegCreateKeyEx(HKEY_CURRENT_USER, argv[3], 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkResult, &dwDisposition) == 0)
{
if (dwDisposition == REG_CREATED_NEW_KEY)
{
_tprintf(_T("The registry key has been created. \n"));
}
else
{
_tprintf(_T("The registry key already exists. \n"));
}
RegCloseKey(hkResult);
}
else
{
_tprintf(_T("Unable to create the registry key. \n"));
}
}
else
{
_tprintf(_T("No HKCU sub-key has been specified \n"));
}
}
else
{
_tprintf(_T("No root key has been specified \n"));
}
}
_tsystem(_T("Pause"));
return 0;
}
With that said, since you are starting a new project, you are best off forgetting that Ansi even exists and just use Unicode for everything:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int wmain(int argc, WCHAR *argv [])
{
int count;
HKEY hkResult;
DWORD dwDisposition;
if (argc < 1)
{
wprintf(L"There are no arguments, pleas type one at least. \n");
}
else if (wcscmp(argv[1], L"-Clave") == 0)
{
if (argc < 3)
{
wprintf(L"There are not enough arguments typed in. \n");
}
else if (_wcsicmp(argv[2], L"HKCU") == 0)
{
if (wcscmp(argv[3], L"") != 0)
{
wprintf(L"You are going to create HKCU sub-key: %s \n", argv[3]);
if (RegCreateKeyExW(HKEY_CURRENT_USER, argv[3], 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkResult, &dwDisposition) == 0)
{
if (dwDisposition == REG_CREATED_NEW_KEY)
{
wprintf(L"The registry key has been created. \n");
}
else
{
wprintf(L"The registry key already exists. \n");
}
RegCloseKey(hkResult);
}
else
{
wprintf(L"Unable to create the registry key. \n");
}
}
else
{
wprintf(L"No HKCU sub-key has been specified \n");
}
}
else
{
wprintf(L"No root key has been specified \n");
}
}
_wsystem(L"Pause");
return 0;
}

Simple multithreading mutex example is incorrect

I expect to get numbers from 0 to 4 in random order, but instead, I have some unsynchronized mess
What i do wrong?
#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;
void addQuery(void *v );
HANDLE ghMutex;
int main()
{
HANDLE hs[5];
ghMutex = CreateMutex( NULL, FALSE, NULL);
for(int i=0; i<5; ++i)
{
hs[i] = (HANDLE)_beginthread(addQuery, 0, (void *)&i);
if (hs[i] == NULL)
{
printf("error\n"); return -1;
}
}
printf("WaitForMultipleObjects return: %d error: %d\n",
(DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());
return 0;
}
void addQuery(void *v )
{
int t = *((int*)v);
WaitForSingleObject(ghMutex, INFINITE);
cout << t << endl;
ReleaseMutex(ghMutex);
_endthread();
}
You have to read and write the shared variable inside the lock. You are reading it outside of the lock and thus rendering the lock irrelevant.
But even that's not enough since your shared variable is a loop variable that you are writing to without protection of the lock. A much better example would run like this:
#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;
void addQuery(void *v );
HANDLE ghMutex;
int counter = 0;
int main()
{
HANDLE hs[5];
ghMutex = CreateMutex( NULL, FALSE, NULL);
for(int i=0; i<5; ++i)
{
hs[i] = (HANDLE)_beginthread(addQuery, 0, NULL);
if (hs[i] == NULL)
{
printf("error\n"); return -1;
}
}
printf("WaitForMultipleObjects return: %d error: %d\n",
(DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());
return 0;
}
void addQuery(void *v)
{
WaitForSingleObject(ghMutex, INFINITE);
cout << counter << endl;
counter++;
ReleaseMutex(ghMutex);
_endthread();
}
If you can, use a critical section rather than a mutex because they are simpler to use and more efficient. But they have the same semantics in that they only protect code inside the locking block.
Note: Jerry has pointer out some other problems, but I've concentrated on the high level trheading and serialization concerns.
Your synchronization has some issues as you want to get numbers from 0 to 4 in random order.
The problem is that the variable i is write outside the lock and every time the addQuery method get called by the execution of a thread, it get the modified version of variable i. That why you may see 5 as the value at the output for all.
So, here is my fix for this scenario. Instead of pass the address of variable i in parameters of the function addQuery, you should pass it's value. Hope it helps:
#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;
void addQuery(void *v);
HANDLE ghMutex;
int main()
{
HANDLE hs[5];
ghMutex = CreateMutex(NULL, FALSE, NULL);
for (int i = 0; i<5; ++i)
{
hs[i] = (HANDLE)_beginthread(addQuery, 0, (void *)i);
if (hs[i] == NULL)
{
printf("error\n"); return -1;
}
}
printf("WaitForMultipleObjects return: %d error: %d\n",
(DWORD)WaitForMultipleObjects(5, hs, TRUE, INFINITE), GetLastError());
return 0;
}
void addQuery(void *v)
{
int t = (int)v;
WaitForSingleObject(ghMutex, INFINITE);
cout << t << endl;
ReleaseMutex(ghMutex);
_endthread();
}

Resources