InvalidArgs When trying to use UrlCreateFromPath in c++ - c++

I am trying to convert filepath to fileUrl using UrlCreateFromPath() function in c++.
Following code tries to convert filepath to fileUrl
PCTSTR lpszUnicode = L"C:\\Users\\TBD\\Downloads\\index.html";
PTSTR output =L"C:\\Users\\TBD\\Downloads\\index.html";
DWORD dwDisp = 0;
DWORD dw2 = 0;
LPDWORD lpdwDisp = &dwDisp;
HRESULT res2 = UrlCreateFromPath(lpszUnicode, output, lpdwDisp, dw2);
std::wstring newOutput(output);
but res2 always shows InvalidArgs.Am i doing something wrong in above code snap ?

You actualy write to constant buffer (wich is wrong)
PCTSTR lpszUnicode = L"C:\\Users\\TBD\\Downloads\\index.html";
//PTSTR output =L"C:\\Users\\TBD\\Downloads\\index.html"; cannot do that way
TCHAR output[MAX_PATH]; // allocate buffer in memory (stack)
DWORD dwDisp = MAX_PATH; // max posible buffer size
LPDWORD lpdwDisp = &dwDisp;
HRESULT res2 = UrlCreateFromPath(lpszUnicode, output, lpdwDisp, NULL);
std::wstring newOutput(output);
And why did you do that
LPDWORD lpdwDisp = &dwDisp;
you can simply do so
HRESULT res2 = UrlCreateFromPath(lpszUnicode, output, &dwDisp, dw2);

Related

Can't cast void pointer returned by RegGetValueA

I'm trying to access the registry using the RegGetValueA function, but I can't cast the void pointer passed to the function. I just get the (value?) of the pointer itself.
Here's my code:
LSTATUS res;
LPCSTR lpSubKey = "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{071c9b48-7c32-4621-a0ac-3f809523288f}";
LPCSTR lpValue = "InstallSource";
PVOID pvData = new PVOID;
LPDWORD pcbData = new DWORD;
res = RegGetValueA(
HKEY_LOCAL_MACHINE,
lpSubKey,
lpValue,
RRF_RT_ANY,
NULL,
pvData,
pcbData);
string* data = static_cast<string*>(pvData);
cout << data << "\n";
cout << pvData;
output:
000000000045A240
000000000045A240
Any help would be much appreciated.
link to documentation:
https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluea
You are using the function incorrectly.
First off, you shouldn't be accessing Wow6432Node directly at all. The function has flags for accessing 32bit and 64bit keys when dealing with WOW64.
More importantly, you are giving the function a void* pointer that doesn't point at valid memory for your purpose. When reading a string value from the Registry, you must pre-allocate a character buffer of sufficient size, then pass the address of that buffer to the function. You can ask the function for the necessary buffer size.
The code should look more like the following instead:
LSTATUS res;
LPCSTR lpSubKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{071c9b48-7c32-4621-a0ac-3f809523288f}";
LPCSTR lpValue = "InstallSource";
char *pszData = NULL;
DWORD cbData = 0;
res = RegGetValueA( HKEY_LOCAL_MACHINE, lpSubKey, lpValue, RRF_RT_REG_SZ | RRF_SUBKEY_WOW6432KEY, NULL, NULL, &cbData);
if (res != ERROR_SUCCESS) ...
pszData = new char[cbData];
res = RegGetValueA( HKEY_LOCAL_MACHINE, lpSubKey, lpValue, RRF_RT_REG_SZ | RRF_SUBKEY_WOW6432KEY, NULL, pszData, &cbData);
if (res != ERROR_SUCCESS) ...
cout << pszData << "\n";
delete[] pszData;

Registry RegQueryValueExW

