Getting Enviroment Variable with cpp - winapi

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;
}

Related

How can I decrypt a string using CryptUnprotectData

I have been trying to decrypt some encrypted data (AES key encrypting chrome cookies) via the c++ CryptUnprotectData function for a short while now, but I cant seem to get it working. Currently the function will fail and return an error code of 13 (meaning "The parameter is incorrect."). Here is my code so far:
#include <iostream>
#include <Windows.h>
#include <wincrypt.h>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
std::string GetLastErrorAsString()
{
DWORD errorMessageID = ::GetLastError();
if(errorMessageID == 0) {
return std::string();
}
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
return message;
}
int main()
{
string data = "(data I want to decode)";
cout << data;
DATA_BLOB DataBytes;
DataBytes.pbData = (BYTE*)data.data();
DataBytes.cbData = (DWORD)data.size()+1;
DATA_BLOB output;
output.pbData = NULL;
output.cbData = (DWORD)data.size();
CryptUnprotectData(&DataBytes, NULL, NULL, NULL, NULL, 0, &output);
cout << GetLastErrorAsString() << endl;
cout << output.pbData;
LocalFree(output.pbData);
return 0;
}
If anyone can provide any help, that would be greatly appreciated.
I have tried different variations of the data types the parameters are stored in, although it still returns this error.
I modified your code, which is as follows. It only implements simple decryption.
And the data is not encrypted, so CryptUnprotectData() does not return the correct value.
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#pragma comment (lib, "Crypt32.lib")
int main()
{
// Decrypt data from DATA_BLOB DataOut to DATA_BLOB DataVerify.
//--------------------------------------------------------------------
// Declare and initialize variables.
string data = ("data I want to decode \n");
cout << data;
LPWSTR pDescrOut = NULL;
DATA_BLOB DataBytes;
BYTE* pbDataOutput = (BYTE*)data.data();
DWORD cbDataOutput = strlen((char*)pbDataOutput) + 1;
DataBytes.pbData = pbDataOutput;
DataBytes.cbData = cbDataOutput;
//DATA_BLOB DataVerify;
//--------------------------------------------------------------------
// The buffer DataOut would be created using the CryptProtectData
// function. If may have been read in from a file.
//--------------------------------------------------------------------
// Begin unprotect phase.
BOOL res = CryptUnprotectData(
&DataBytes,
&pDescrOut,
NULL, // Optional entropy
NULL, // Reserved
NULL, // Here, the optional
// prompt structure is not
// used.
0,
&DataBytes);
if (res==1)
{
printf("The decrypted data is: %s\n", DataBytes.pbData);
printf("The description of the data was: %s\n", pDescrOut);
}
else
{
printf("Decryption error!");
}
// LocalFree(DataVerify.pbData);
LocalFree(pDescrOut);
//LocalFree(DataBytes.pbData);
}
It is recommended to refer to Microsoft's official documentation when you add additional code.

NT Security API: SECURITY_DESCRIPTOR.Control, when can I see SE_OWNER_DEFAULTED?

