Having trouble with syscall.Syscall and the WinAPI - winapi

I'm trying to use VkKeyScan from the Window's API, however the program crashes whenever that function is called. I've had no problems with other Window's API functions I've imported and used in this way. Is there something wrong with my syscall.Syscall call?
var (
user32, _ = syscall.LoadLibrary("user32.dll")
vkKeyScan, _ = syscall.GetProcAddress(user32, "VkKeyScan")
)
func VkKeyScan(char byte) (int16, syscall.Errno) {
var nargs uintptr = 1
ret, _, callErr := syscall.Syscall(uintptr(vkKeyScan), nargs, uintptr(char), 0, 0)
return int16(ret), callErr
}

VkScanKey works in C because it’s #defined roughly like this:
#ifdef UNICODE
# define VkScanKey VkScanKeyW
#else
# define VkScanKey VkScanKeyA
#endif
So VkScanKey isn’t the real symbol—VkScanKeyW is, and that’s the only form GetProcAddress will take it in. If you had been doing proper error handling you might have noticed that GetProcAddress was failing rather than Syscall, which might have tipped you off to this fact.

Related

How to get paths for apps showing in "App Paths" folder in Windows Registry using windows API?

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.

Why WNetOpenEnum gets ERROR_INVALID_ADDRESS (487) result?

trying to rewrite using WINAPI library https://learn.microsoft.com/en-us/windows/win32/wnet/enumerating-network-resources on Rust
let dw_result: DWORD;
let mut h_enum: LPHANDLE = null_mut();
let mut lpnr_local: LPNETRESOURCEW = null_mut();
dw_result = WNetOpenEnumW(RESOURCE_GLOBALNET, // all network resources
RESOURCETYPE_ANY, // all resources
0, // enumerate all resources
lpnr_local, // NULL first time the function is called
h_enum);
if dw_result != WN_NO_ERROR {
println!("WnetOpenEnum failed with error {:?}\n", dw_result);
}
But this code assign 487 into dw_result which means ERROR_INVALID_ADDRESS
And I can't get what is wrong
I guess your doubt is the difference between LPHANDLE and HANDLE.
LP stands for Long Pointer. It's a pointer to a handle.
If you want to use LPHANDLE, please give it a legal address。
Like this:(C++)
HANDLE ph;
LPHANDLE hEnum = &ph;
Or simply use HANDLE.
let mut h_enum: HANDLE;
...
dw_result = WNetOpenEnumW(RESOURCE_GLOBALNET, // all network resources
RESOURCETYPE_ANY, // all resources
0, // enumerate all resources
lpnr_local, // NULL first time the function is called
&h_enum);
Related: LPHANDLE vs. HANDLE

Pass a complex struct to the Windows API

I am trying to use the GetConsoleScreenBufferInfo(HANDLE, PCONSOLE_SCREEN_BUFFER_INFO) function from the Windows API using Perl 6 and (of course) NativeCall.
I think I have set up the CONSOLE_SCREEN_BUFFER_INFO struct the function needs correctly, but the code crashes after the call when I try to dump its content.
This is the shortest (not quite but close) way to demonstrate the problem:
use NativeCall;
constant \HANDLE := Pointer[void];
constant \SHORT := int16;
constant \USHORT := uint16;
constant \WORD := uint16;
constant \DWORD := uint32;
constant \BOOL := int32;
constant \STD_OUTPUT_HANDLE := -11;
constant \STD_INPUT_HANDLE := -10;
class COORD is repr('CStruct') {
has SHORT $.X;
has SHORT $.Y;
}
class SMALL_RECT is repr("CStruct") {
has SHORT $.Left;
has SHORT $.Top;
has SHORT $.Right;
has SHORT $.Bottom;
};
class CONSOLE_SCREEN_BUFFER_INFO is repr("CStruct") {
has COORD $.dwSize;
has COORD $.dwCursorPosition;
has WORD $.wAttributes;
has SMALL_RECT $.srWindow;
has COORD $.dwMaximumWindowSize;
submethod TWEAK {
$!dwSize := COORD.new;
$!dwCursorPosition := COORD.new;
$!srWindow := SMALL_RECT.new;
$!dwMaximumWindowSize := COORD.new;
}
}
# C: BOOL WINAPI GetConsoleScreenBufferInfo(_In_ HANDLE hConsoleOutput, _Out_ PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);
sub GetConsoleScreenBufferInfo(HANDLE, CONSOLE_SCREEN_BUFFER_INFO is rw) is native("Kernel32.dll") returns BOOL { * };
sub GetStdHandle(DWORD) is native('Kernel32') returns Pointer[void] { * };
my CONSOLE_SCREEN_BUFFER_INFO
$info = CONSOLE_SCREEN_BUFFER_INFO.new;
my HANDLE
$handle-o = GetStdHandle( STD_OUTPUT_HANDLE );
dd $info;
say "GetConsoleScreenBufferInfo ", GetConsoleScreenBufferInfo( $handle-o, $info );
say "Will I live?";
dd $info; #crashes without notice
Any hints as to why the crash occurs and how to fix it are very welcome.
You need to use HAS instead of has for the members of CONSOLE_SCREEN_BUFFER_INFO that are structures as these are embedded instead of referenced by pointer (which is the Perl6 default).
Once you do that, you can drop the TWEAK as well so the code will read
class CONSOLE_SCREEN_BUFFER_INFO is repr("CStruct") {
HAS COORD $.dwSize;
HAS COORD $.dwCursorPosition;
has WORD $.wAttributes;
HAS SMALL_RECT $.srWindow;
HAS COORD $.dwMaximumWindowSize;
}

