I was surprised about the behavior of the following code:
if(RegQueryValueEx(....)!=ERROR_SUCCESS){
...
}
when it was run from visual studio it didn't enter this if block, because the key did exist. when ran outside of the visual studio environment it evaluated true and hence entered the block, even though the queried key existed. After some testing i found out that when i first save it to a variable it runs always fine. With the following code:
HKEY hSoftwareKey,hAppKey;
DWORD dwLength;
int iStatus=1;
char szBuffer[MAX_PATH];
if(iStatus&&RegOpenKeyA(HKEY_CURRENT_USER,"Software",&hSoftwareKey)!=ERROR_SUCCESS)
iStatus = 0;
if(iStatus&&RegCreateKeyA(hSoftwareKey,"Amine",&hAppKey)!=ERROR_SUCCESS){
iStatus = 0;
}
ZeroMemory(szBuffer,MAX_PATH);
LONG lRet;
lRet = RegQueryValueExA(hAppKey,"One",0,0,reinterpret_cast<LPBYTE>(szBuffer),&dwLength);
Does this bevavior have anything to do with the __stdcall/WINAPI calling convention? If so could somebody please explain why
You need to initialize dwLength to MAX_PATH before calling RegQueryValueEx(), otherwise it's value is undefined.
from MSDN RegQueryValueEx:
lpcbData is a pointer to a variable that specifies the size of the buffer pointed to by the lpData parameter, in bytes. When the function returns, this variable contains the size of the data copied to lpData
Related
I'm trying to update the Raku code in this file which tries to find the path to commands/apps on a Windows machine.
I have a Windows 11 machine running inside VirtualBox. wordpad.exe cannot be run from the command line because it is not in the $PATH, and so the code will also fail to detect wordpad.exe in the path. As a fallback, the Raku code attempts to find the executable in the registry using the Windows API via the NativeCall module. However, this is also failing to find the wordpad.exe command.
Looking at the registry, there is a WORDPAD.EXE entry in the registry at Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WORDPAD.EXE. It shows a path of "%ProgramFiles%\Windows NT\Accessories\WORDPAD.EXE".
I did a little googling, and this is how paths to some executables are stored. However, I was not able to figure out how to use the Windows API to find and extract the path to the app. I'm also unclear as to why the current Raku code uses the AssocQueryStringA() function.
Some hints are dropped in this SO answer.
But, never having done Windows API programming, and only knowing basic C programming, I'm a little at a loss.
I was able to piece together a solution using most of this code which needed a few adjustments to get working properly. Here is the code that works:
use NativeCall;
constant BYTE := uint8;
constant WCHAR := uint16;
constant DWORD := int32;
constant REGSAM := int32;
constant WCHARS := CArray[WCHAR];
constant BYTES := CArray[BYTE];
constant HKEY_LOCAL_MACHINE = 0x80000002;
constant KEY_QUERY_VALUE = 1;
constant ERROR_SUCCESS = 0; # Yeah, I know. The Win-Api uses 0 for success and other values to i
+ndicate errors
sub RegOpenKeyExW( DWORD, WCHARS, DWORD, REGSAM, DWORD is rw) is native("Kernel32.dll") returns DWOR
+D { * };
sub RegQueryValueExW( DWORD, WCHARS, DWORD is rw, DWORD is rw, BYTE is rw, DWORD is rw) is native("K
+ernel32.dll") returns DWORD { * };
my $key = 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths';
my DWORD $hkey;
my $length = 1024;
sub wstr( Str $str ) returns WCHARS {
my $return = CArray[WCHAR].new( $str.encode.list );
$return[$return.elems] = 0;
return $return;
}
my $h-key = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wstr($key), 0, KEY_QUERY_VALUE, $hkey);
say $hkey;
The key to figuring this out was that the HKEY_LOCAL_MACHINE constant has a hex value of 0x80000002 which can be used to getting the hkey value for other keys.
With this stumbling block overcome, it should now be a simple matter to retrieve data about the subkeys which contain the paths to the application in the folder using other Windows API functions.
I am trying to run this code in Rust (2021 version):
let module_list_size: PDWORD = ptr::null_mut();
res = winapi::um::psapi::EnumProcessModules(remote_handle, ptr::null_mut(), 0, module_list_size);
Res is well defined and the handle is valid (I checked it before) yet I'm still getting windows error 998 which is invalid access (I'm running this code as admin).
(The function exists and I imported it correctly).
Thank you in advance!
The last parameter is a pointer that indicates where to write how many bytes are needed to store all the module handles. But you're pointing at null, so it'll fail with an invalid access error when it tries to give you the result.
Instead, make a DWORD variable and pass a pointer to it:
let module_list_size: DWORD = 0;
res = winapi::um::psapi::EnumProcessModules(remote_handle, ptr::null_mut(), 0, &mut module_list_size);
I have implemented the creation of a shortcut as defined in this article on Shell Links by MSDN
MSDN Shell Links
Here is what I implemented
CreateLink - Uses the Shell's IShellLink and IPersistFile interfaces
to create and store a shortcut to the specified object.
Returns the result of calling the member functions of the interfaces.
Parameters:
lpszPathObj - Address of a buffer that contains the path of the object,
including the file name.
lpszPathLink - Address of a buffer that contains the path where the
Shell link is to be stored, including the file name.
lpszDesc - Address of a buffer that contains a description of the
Shell link, stored in the Comment field of the link
properties.
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres;
IShellLink* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
I call it as:
r = CreateLink("c:\\TT\\TT.exe", "C:\\Users\\Public\\Desktop\\TT.lnk", "TT Program");
This works great on a WIN7 machine but fails on a WIN10
This is the code line that is failing:
hres = ppf->Save(wsz, TRUE);
hres == AccessDenied;
I have found other system calls that work on a Win7 but fails on Win10 and it usually comes down to some undocumented change.
Has Win10 tightened privileges on the DeskTop?
Any suggestions on addressing this on a Win10 machine?
Thanks.
I am trying to use MFC with visual Studio 2012 on Windows 8.
I have the following code:
BOOL CALLBACK EWP(HWND hwnd, LPARAM lParam)
{
int txtlen = GetWindowTextLengthW(hwnd);
std::wstring s;
s.reserve(txtlen + 1);
GetWindowText(hwnd, const_cast<wchar_t*>(s.c_str()), txtlen);
return TRUE;
}
EnumWindows(EWP, 0);
What happens is that the very first string comes out as "Task Switchin" and the rest come out as "". I get about 330 of these strings. I have tried without using that weird string method too with just char buff[300], same story.
Can someone please tell me whats going on?
Your last argument to GetWindowText() is off-by-one. From the MSDN article description of that argument:
Specifies the maximum number of characters to copy to the buffer, including the NULL character. If the text exceeds this limit, it is truncated.
Pass txtlen+1 to fix.
I'm having an issue with using SHGetFileInfo on the public desktop and files in the public desktop. I'll focus on the actual desktop folder (CSIDL_COMMON_DESKTOPDIRECTORY or usually "C:\Users\Public\Desktop"). Also - I've started seeing this behavior only recently, but I can't pinpoint the exact change which made it faulty. The actual call to ShGetFileInfo has not changed (as far as I can tell).
So I have this (I've omitted intermediate error checks to shorten - the function calls return with success):
SHFILEINFOW info;
uint32_t return_value = 0;
uint32_t flags = SHGFI_TYPENAME|SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX;
uint32_t attributes = FILE_ATTRIBUTE_NORMAL;
wchar_t *path = L"C:\\Users\\Public\\Desktop";
return_value = SHGetFileInfoW(path, attributes, &info, sizeof(SHFILEINFOW), flags);
printf("[%ls] %u ", path, return_value);
This returns 0 as the return value. If I populate path using:
SHGetFolderPathW(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, path)
I get the same result. But if I use the pidl, as in:
LPITEMIDLIST pidl = NULL;
SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &pidl);
return_value = SHGetFileInfoW((LPCWSTR) pidl, attributes, &info, sizeof(SHFILEINFOW), flags | SHGFI_PIDL);
Then I get something which I expect, a handle to the system small icon list.
I can't tell what I'm doing wrong - and it only happens on this specific folder. I actually need icons for the items inside the directory, so using the pidl doesn't seem to be an option right now. Any ideas on what is the expected way to retrieve icons from the common desktop?
--
I should mention this behavior happens on Windows Vista - using the path populated by SHGetFolderPathW on XP works fine
I had the same problem. It can be fixed by calling the function CoInitialize from OLE32.DLL when the program starts.
CoInitialize(0);
return_value = SHGetFileInfoW(path, attributes, &info, sizeof(SHFILEINFOW), flags);