From Windows NT security API, SE_OWNER_DEFAULTED is a flag bit from SECURITY_DESCRIPTOR_CONTROL.
MSDN states it quite briefly:
(SE_OWNER_DEFAULTED) Indicates that the SID of the owner of the security descriptor was provided by a default mechanism. This flag can be used by a resource manager to identify objects whose owner was set by a default mechanism.
I'm curious that when I can see this flag set.
I write NtfsOwner.cpp to display owner SID of an NTFS file/directory's security descriptor, and use GetSecurityDescriptorOwner to query that SE_OWNER_DEFAULTED flag, but have no chance seeing it even once.
Could somebody give me some clue. Could it be possible that SE_OWNER_DEFAULTED exhibits on other type of NT objects(not on a file/directory)?
#include <Windows.h>
#include <AclAPI.h>
#include <sddl.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <locale.h>
template<typename T1, typename T2>
bool IsSameBool(T1 a, T2 b)
{
if(a && b)
return true;
else if(!a && !b)
return true;
else
return false;
}
void myDisplayNtfsOwner(const TCHAR *szfn)
{
DWORD succ = 0;
HANDLE hFile = CreateFile(szfn,
READ_CONTROL, // dwDesiredAccess=GENERIC_READ etc
FILE_SHARE_READ|FILE_SHARE_WRITE, // shareMode
NULL, // SecuAttr, no need bcz we are opening existing file
OPEN_EXISTING, // dwCreationDisposition
FILE_FLAG_BACKUP_SEMANTICS, // this is required for open a directory
NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
_tprintf(_T("Warning: CreateFile() failed!(WinErr=%d) But I will go on calling GetSecurityInfo(0xFFFFffff, ...)\n"),
GetLastError());
}
SECURITY_DESCRIPTOR *pSD = nullptr;
DWORD winerr = GetSecurityInfo(hFile, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
NULL, NULL, NULL, NULL,
(PSECURITY_DESCRIPTOR*)&pSD);
assert(winerr==0);
SID* psidOwner = nullptr;
BOOL isOwnerDefaulted = 0;
succ = GetSecurityDescriptorOwner(pSD, (PSID*)&psidOwner, &isOwnerDefaulted);
assert(succ);
PTSTR strOwner = nullptr;
succ = ConvertSidToStringSid(psidOwner, &strOwner);
assert(succ);
_tprintf(_T("Owner SID is: %s\n"), strOwner);
_tprintf(_T("Is owner SID defaulted? %s\n"), isOwnerDefaulted?_T("yes"):_T("no"));
assert(IsSameBool(pSD->Control & SE_OWNER_DEFAULTED, isOwnerDefaulted));
LocalFree(strOwner);
LocalFree(pSD);
CloseHandle(hFile);
}
int _tmain(int argc, TCHAR* argv[])
{
setlocale(LC_ALL, "");
if(argc==1)
{
const TCHAR *s = _T("D:\\test\\foo.txt");
_tprintf(_T("Missing parameters.\n"));
_tprintf(_T("Example:\n"));
_tprintf(_T(" NtfsOwner1 %s\n"), s);
exit(1);
}
const TCHAR *szfn = argv[1];
myDisplayNtfsOwner(szfn);
return 0;
}

Enclave field not working, but there is no error

I'm trying make simple code call an enclave field and just add 1.
I'm reference this site : https://software.intel.com/en-us/articles/getting-started-with-sgx-sdk-f...
After it finishes, there is no error, but the enclave code is not working.
Here is my project.zip code with Visual Studio 2017 https://drive.google.com/open?id=13trTAamhNWaz2Q2BRDtUFP5qCX8Syyuc
app.cpp
#include <stdio.h>
#include <Windows.h>
#include <tchar.h>
#include "sgx_urts.h"
#include "Enclave1_u.h"
#define ENCLAVE_FILE _T("Enclave1.signed.dll")
int main() {
int a = 1;
int i = 0;
sgx_enclave_id_t eid;
sgx_status_t ret = SGX_SUCCESS;
sgx_launch_token_t token = { 0 };
int updated = 0;
ret = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &token, &updated, &eid, NULL);
if (ret != SGX_SUCCESS)
{
printf("APP error%#x, failed to create enclave. \n", ret);
return -1;
}
int *ptr = &a;
printf("%d\n",*ptr);
while (i<5) {
foo(eid, ptr);
printf("%d\n", *ptr);
Sleep(1000);
i++;
}
if (SGX_SUCCESS != sgx_destroy_enclave(eid))
return -1;
}
Enclave1.edl
enclave {
from "sgx_tstdc.edl" import *;
trusted {
/* define ECALLs here. */
public void foo([in, size = 4]int *ptr);
};
untrusted {
/* define OCALLs here. */
};
};
Enclave1.cpp
#include "Enclave1_t.h"
#include "sgx_trts.h"
#include <string.h>
void foo(int *ptr)
{
if (*ptr == 1) *ptr == 43971;
*ptr += 1;
}
I expected it to print:
43971, 43972, 43973, 43974 .....
But the result is:
1, 1, 1, .........
What did I miss?
i solved this problem.
foo needs [out] instad of [in] so Enclave1.edl should
enclave { from "sgx_tstdc.edl" import *;
trusted {
/* define ECALLs here. */
public void foo([out, size = 4]int *ptr);
};
untrusted {
/* define OCALLs here. */
};
};
project1.signed.dll file is not updated on debug folder. so i try rebuild project and it updated. I'm realized this file is enclave field itself
IF state grammar is wrong. it should be if (*ptr == 1) *ptr = 43971;

ReadFile/WriteFile crahes

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);

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;
}

Resources