I am new to winsock and I wish to use bluetooth for my project.
I wrote a simple code taking help from online resources to find remote devices
It should print the name of the remote devices but instead it prints some hex value I think...I dont know what that is
The code is
#include "stdafx.h"
#include<iostream>
#include<winsock2.h>
#include<ws2bth.h>
#include<bluetoothapis.h>
#include<stdlib.h>
using namespace std;
#define SUCCESS 0
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "irprops.lib")
int main()
{
WSADATA data;
int result;
result = WSAStartup(MAKEWORD(2, 2), &data);
if (result != SUCCESS)
{
cout << "error occured while initialising winsock...";
exit(result);
}
cout << "winsock initialisation successful\n";
WSAQUERYSET queryset;
memset(&queryset, 0, sizeof(WSAQUERYSET));
queryset.dwSize = sizeof(WSAQUERYSET);
queryset.dwNameSpace = NS_BTH;
HANDLE hLookup;
result = WSALookupServiceBegin(&queryset, LUP_CONTAINERS, &hLookup);
if (result != SUCCESS)
{
cout << "error in initialising look up service\n";
exit(result);
}
cout << "initialising lookup service successful\n";
BYTE buffer[4096];
memset(buffer, 0, sizeof(buffer));
DWORD bufferLength = sizeof(buffer);
WSAQUERYSET *pResults = (WSAQUERYSET*)&buffer;
while (result == SUCCESS)
{
result = WSALookupServiceNext(hLookup, LUP_RETURN_NAME | LUP_CONTAINERS | LUP_RETURN_ADDR | LUP_FLUSHCACHE | LUP_RETURN_TYPE | LUP_RETURN_BLOB | LUP_RES_SERVICE, &bufferLength, pResults);
if (result == SUCCESS)
{
//DEVICE FOUND
LPTSTR s = pResults->lpszServiceInstanceName;
cout << s << endl;
Sleep(1000);
}
}
WSALookupServiceEnd(hLookup);
return 0;
}
I require help in solving this issue
Thanks in advance for any help
You have a (potential) mismatch of character encodings. The line
LPTSTR s = pResults->lpszServiceInstanceName;
expands to
LPWSTR s = pResults->lpszServiceInstanceName;
if you have your project's character encoding set to Unicode (default setting). To output a Unicode string, you have to use std::wcout instead of std::cout:
LPCWSTR s = pResults->lpszServiceInstanceName;
wcout << s << endl;
To reduce the odds of inadvertently using an unexpected character encoding, code should explicitly specify the character encoding it uses. The code in the question should use WSAQUERYSETW, and call WSALookupServiceBeginW and WSALookupServiceNextW instead.
Explanation of the observed behavior:
std::cout interprets a const char* as a C-style string, and displays the characters until it finds a NUL character (see operator<<(std::basic_ostream)).
A const wchar_t*, on the other hand, is not interpreted to mean anything special. std::cout treats it like any other pointer, and prints its value using the hexadecimal numeral system by default (see std::basic_ostream::operator<<).
Related
I am trying to get the various attributes of a file as seen in its "Details" tab with the WinAPI function VerQueryValue. I have successfully used this function to get the non-string version info with VS_FIXEDFILEINFO, but have not been able to get the example shown at the bottom of the functions documentation working.
The example isn't actually complete as it leaves out the use of the other related functions and the constructions of some buffers needed to use the function, so I've filled in the blanks the best I can and changed some of the in-between steps to use C++ SL since that's ultimately the language I need to use this in:
#include <iostream>
#include <iomanip>
#include "sstream"
#include "Windows.h"
#pragma comment(lib, "Version.lib")
int ReadOutFileDescriptions(std::wstring filename)
{
LPBYTE lpBuffer = NULL;
DWORD verHandle, verSize = GetFileVersionInfoSize(filename.c_str(), &verHandle);
if (verSize != NULL)
{
LPSTR verData = new char[verSize];
if (GetFileVersionInfo(filename.c_str(), verHandle, verSize, verData))
{
UINT cbTranslate;
// Structure used to store enumerated languages and code pages.
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// Read the list of languages and code pages.
VerQueryValue(verData, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate);
// Read the file description for each language and code page.
for (ULONGLONG i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
{
std::wostringstream ss; ss << std::setfill(L'0') << std::hex;
ss << std::setw(4) << lpTranslate[i].wLanguage;
std::wstring langS = ss.str();
ss.str(std::wstring());
ss << std::setw(4) << lpTranslate[i].wCodePage;
std::wstring codeS = ss.str();
std::wstring subBlock = L"\\StringFileInfo\\" + langS + codeS + L"\\FileDescription";
// Retrieve file description for language and code page "i".
WCHAR descBuffer[50];
LPVOID lpBuffer = &descBuffer;
UINT bufferSize;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);
std::cout << bufferSize << '\n' << descBuffer;
}
}
delete[] verData;
}
return 0;
}
int main(int argc, char* argv[])
{
ReadOutFileDescriptions(L"MyFile.exe");
return 0;
}
I only have a little experience with WinAPI and its typedefs and my C is a bit rusty so I'm sure I'm just setting-up/using a buffer incorrectly or the like.
The printed buffer size is correct (the length of MyFile.exe's description + 1 for the null character) so I know the function is getting the right value, but the actually value that gets printed is just a series of hexadecimal character, most likely an address.
What am I doing wrong?
EDIT (Answer):
Thanks to #dxiv I was made aware that I did not fully understand how the "result" argument (lplpBuffer) of VerQueryValue was to be used, both internally and after the function returns.
Changing the end of the loop to the following achieves my desired result:
//WCHAR descBuffer[50] Not required, the function doesn't utilize a user made buffer
LPVOID lpBuffer;
UINT bufferSize;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize); // lpBuffer is reassigned here
std::wstring fileDescription((const TCHAR*)lpBuffer); // Create std::string from C style string (char*) that lpBuffer now points to
std::wcout << bufferSize << '\n' << fileDescription;
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);
std::cout << bufferSize << '\n' << descBuffer;
Once VerQueryValue returns, lpBuffer no longer points to descBuffer, but to a different buffer assigned inside the call. The returned string is at (const TCHAR *)lpBuffer at that point.
Consider the emoji 😙. It's U+1F619 (decimal 128537). I believe it's UTF-8 byte array is 240, 159, 152, 151.
Given the UTF-8 byte array, how can I display it? Do I create a std::string from the byte array? Are there 3rd party libraries which help?
Given a different emoji, how can I get its UTF-8 byte array?
Target platform: Windows. Compiler: Visual C++ 2019. Just pasting 😙 into the Windows CMD prompt does not work. I tried chcp 65001 and Lucida as the font, but no luck.
I can do this on macOS or Linux if necessary, but I prefer Windows.
To clarify ... given a list of 400 bytes, how can I display the corresponding code points assuming UTF-8?
C++ has a simple solution to that.
#include <iostream>
#include <string>
int main(void) {
std::string s = u8"😙"; /* use std::u8string in c++20*/
std::cout << s << std::endl;
return 0;
}
This will allow you to store and print any UTF-8 string.
Note that Windows command prompt is weird with this kind of stuff. It's better you use an alternative such as MSYS2.
Here is sample code for experimenting with unicode, to convert unicode character/string and print it in console, it works just fine for a lot of unicode characters assuming you set correct locale, console code page, and perform adequate string conversion (if needed ex. char32_t, char16_t and char8_t need conversion).
except for the character you want to display its not that easy, running a test takes huge amount of time, this can be improved my modifying code bellow or by knowing details needed such as code page (likely not supported by windows), so feel free to experiment as long as it doesn't become boring ;)
Hint, it would be the best to add code to write to file, let it run and check after some hour the results in file. For this to work you'll need to put BOM mark into file, but not before file is opened as UTF encoded, you do this by wofstream::imbue() to specific locale, and for BOM it depends on endianess, it's UTF-X LE encoding scheme on Windows, where X is either 8, 16, or 32, write to file must be done with wcout wchar_t to be sucessful.
See code commenets for more info, and try to comment out/uncomment parts of code to see different and quicker results.
BTW. the point in this code is to try out all possible locales/code pages supported by sytem, until you see your smiley in the console or ulitmately fail
#include <climits>
#include <locale>
#include <iostream>
#include <sstream>
#include <Windows.h>
#include <string_view>
#include <cassert>
#include <cwchar>
#include <limits>
#include <vector>
#include <string>
#pragma warning (push, 4)
#if !defined UNICODE && !defined _UNICODE
#error "Compile as unicode"
#endif
#define LINE __LINE__
// NOTE: change desired default code page here (unused)
#define CODE_PAGE CP_UTF8
// Error handling helper method
void StringCastError()
{
std::wstring error = L"Unknown error";
switch (GetLastError())
{
case ERROR_INSUFFICIENT_BUFFER:
error = L"A supplied buffer size was not large enough, or it was incorrectly set to NULL";
break;
case ERROR_INVALID_FLAGS:
error = L"The values supplied for flags were not valid";
break;
case ERROR_INVALID_PARAMETER:
error = L"Any of the parameter values was invalid.";
break;
case ERROR_NO_UNICODE_TRANSLATION:
error = L"Invalid Unicode was found in a string.";
break;
default:
break;
};
std::wcerr << error << std::endl;
}
// Convert multybyte to wide string
static std::wstring StringCast(const std::string& param, int code_page)
{
if (param.empty())
{
std::wcerr << L"ERROR: param string is empty" << std::endl;
return std::wstring();
}
DWORD flags = MB_ERR_INVALID_CHARS;
//flags |= MB_USEGLYPHCHARS;
//flags |= MB_PRECOMPOSED;
switch (code_page)
{
case 50220:
case 50221:
case 50222:
case 50225:
case 50227:
case 50229:
case 65000:
case 42:
flags = 0;
break;
case 54936:
case CP_UTF8:
flags = MB_ERR_INVALID_CHARS; // or 0
break;
default:
if ((code_page >= 57002) && (code_page <= 57011))
flags = 0;
break;
}
const int source_char_size = static_cast<int>(param.size());
int chars = MultiByteToWideChar(code_page, flags, param.c_str(), source_char_size, nullptr, 0);
if (chars == 0)
{
StringCastError();
return std::wstring();
}
std::wstring return_string(static_cast<const unsigned int>(chars), 0);
chars = MultiByteToWideChar(code_page, flags, param.c_str(), source_char_size, &return_string[0], chars);
if (chars == 0)
{
StringCastError();
return std::wstring();
}
return return_string;
}
// Convert wide to multybyte string
std::string StringCast(const std::wstring& param, int code_page)
{
if (param.empty())
{
std::wcerr << L"ERROR: param string is empty" << std::endl;
return std::string();
}
DWORD flags = WC_ERR_INVALID_CHARS;
//flags |= WC_COMPOSITECHECK;
flags |= WC_NO_BEST_FIT_CHARS;
switch (code_page)
{
case 50220:
case 50221:
case 50222:
case 50225:
case 50227:
case 50229:
case 65000:
case 42:
flags = 0;
break;
case 54936:
case CP_UTF8:
flags = WC_ERR_INVALID_CHARS; // or 0
break;
default:
if ((code_page >= 57002) && (code_page <= 57011))
flags = 0;
break;
}
const int source_wchar_size = static_cast<int>(param.size());
int chars = WideCharToMultiByte(code_page, flags, param.c_str(), source_wchar_size, nullptr, 0, nullptr, nullptr);
if (chars == 0)
{
StringCastError();
return std::string();
}
std::string return_string(static_cast<const unsigned int>(chars), 0);
chars = WideCharToMultiByte(code_page, flags, param.c_str(), source_wchar_size, &return_string[0], chars, nullptr, nullptr);
if (chars == 0)
{
StringCastError();
return std::string();
}
return return_string;
}
// Console code page helper to adjust console
bool SetConsole(UINT code_page)
{
if (IsValidCodePage(code_page) == 0)
{
std::wcerr << L"Code page is not valid: " << LINE << std::endl;
}
else if (SetConsoleCP(code_page) == 0)
{
std::wcerr << L"Failed to set console input code page line: " << LINE << std::endl;
}
else if (SetConsoleOutputCP(code_page) == 0)
{
std::wcerr << L"Failed to set console output code page: " << LINE << std::endl;
}
else
{
return true;
}
return false;
}
std::vector<std::string> locales;
// System locale enumerator to get all locales installed on system
BOOL LocaleEnumprocex(LPWSTR locale_name, [[maybe_unused]] DWORD locale_info, LPARAM code_page)
{
locales.push_back(StringCast(locale_name, static_cast<int>(code_page)));
return TRUE; // continue drilling
}
// System code page enumerator to try out every possible supported/installed code page on system
BOOL CALLBACK EnumCodePagesProc(LPTSTR page_str)
{
wchar_t* end;
UINT code_page = std::wcstol(page_str, &end, 10);
char char_buff[MB_LEN_MAX]{};
char32_t target_char = U'😙';
std::mbstate_t state{};
std::stringstream string_buff{};
std::wstring wstr = L"";
// convert UTF-32 to multibyte
std::size_t ret = std::c32rtomb(char_buff, target_char, &state);
if (ret == -1)
{
std::wcout << L"Conversion from char32_t failed: " << LINE << std::endl;
return FALSE;
}
else
{
string_buff << std::string_view{ char_buff, ret };
string_buff << '\0';
if (string_buff.fail())
{
string_buff.clear();
std::wcout << L"string_buff failed or bad line: " << LINE << std::endl;
return FALSE;
}
// NOTE: CP_UTF8 gives good results, ex. CP_SYMBOL or code_page variable does not
// To make stuff work, provide good code page
wstr = StringCast(string_buff.str(), CP_UTF8 /* code_page */ /* CP_SYMBOL */);
}
// Try out every possible locale, this will take insane amount of time!
// make sure to comment this range for out if you know the locale.
for (auto loc : locales)
{
// locale used (comment out for testing)
std::locale::global(std::locale(loc));
if (SetConsole(code_page))
{
// HACK: put breakpoint here, and you'll see the string
// is correctly encoded inside wstr (ex. mouse over wstr)
// However it's not printed because console code page is likely wrong.
assert(std::wcout.good() && string_buff.good());
std::wcout << wstr << std::endl;
// NOTE: commented out to avoid spamming the console, basically
// hard to find correct code page if not impossible for CMD
if (std::wcout.bad())
{
std::wcout.clear();
//std::wcout << L"std::wcout Read/write error on i/o operation line: " << LINE << std::endl;
}
else if (std::wcout.fail())
{
std::wcout.clear();
//std::wcout << L"std::wcout Logical error on i/o operation line: " << LINE << std::endl;
}
}
}
return TRUE; // continue drilling
}
int main()
{
// NOTE: can be also LOCALE_ALL, anything else than CP_UTF8 doesn't make sense here
EnumSystemLocalesEx(LocaleEnumprocex, LOCALE_WINDOWS, static_cast<LPARAM>(CP_UTF8), 0);
// NOTE: can also be CP_INSTALLED
EnumSystemCodePagesW(EnumCodePagesProc, CP_SUPPORTED);
// NOTE: following is just a test code to demonstrate these algorithms indeed work,
// comment out 2 function above to test!
std::mbstate_t state{};
std::stringstream string_buff{};
char char_buff[MB_LEN_MAX]{};
// Test case for working char:
std::locale::global(std::locale("ru_RU.utf8"));
string_buff.clear();
string_buff.str(std::string());
// Russian (KOI8-R); Cyrillic (KOI8-R)
if (SetConsole(20866))
{
char32_t char32_str[] = U"Познер обнародовал";
for (char32_t c32 : char32_str)
{
std::size_t ret2 = std::c32rtomb(char_buff, c32, &state);
if (ret2 == -1)
{
std::wcout << L"Conversion from char32_t failed line: " << LINE << std::endl;
}
else
{
string_buff << std::string_view{ char_buff, ret2 };
}
}
string_buff << '\0';
if (string_buff.fail())
{
string_buff.clear();
std::wcout << L"string_buff failed or bad line: " << LINE << std::endl;
}
std::wstring wstr = StringCast(string_buff.str(), CP_UTF8);
std::wcout << wstr << std::endl;
if (std::wcout.fail())
{
std::wcout.clear();
std::wcout << L"std::wcout failed or bad line: " << LINE << std::endl;
}
}
}
#pragma warning (pop)
I would like to copy all files from test1 into test2. The code compiles but nothing happens.
#include <iostream>
#include <stdlib.h>
#include <windows.h>
using namespace std;
int main()
{
string input1 = "C:\\test1\\";
string input2 = "C:\\test2\\";
MoveFile(input1.c_str(), input2.c_str());
}
I was considering xcopy but it would not accept a pre defined string. Is there a work around?
std::string GetLastErrorAsString()
{
//Get the error message, if any.
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0)
return std::string(); //No error message has been recorded
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);
//Free the buffer.
LocalFree(messageBuffer);
return message;
}
int main()
{
string input1 = "C:\\test1\\";
string input2 = "C:\\test2\\";
if (!MoveFile(input1.c_str(), input2.c_str()))
{
string msg = GetLastErrorAsString();
cout << "fail: " << msg << endl;
}
else {
cout << "ok" << endl;
}
system("pause");
}
Your code works for me, you may have to set the character set to use multi-byte character set in your project properties.
If not, provide us with the error.
Check if you have the write rights on C:.
Check if there already is a test2 folder in C: (or if there is not a test1 folder in C:).
I resovled the issue by removing the \\ from test2. Folder test 2 doesn't exist. Thank you for the replies and the test code. I think SHFileOperation will be a better option as I have to transfer files from a floppy to my C drive. string input1 = "C:\\test1\\";
string input2 = "C:\\test2";
INTRODUCTION:
I am reading from text file with ReadFile. Buffer passed to ReadFile is sent to standard output with cout. Standard output is redirected to a text file.
PROBLEM:
Although my code "works", no data is lost, resulting file is larger than the original one.
When opened in notepad, everything seems fine, but when opened in Notepad++ I can clearly see extra lines added. These lines are new lines (\n).
MVCE that reproduces this behavior is submitted below.
#include <iostream>
#include <Windows.h>
int main()
{
HANDLE hFile = ::CreateFile("C:\\123.txt",
GENERIC_READ,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
return ::GetLastError();
char buffer[256];
DWORD bytesRead = 1, // dummy value so while loop can work
bytesWritten = 0; // needed for WriteFile, not for cout version
//======== so WriteFile outputs to console, not needed for cout version
HANDLE hStandardOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
if (INVALID_HANDLE_VALUE == hStandardOutput)
{
std::cout << "GetStdHandle error code = " << ::GetLastError() << std::endl;
::CloseHandle(hFile);
return ::GetLastError();
}
//============================
while(bytesRead)
{
// '\0' terminate buffer, needed for cout only
::memset(buffer, '\0', sizeof(buffer));
if (!::ReadFile(hFile,
buffer,
sizeof(buffer) - 1, // - 1 for '\0', not needed when using WriteFile
&bytesRead, NULL))
{
std::cout << "ReadFile error code = " << ::GetLastError() << std::endl;
break;
}
/*============= Works fine
if(!::WriteFile(hStandardOutput, buffer, bytesRead, &bytesWritten, NULL))
{
std::cout << "WriteFile error code = " << ::GetLastError() << std::endl;
break;
}*/
//------------- comment out when testing WriteFile
std::cout << buffer; // extra lines...
// std::cout.write(buffer, bytesRead); // extra lines as well...
//----------------------------------------
}
::CloseHandle(hFile);
return 0;
}
QUESTION:
What is causing above described behavior? How to fix it?
MY EFFORTS TO SOLVE THE PROBLEM:
As I type this post I am Googling aimlessly, hoping for some clue to show up.
I suspect that the problem lies when outputting \n, it seems that Windows inserts \r as well, but I am not sure.
The \n character has special meaning to STL character streams. It represents a newline, which gets translated to the platform-specific line break upon output. This is discussed here:
Binary and text modes
A text stream is an ordered sequence of characters composed into lines (zero or more characters plus a terminating '\n'). Whether the last line requires a terminating '\n' is implementation-defined. Characters may have to be added, altered, or deleted on input and output to conform to the conventions for representing text in the OS (in particular, C streams on Windows OS convert \n to \r\n on output, and convert \r\n to \n on input) .
So it is likely that std::cout outputs \r\n when it is given \n, even if a preceding \r was also given, thus an input of \r\n could become \r\r\n on output. It is not standardized behavior on Windows how individual apps handle bare-CR characters. They might be ignored, or they might be treated as line breaks. In your case, it sounds like the latter.
There is no standard way to use std::cout in binary mode so \n is output as \n instead of as \r\n. However, see How to make cout behave as in binary mode? for some possible ways that you might be able to make std::cout output in binary mode on Windows, depending on your compiler and STL implementation. Or, you could try using std::cout.rdbuf() to substitute in your own std::basic_streambuf object that performs binary output to the console.
That being said, the way your code is handling the data buffer is a little off, it should look more like this instead (not accounting for the above info):
#include <iostream>
#include <Windows.h>
int main()
{
HANDLE hFile = ::CreateFile("C:\\123.txt",
GENERIC_READ,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE, // why??
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
return ::GetLastError();
char buffer[256];
DWORD bytesRead, bytesWritten, err;
//======== so WriteFile outputs to console, not needed for cout version
HANDLE hStandardOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
if (INVALID_HANDLE_VALUE == hStandardOutput)
{
err = ::GetLastError();
std::cout << "GetStdHandle error code = " << err << std::endl;
::CloseHandle(hFile);
return err;
}
//============================
do
{
if (!::ReadFile(hFile, buffer, sizeof(buffer), &bytesRead, NULL))
{
err = ::GetLastError();
std::cout << "ReadFile error code = " << err << std::endl;
::CloseHandle(hFile);
return err;
}
if (bytesRead == 0) // EOF reached
break;
/*============= Works fine
if (!::WriteFile(hStandardOutput, buffer, bytesRead, &bytesWritten, NULL))
{
err = ::GetLastError();
std::cout << "WriteFile error code = " << err << std::endl;
::CloseHandle(hFile);
return err;
}
*/
//------------- comment out when testing WriteFile
std::cout.write(buffer, bytesRead);
//----------------------------------------
}
while (true);
::CloseHandle(hFile);
return 0;
}
I have the following code:
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
int main(int argc, wchar_t*argv[])
{
std::locale::global(std::locale("spanish"));
/*Declaración de variables*/
HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU");
DWORD ulOptions = 0;
REGSAM samDesired = KEY_READ | KEY_WRITE;
HKEY phkResult;
DWORD dwIndex = 0;
TCHAR lpValueName[16383];
DWORD lpcchValueName = 16383;
LPTSTR lpData="";
long OpenK = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (OpenK == ERROR_SUCCESS)
{
long R = RegEnumValue(phkResult, dwIndex, lpValueName, &lpcchValueName, NULL, NULL,(LPBYTE)lpData, NULL);
if (R == ERROR_SUCCESS)
{
cout << "The value and data is: \n" << lpValueName << ": " << lpData << endl;
//printf(TEXT("(%d) %s\n"), lpValueName);
}
else
cout << "Error: " << R << endl;
}
else if (OpenK == ERROR_FILE_NOT_FOUND)
{
cout << "La sub-clave RunMRU no existe." << endl;
}
else if (OpenK == ERROR_ACCESS_DENIED)
{
cout << "Acceso denegado al abrir la sub-clave RunMRU." << endl;
}
else
{
cout << "Error al abrir la clave de registro. Código: " << OpenK << endl;
}
system("Pause");
}
I am trying to show both, the Value name, and its Data using the RegEnumValue in the first if (The value and data is:) but I can only show the Value name.
Is there any way to do that? I'm trying to figure out how to use the lpData, but I can't because I only receive error 87 (Incorrect parameters) or nothing (If I set NULL instead).
You're not providing a suitable buffer for RegEnumValue() to store the data.
LPTSTR lpData="";
This is just a string literal, of at most 2 bytes in size, and is almost certainly not writable anyway. You need to allocate an area of memory and pass that to RegEnumValue() to read the data back for each value.
Your first step should be to use RegQueryInfoKey() to find out how big the largest data value is. I showed you how to use this function in a previous answer to query the size of the largest value name - the process is the same. See the docs for RegQueryInfoKey() to find out which parameter provides the data size.
Once you know how big your largest item of data is, allocate a buffer for it:
void* pData = malloc(dwLargestValueSize);
// remember this buffer needs to be freed at the end with free()
You then pass that buffer, plus a value indicating its size, to RegEnumValue().
Something else you need to be aware of is that registry values can be different types - REG_DWORD, REG_SZ, etc, and the data you get back from RegEnumValue() is the raw data. RegEnumValue() can also return a value indicating the type of data and if you're to properly interpret it, you absolutely need to check this as well.
Changes to your code to get a string value into lpData:
#define MAX_DATA_LENGTH 16383
char* lpData = new char[MAX_DATA_LENGTH];
DWORD lpDataLength = MAX_DATA_LENGTH;
RegEnumValue(phkResult, dwIndex, lpValueName, &lpcchValueName, NULL, NULL, (unsigned char*)lpData, &lpDataLength);