show variant type value in MessageBox - c++

huh i got a small prob in fact i want to be able to see list of my plugged devices
i want to see them at the first place in MessageBox()
but this variant irks me (^_^) i have tried many ways but without result
IMoniker *tmpMonk=NULL;
ULONG done;
VARIANT varName;
while(this->deviceClassEnum->Next(1,&tmpMonk,&done)==S_OK)
{
IPropertyBag *tmpBag=NULL;
tmpMonk->BindToStorage(0,0,IID_IPropertyBag,(void **)&tmpBag);
VariantInit(&varName);
checkIt(tmpBag->Read(L"FriendlyName",&varName,0));
// this i wana see what is inside but huuuuuuuuuuuuuh
MessageBox(this->app,TEXT((LPCSTR)varName.bstrVal),"",NULL);
VariantClear(&varName);
tmpBag->Release();
}
secondly how to be able to switch from device to another . from
whatever menu or list

You need to call MessageBoxW instead of MessageBox. And remove the casts. So it will look like:
MessageBoxW(this->app, varName.bstrVal , L"", NULL);
This is a problem in character encoding; strings used in COM are of type BSTR, which can be used the same as PWSTR / PCWSTR types. This is incompatible with PCSTR.
Remember that casts simply tell the compiler "hey I know what I'm doing, shut up". Except the compiler's messages were actually trying to help you, you told them to go away. Next time listen to them.

Related

What does the BluetoothGATTSetCharacteristicValue ReliableWriteContext parameter actually do?

Using C++ VS2017 Win10...
I am testing some code to set a characteristic value on a BLE device. I had originally had the default function call
HRESULT hr = BluetoothGATTSetCharacteristicValue(
hBleService.get(),
_pGattCharacteristic,
gatt_value,
NULL,
BLUETOOTH_GATT_FLAG_NONE);
I had to switch the flag to BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE to get any sets to take place even though IsWritable and IsReadable were the only 2 properties set showing true but that is a different story and another topic.
Anyway, before I found the problem with the flag I had tried to use the ReliableWriteContext parameter so the code changed to
HANDLE hDevice = _bleDeviceContext.getBleDeviceHandle();
BTH_LE_GATT_RELIABLE_WRITE_CONTEXT ReliableWriteContext = NULL;
HRESULT hr1 = BluetoothGATTBeginReliableWrite(hDevice,
&ReliableWriteContext,
BLUETOOTH_GATT_FLAG_NONE);
HRESULT hr = BluetoothGATTSetCharacteristicValue(
hBleService.get(),
_pGattCharacteristic,
gatt_value,
ReliableWriteContext,
BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE);
if (NULL != ReliableWriteContext) {
BluetoothGATTEndReliableWrite(hDevice,
ReliableWriteContext,
BLUETOOTH_GATT_FLAG_NONE);
}
Once I fixed the flag issue my BluetoothGATTSetCharacteristicValue() function would work with either the NULL or the ReliableWriteContext parameters. No difference that I could see.
My question is,then, what does the ReliableWriteContext do exactly? MS docs only say:
The BluetoothGATTBeginReliableWrite function specifies that reliable
writes are about to begin.
Well that doesn't tell me anything. So should I keep the reliable writes because the word "Reliable" sure sounds like it is something that I want? Or do I not use it because it does not seem to be necessary>
Any insight would be appreciated.
Ed

Is there a way to save raw binary data from a registry call to a string without casting it as a string?