Is it possible to read a value in the Registry not to an array of chars but directly to an AnsiString in this case?
LONG result;
wchar_t buf[255] = {0};
DWORD dwBufSize = sizeof(buf);
String d = "Nazwa";
DWORD dwType = REG_SZ;
result = ::RegQueryValueExW( hkSoftware, (LPCWSTR)(d.c_str()), NULL, &dwType, (LPBYTE)&buf, &dwBufSize );
First off, your code example is not using AnsiString. In C++Builder 2009 and later, String is an alias for UnicodeString instead.
And yes, you can use UnicodeString with RegQueryValueExW(), without using a typecast. UnicodeString::c_str() returns a WideChar*, and WideChar is an alias for wchar_t on Windows, so WideChar* (aka wchar_t *) is implicitly convertible to LPCWSTR (aka const wchar_t *), eg:
LONG result;
wchar_t buf[255] = {0};
DWORD dwBufSize = sizeof(buf);
UnicodeString d = L"Nazwa";
DWORD dwType = REG_SZ;
result = ::RegQueryValueExW( hkSoftware, d.c_str(), NULL, &dwType, reinterpret_cast<LPBYTE>(&buf), &dwBufSize );
You can also use UnicodeString as a buffer to receive string data from RegQueryValueExW(), eg:
LONG result;
UnicodeString buf;
buf.SetLength(...);
DWORD dwBufSize = ByteLength(buf);
UnicodeString d = L"Nazwa";
DWORD dwType = REG_SZ;
result = ::RegQueryValueExW( hkSoftware, d.c_str(), NULL, &dwType, reinterpret_cast<LPBYTE>(buf.c_str()), &dwBufSize );
if ( result == 0 ) {
buf.SetLength(dwBufSize/sizeof(WideChar));
...
}
That being said, you should consider using C++Builder's TRegistry class instead of using the Win32 Registry API directly. TRegistry has many methods for reading different kinds of data, including ReadString() for String data, eg:
#include <Registry.hpp>
TRegistry *Reg = new TRegistry;
String buf;
Reg->RootKey = ...;
if (Reg->OpenKeyReadOnly(_D("...")))
{
buf = Reg->ReadString(_D("Nazwa"));
Reg->CloseKey();
}
delete Reg;

How to assign value to LPVOID buffer of ReadFile

I am developing a win32 API hook program.
Accordingly to my understanding, when a program calls ReadFile for a particular file, the content of that file is copied to lpBuffer(see the definition below),
ReadFile definition:
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
Now, my target is to alter this lpBuffer and fill it with provided content by me!
I am using EasyHook to hook ReadFile. I am not familiar with LPVOID type. I was able to alter the content for GetCurrentDirectory using the following code.
string b = "C:\\my\\altered\\directory";
DWORD returnLength = b.length();
int i;
for (i = 0; i<b.length(); i++)
{
lpBuffer[i] = b[i];
}
lpBuffer[i++] = '\0';
GetCurrentDirectory definition:
DWORD GetCurrentDirectory(
DWORD nBufferLength,
LPTSTR lpBuffer
);
How to do similar value assignment for ReadFile (LPVOID lpBuffer)?
Here's the LPVOID typedef:
#define far
typedef void far *LPVOID;
The far macro is defined as nothing, I guess it's because of some historical reasons (baggage).
So you can almost directly treat the LPVOID as void*.
And now, suppose you have a std::vector<uint8_t> named FakeData, just:
if (nNumberOfBytesToRead < FakeData.size()) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
memcpy(lpBuffer, FakeData.data(), FakeData.size());
*lpNumberOfBytesRead = FakeData.size();
SetLastError(ERROR_SUCCESS);
return TRUE;

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.

Converting a PIDL to file path with SHGetPathFromIDList

My application receives a PIDL as a string:
QString pidl = "::{20D04FE1-3AEA-1069-A2D8-08002B30309B}";
In this case it corresponds to My Computer. I need to convert it to My Computer.
Theres a WINAPI function SHGetPathFromIDList which requires the LPCITEMIDLIST as the first parameter and converts it to a string.
How can I build that LPCITEMIDLIST?
UPDATE
This is what I got so far:
LPCWSTR csPath = (LPCWSTR)"::{20D04FE1-3AEA-1069-A2D8-08002B30309B}";
LPITEMIDLIST stId = 0;
SFGAOF stSFGAOFIn = 0;
SFGAOF stSFGAOFOut = 0;
if(!FAILED(SHParseDisplayName(csPath, 0, stId, stSFGAOFIn, &stSFGAOFOut)))
msgBox("not failed")
Unfortunately this code crashes.
Your code crashes because you are not setting up the 1st and 3rd parameters of SHParseDisplayName() correctly. Try this instead:
LPCWSTR csPath = L"::{20D04FE1-3AEA-1069-A2D8-08002B30309B}";
PIDLIST_ABSOLUTE stId = NULL;
SFGAOF stSFGAOFIn = 0;
SFGAOF stSFGAOFOut = 0;
if (!FAILED(SHParseDisplayName(csPath, NULL, &stId, stSFGAOFIn, &stSFGAOFOut)))
msgBox("not failed")
The function you need is not SHGetPathFromIDList, because there is no path for "My Computer".
To convert your QString pidl to an PIDLIST_ABSOLUTE you need to use SHParseDisplayName.
To convert the PIDLIST_ABSOLUTE to a localised string like "My Computer" you need SHGetNameFromIDList.
I think may be:
SHParseDisplayName(csPath, 0, &stId, stSFGAOFIn, &stSFGAOFOut)
Declaration of SHParseDisplayName from MSDN:
HRESULT SHParseDisplayName(
__in LPCWSTR pszName,
__in_opt IBindCtx *pbc,
__out PIDLIST_ABSOLUTE *ppidl,
__in SFGAOF sfgaoIn,
__out_opt SFGAOF *psfgaoOut
);