Call golang function from Tcl sript

We use a third party Tcl parsing library to validation Tcl script for both syntax and semantic checking. The driver was written in C and defined a set of utility functions. Then it calls Tcl_CreateObjCommand so the script could call these C functions. Now we are in the process of porting the main program to go and I could not find a way to do this. Anyone know a way to call golang functions from Tcl script?
static int
create_utility_tcl_cmds(Tcl_Interp* interp)
{
if (Tcl_CreateObjCommand(interp, "ip_v4_address",
ip_address, (ClientData)AF_INET, NULL) == NULL) {
TCL_CHECKER_TCL_CMD_EVENT(0, "ip_v4_address");
return -1;
}
.....
return 0;
}
Assuming you've set the relevant functions as exported and built the Go parts of your project as in
Using Go code in an existing C project
[…]
The important things to note are:
The package needs to be called main
You need to have a main function, although it can be empty.
You need to import the package C
You need special //export comments to mark the functions you want callable from C.
I can compile it as a C callable static library with the following command:
go build -buildmode=c-archive foo.go
Then the core of what remains to be done is to write the C glue function from Tcl's API to your Go code. That will involve a function something like:
static int ip_address_glue(
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) {
// Need an explicit cast; ClientData is really void*
GoInt address_family = (GoInt) clientData;
// Check for the right number of arguments
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "address");
return TCL_ERROR;
}
// Convert the argument to a Go string
GoString address;
int len;
address.p = Tcl_GetStringFromObj(objv[1], &len);
address.n = len; // This bit is hiding a type mismatch
// Do the call; I assume your Go function is called ip_address
ip_address(address_family, address);
// Assume the Go code doesn't fail, so no need to map the failure back to Tcl
return TCL_OK;
}
(Credit to https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf for providing enough information for me to work out some of the type bindings.)
That's then the function that you register with Tcl as the callback.
Tcl_CreateObjCommand(interp, "ip_v4_address", ip_address_glue, (ClientData)AF_INET, NULL);
Theoretically, a command registration can fail. Practically, that only happens when the Tcl interpreter (or a few critical namespaces within it) is being deleted.
Mapping a failure into Tcl is going to be easiest if it is encoded at the Go level as an enumeration. Probably easiest to represent success as zero. With that, you'd then do:
GoInt failure_code = ip_address(address_family, address);
switch (failure_code) {
case 0: // Success
return TCL_OK;
case 1: // First type of failure
Tcl_SetResult(interp, "failure of type #1", TCL_STATIC);
return TCL_ERROR;
// ... etc for each expected case ...
default: // Should be unreachable, yes?
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unexpected failure: %d", failure_code));
return TCL_ERROR;
}
Passing back more complex return types with tuples of values (especially a combination of a success indicator and a “real” result value) should also be possible, but I've not got a Go development environment in order to probe how they're mapped at the C level.

GetModuleHandleEx usage example. WTL internationalisation

I am trying to do internationalization in a WTL GUI application .. in my drop down selection change handler (which is used for language selection I do something like this):
int selected = (int)::SendMessage(m_cbLang, CB_GETCURSEL,0,0);
HMODULE hmod;
int retCode = 0;
switch(selected)
{
case 0:
retCode =::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, NULL, &hmod);
ATL::_AtlBaseModule.SetResourceInstance(hmod);
break;
case 1:
retCode =::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, L"GuiLibOther.dll", &hmod);
ATL::_AtlBaseModule.SetResourceInstance(hmod);
break;
}
return S_OK;
Now, I really don't know how to use this function, although it is here , I don t know what the lpModuleName represents. The "GuiLibOther.dll" is a dll which contains the entire interface in another language.. all resources translated to another language.. I want the interface to change the language imediatelly after another language is selected. is this the right way?
Case 0 return hmod = NULL
First of all you don't want to use the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS flag unless you're passing the address of some item in the DLL, which in this case you're not.
Second the documentation implies that the DLL must already be loaded before you call GetModuleHandleEx. If you haven't linked it in to your .exe so that it's automatically loaded, you must use LoadLibrary.
The need to use LoadLibrary suggests a simplification:
static HMODULE hmodExe = INVALID_HANDLE;
static HMODULE hmodDLL1 = INVALID_HANDLE;
switch(selected)
{
case 0:
if (hmodExe == INVALID_HANDLE)
retCode =::GetModuleHandleEx(0, NULL, &hmodExe);
ATL::_AtlBaseModule.SetResourceInstance(hmodExe);
break;
case 1:
if (hmodDLL1 == INVALID_HANDLE)
hmodDLL1 = LoadLibrary(L"GuiLibOther.dll");
ATL::_AtlBaseModule.SetResourceInstance(hmodDLL1);
break;
This should let you switch resource libraries dynamically without extra overhead.

Resources