I'm working on an utility to hook various bits of the Windows API used by different applications. The aim of the project is, at the moment to make any application portable by redirecting filesystem and registry calls to custom locations using easyhook and boost (specifically the property_tree library).
I'm currently working on the registry part of the project and I have successfully created analogues to the RegCreateKey(ExA/ExW/A/W), RegOpenKey(ExA/ExW/A/W) and RegCloseKey functions and they work fine (i made a virtual handle system to create and translate hKey handles). They work by basically translating everything to strings and saving them in a boost property tree (and then writing the tree to an .info file).
I started working on the RegSetValue and RegQueryValue functions, the ones that actually handle the data and encountered a major problem. Below are the two functions. Note that these are called by easyhook with the same parameters of the original winapi call.
LSTATUS WINAPI myRegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData)
{
boost::property_tree::ptree VirtualRegistry;
boost::property_tree::read_info("VirtualRegistry.info", VirtualRegistry);
VirtualRegistry.put(boost::property_tree::ptree::path_type(std::string(GetPathFromHandleA(hKey) + '\\' + lpValueName), '\\'), reinterpret_cast<const char*>(lpData));
boost::property_tree::write_info("VirtualRegistry.info", VirtualRegistry);
return ERROR_SUCCESS;
}
This works fine for REG_SZ calls but other types of data are not saved correctly.
LSTATUS WINAPI myRegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData)
{
boost::property_tree::ptree VirtualRegistry;
boost::property_tree::read_info("VirtualRegistry.info", VirtualRegistry);
try
{
*lpData = reinterpret_cast<const BYTE*>VirtualRegistry.get_child(boost::property_tree::ptree::path_type(std::string(GetPathFromHandleA(hKey) + "\\" + lpValueName), '\\')).data();
return ERROR_SUCCESS;
}
catch (const boost::property_tree::ptree_bad_path& e1)
{
std::cout << "\n" << "ENTRY NOT FOUND" << "\n";
return ERROR_FILE_NOT_FOUND;
}
}
This does not work. The reinterpret cast on line 6 is invalid and it won't compile.
The problem is the way my functions handle different types of data. A registry call can have many different value types and the way I wrote myRegSetValue only seems to work for REG_SZ. I will also have to save the value type when writing the call to the file but that does not solve the problem.
So my question is, is there any way of saving the raw data of a call, as a string, without having to cast it as a string, so that it works for all types of data, and then reading it back from the file from a string back to raw data and passing it to the application?
I guess I could write a separate interpreter for each key type but i would really rather not because it would be very hacky and also would break applications that do not use the registry API correctly and store invalid values in the registry (like, for example, the Unity game Sunless Sea).
Thank you, I hope I explained this in enough detail.
It appears that the real problem is already the implementation of myRegSetValueExA. When you get lpData, you can't assume that it points to data that will remain valid. You must store not the pointer, but the pointed-to data.
That's also why cbData is necessary; you need to know how much data to store. You can't rely on strlen since the type might not be REG_SZ.
Note that your assumption about This works fine for REG_SZ is true only because VirtualRegistry.put(std::string key, const char* value) is a convenient overload which calls strlen(buf) for you.
The solution is to create explicitly std::string data(static_cast<const char*>(lpData), cbData) and use that in the put. To retrieve it, you use .get<std::string>(key) instead of get_child(key).data().

C++ #define LPWSTR?

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.

Why is OPENFILENAME lpstrFileTitle param a LPSTR and not LPCSTR?

I am creating some file open dialog and stumbled across something inconsistent in the WinAPI (hehe).
I fully understand why lpstrFile is a LPSTR as the path is written into this variable.
Fine, but why is lpstrFileTitle not LPCSTR? I've read the docs at MSDN and googled around and found no satisfying explanation as it doesn't look like it is modified in any way.
Is this a compatibility remnant or something?
Causes annoying workarounds when passing a std::string as I cannot use c_str() and resort to &str[0].
lpstrFileTitle is also an output buffer. It contains the name and extension without path information of the selected file.
Related side-note: You must set lpstrFileTitle to a valid buffer for non-Unicode builds.
The docs for OPENFILENAME state that field is ignored if the pointer is null. However, since at least VS2008 the MFC CFileDialog code has included this code:
VC\atlmfc\src\mfc\dlgfile.cpp
void CFileDialog::UpdateOFNFromShellDialog()
{
...
#ifdef UNICODE
...
#else
::WideCharToMultiByte(CP_ACP, 0, wcPathName + offset,-1, m_ofn.lpstrFileTitle, m_ofn.nMaxFileTitle, NULL, NULL);
m_ofn.lpstrFileTitle[m_ofn.nMaxFileTitle - 1] = _T('\0');
#endif
...
The Unicode support correctly handles a NULL lpstrFileTitle and the WideCharToMultiByte basically does nothing. However, the added code to safely terminate the buffer does not check for a null pointer or a nMaxFileTitle==0. The result is an access violation.
Better of course to kill multibyte apps, but if you must compile that way, you have to supply that buffer.

Program doesn't run - it opens and closes

I have a problem with my main program to which after all the calls I make after running the program it just opens then closes. It doesn't find any error in my code or anything, so I tried creating a new project and it does the same thing with no error.
I even tried example code:
int APIENTRY WinMain (HINSTANCE ...)
ShellExecute(NULL, (LPCWSTR)"open", (LPCWSTR)"cmd.exe", NULL, NULL, SW_SHOW);
and it still just opens and closes. What is the issue here? I can provide the output log if necessary but I have no idea.
I'm not sure I understand what you mean about opening and closing. But this code is very wrong:
ShellExecute(NULL, (LPCWSTR)"open", (LPCWSTR)"cmd.exe",
NULL, NULL, SW_SHOW);
The casts are no good. The two string literals are pointers to arrays of char casting them to const wchar_t* doesn't change what they are. It just asks the compiler to trust that you know better than it does. You don't. They are really not const wchar_t*. All your cast achieves is to allow you to break type safety and convert an informative compile time error into a cryptic run time failure. Until you have a deep understanding of the language you should refrain from casting.
You need to use wide literals:
ShellExecute(NULL, L"open", L"cmd.exe", NULL, NULL, SW_SHOW);
You also appear to be doing no error checking. That's quite hard with ShellExecute. Try ShellExecuteEx instead and take heed of the value it returns.