I want to write a small program that reads data from a text file and then imports it into the Windows Registry. I've found the bindings to the Windows functions in the System.Win32.Registry package, but ran into an issue with the regSetValueEx function. When I want to import a number as a DWORD (Word32) I can't figure out how to pass it to regSetValueEx to get the desired result.
Right now I'm storing the number as a TCHAR and using alloca and poke to get a pointer. Here's the code I'm using for testing:
module Main where
import Foreign.Marshal.Alloc
import Foreign.Storable
import System.Win32.Registry
import System.Win32.Types
number :: TCHAR
number = 42
getKey :: IO HKEY
getKey = regOpenKey hKEY_CURRENT_USER "test"
importFromTCHAR :: IO ()
importFromTCHAR = alloca $ \ptr -> do
poke ptr number
key <- getKey
regSetValueEx key "tchar" rEG_DWORD ptr (sizeOf (undefined::DWORD))
main :: IO ()
main = importFromTCHAR
The result: 0x0184002a
It kinda works, but since the size of a TCHAR value is only 2 bytes the other two bytes is taken up by junk. How can I prevent this? Any help would be greatly appreciated. I'm fairly new to Haskell (only recently finished LYAH), so please go easy on me. :)
Also, I'd really like to know what libraries more experienced Haskellers use to interface with the Windows Registry. Is there any libraries that makes working with it easier?
EDIT: Alright, as it turns out while looking through the packages on Hackage I somehow missed the castPtr function in the Foreign.Ptr package. I feel like an idiot, because with it the solution is really easy. As per Ilya's answer I just need to store the number as a Word32 (or DWORD), poke it into the pointer alloca gives me and then call castPtr on it before I pass it to regSetValueEx. Here's the modified code:
module Main where
import Foreign.Marshal.Alloc
import Foreign.Ptr
import Foreign.Storable
import System.Win32.Registry
import System.Win32.Types
number :: DWORD
number = 42
getKey :: IO HKEY
getKey = regOpenKey hKEY_CURRENT_USER "test"
importFromDWORD :: IO ()
importFromDWORD = alloca $ \ptr -> do
poke ptr number
key <- getKey
regSetValueEx key "dword" rEG_DWORD (castPtr ptr) (sizeOf number)
main :: IO ()
main = importFromDWORD
Just define number as Word32 from Data.Word:
number :: Word32
number = 42
Also you can use sizeOf on normal value like: sizeOf number
Related
I am trying to write a simle rust console application that calls into WINAPI.
I will ommit the obvious use and extern crate parts of my code. Here it is:
fn win32_string(value : &str ) -> Vec<u16> {
OsStr::new( value ).encode_wide().chain( once( 0 ) ).collect()
}
fn main() {
println!("===== Rust Windows experiment #1 =====");
let module_name = win32_string("ntdll.dll");
let h_instance: HMODULE;
unsafe {
h_instance = GetModuleHandleW(module_name.as_ptr());
}
println!("Value of h_instance: {:#?}", h_instance);
}
I am building it against the target triple:
[build]
target = "i686-pc-windows-msvc"
As you can see I am targeting to build a 32 bit application. Now the output of my program is the following:
===== Rust Windows experiment #1 =====
Value of h_instance: 0x00007ffb61c40000
It is showing a 64 bit address. How can this happen? Am I writing the HMODULE value wrongly to the console, or what am I doing wrong?
With help from rodrigo: The build tag is supposed to be included in the .cargo\config file instead of the cargo.toml file, in order for the compiler to pick it up. :) After changing that the issue is now fixed. :)
I'm trying to make a fortan code for displaying a colored ASCII art of 2D graphics in command prompt on Windows 10 systems, like a code distributed in the website below.
https://sites.google.com/site/akohlmey/random-hacks/text-mode-graphics-for-fortran
I have heard that command prompt on Windows 10 partially support ANSI escape sequences, and it is available if we enable the virtual terminal processing option.
There are some examples in C code, but I want to make a function or subroutine to enable ANSI escape sequences by Fortran code. For example, is it difficult to rewrite following simple C function by a Fortran function (or subroutine)?
bool enable_virtual_terminal_processing(FILE *stream) {
HANDLE handle = (HANDLE)_get_osfhandle(_fileno(stream));
DWORD mode = 0;
if (!GetConsoleMode(handle, &mode)) {
return false;
}
if (!SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
return false;
}
return true;
}
An example below of Fortran source calling the necessary Windows APIs to set the console to the correct mode. Calling Windows APIs makes this source inherently platform specific - there are also some compiler specific directives (ifort and gfortran variants provided) necessary to fully define the API interfaces.
The library for the Win32 kernel API's will also need to be accessible, but this is often installed (or required) as part of installing a compiler on Windows.
Some compilers provide modules with the relevant interfaces to the Windows API, saving you the trouble of having to write them yourself.
PROGRAM WriteAnsi
IMPLICIT NONE
CALL set_ansi
PRINT "(A)", &
ACHAR(27) // '[31m' // 'H' // &
ACHAR(27) // '[32m' // 'e' // &
ACHAR(27) // '[33m' // 'l' // &
ACHAR(27) // '[34m' // 'l' // &
ACHAR(27) // '[35m' // 'o' // &
ACHAR(27) // '[0m'
CONTAINS
SUBROUTINE set_ansi
USE, INTRINSIC :: ISO_C_BINDING, ONLY: &
DWORD => C_LONG, & ! C_INT32_T really, but this is per the docs
HANDLE => C_INTPTR_T, &
BOOL => C_INT
INTEGER(HANDLE), PARAMETER :: INVALID_HANDLE_VALUE = -1_HANDLE
INTERFACE
FUNCTION GetStdHandle(nStdHandle) BIND(C, NAME='GetStdHandle')
IMPORT :: DWORD
IMPORT :: HANDLE
IMPLICIT NONE
INTEGER(DWORD), INTENT(IN), VALUE :: nStdHandle
INTEGER(HANDLE) :: GetStdHandle
!DEC$ ATTRIBUTES STDCALL :: GetStdHandle
!GCC$ ATTRIBUTES STDCALL :: GetStdHandle
END FUNCTION GetStdHandle
END INTERFACE
INTEGER(DWORD), PARAMETER :: STD_INPUT_HANDLE = -10_DWORD
INTEGER(DWORD), PARAMETER :: STD_OUTPUT_HANDLE = -11_DWORD
INTEGER(DWORD), PARAMETER :: STD_ERROR_HANDLE = -12_DWORD
INTERFACE
FUNCTION GetConsoleMode(hConsoleHandle, lpMode) BIND(C, NAME='GetConsoleMode')
IMPORT :: HANDLE
IMPORT :: DWORD
IMPORT :: BOOL
IMPLICIT NONE
INTEGER(HANDLE), INTENT(IN), VALUE :: hConsoleHandle
INTEGER(DWORD), INTENT(OUT) :: lpMode
!DEC$ ATTRIBUTES REFERENCE :: lpMode
INTEGER(BOOL) :: GetConsoleMode
!DEC$ ATTRIBUTES STDCALL :: GetConsoleMode
!GCC$ ATTRIBUTES STDCALL :: GetConsoleMode
END FUNCTION GetConsoleMode
END INTERFACE
INTEGER(DWORD), PARAMETER :: ENABLE_ECHO_INPUT = INT(Z'0004', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_INSERT_MODE = INT(Z'0020', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_LINE_INPUT = INT(Z'0002', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_MOUSE_INPUT = INT(Z'0010', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_PROCESSED_INPUT = INT(Z'0001', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_QUICK_EDIT_MODE = INT(Z'0040', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_WINDOW_INPUT = INT(Z'0008', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_VIRTUAL_TERMINAL_INPUT = INT(Z'0200', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_PROCESSED_OUTPUT = INT(Z'0001', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_WRAP_AT_EOL_OUTPUT = INT(Z'0002', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_VIRTUAL_TERMINAL_PROCESSING = INT(Z'0004', DWORD)
INTEGER(DWORD), PARAMETER :: DISABLE_NEWLINE_AUTO_RETURN = INT(Z'00008', DWORD)
INTEGER(DWORD), PARAMETER :: ENABLE_LVB_GRID_WORLDWIDE = INT(Z'0010', DWORD)
INTERFACE
FUNCTION SetConsoleMode(hConsoleHandle, dwMode) BIND(C, NAME='SetConsoleMode')
IMPORT :: HANDLE
IMPORT :: DWORD
IMPORT :: BOOL
IMPLICIT NONE
INTEGER(HANDLE), INTENT(IN), VALUE :: hConsoleHandle
INTEGER(DWORD), INTENT(IN), VALUE :: dwMode
INTEGER(BOOL) :: SetConsoleMode
!DEC$ ATTRIBUTES STDCALL :: SetConsoleMode
!GCC$ ATTRIBUTES STDCALL :: SetConsoleMode
END FUNCTION SetConsoleMode
END INTERFACE
INTEGER(DWORD), PARAMETER :: ENABLE_EXTENDED_FLAGS = INT(Z'0080', DWORD)
INTEGER(HANDLE) :: output_handle
INTEGER(BOOL) :: api_result
INTEGER(DWORD) :: mode
output_handle = GetStdHandle(STD_OUTPUT_HANDLE)
IF (output_handle == INVALID_HANDLE_VALUE) THEN
ERROR STOP 'GetStdHandle failed'
END IF
api_result = GetConsoleMode(output_handle, mode)
IF (api_result == 0_BOOL) THEN
ERROR STOP 'GetConsoleMode failed'
END IF
api_result = SetConsoleMode( &
output_handle, &
IOR(mode, ENABLE_VIRTUAL_TERMINAL_PROCESSING) )
IF (api_result == 0_BOOL) THEN
ERROR STOP 'SetConsoleMode failed'
END IF
END SUBROUTINE set_ansi
END PROGRAM WriteAnsi
It is easy to call a C function from Fortran (hundreds of questions and answers here).
And it is almost impossible to write the above in Fortran, it is systems programming, you would need the right libraries Maybe some compilers supply them, but it is not standard.
Just call your C function from Fortran. The FILE * argument wonn't be available in Fortran directly, you need to get the pointer in C as well.
After enabling, you can write the sequences very easily How to print in the same position in fortran clear screen in Fortran
I'm developing a daemon with no UI apart from a simple icon in the Windows systray.
I would like to have no dependencies on any other package(s), so I'm trying to use the syscall package and implement the necessary call(s) by myself.
Documentation
After some research, I think that I must use the Shell_NotifyIcon function in shell32.dll.
The Golang WIKI gives three ways to call a Windows DLL. The third solution is to be excluded. For many reasons, I want to build sources with the Golang compiler only.
I found an interesting article on "Developing for Multiple Platforms With Go" which explained how to use Shell_NotifyIconW (Unicode declination), but the implementation is partial.
I have found a few Golang libraries which implement Windows System Tray. They are useful to help understand the structure and calls involved in dealing with it.
Libraries
getlantern/systray
cratonica/trayhost
xilp/systray
lxn/walk
Implementation
Structures
Built with xilp/systray documentation.
type HANDLE uintptr
type HICON HANDLE
type HWND HANDLE
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
type NOTIFYICONDATA struct {
CbSize uint32
HWnd HWND
UID uint32
UFlags uint32
UCallbackMessage uint32
HIcon HICON
SzTip [128]uint16
DwState uint32
DwStateMask uint32
SzInfo [256]uint16
UVersion uint32
SzInfoTitle [64]uint16
DwInfoFlags uint32
GuidItem GUID
}
Variables
const (
NIM_ADD = 0x00000000
NIM_MODIFY = 0x00000001
NIM_DELETE = 0x00000002
NIM_SETVERSION = 0x00000004
NIF_MESSAGE = 0x00000001
NIF_ICON = 0x00000002
NIF_TIP = 0x00000004
NIF_STATE = 0x00000008
NIF_HIDDEN = 0x00000001
)
Source
package main
import (
"log"
"syscall"
"unsafe"
)
func main() {
shell32 := syscall.MustLoadDLL("shell32.dll")
Shell_NotifyIcon := shell32.MustFindProc("Shell_NotifyIconW")
iconData := NOTIFYICONDATA{
HWnd: 0,
UFlags: NIF_MESSAGE | NIF_STATE,
DwState: NIF_HIDDEN,
DwStateMask: NIS_HIDDEN,
}
iconData.CbSize = uint32(unsafe.Sizeof(iconData))
ret, _, _ := Shell_NotifyIcon.Call(
NIM_ADD,
uintptr(unsafe.Pointer(&iconData)),
)
if ret == 0 {
log.Println("Failed")
return
}
// Do anything, like open a HTTP server to keep the program running
http.ListenAndServe(":8080", nil)
}
Details
I have no idea what information to give in HWnd, but without it, the executable crashes.
UFlags, DwState and DwStateMask have values that I have found in different projects.
I know that it is possible; the Golang WIKI gives an implementation to call a message box.
Fields of NOTIFYICONDATA
hWnd
hWnd field of NOTIFYICONDATA holds a window handle that is associated with notifyicon itself, as mentioned in MSDN:
hWnd
A handle to the window that receives notifications associated with an icon in the notification area.
I found that it's necessary to associate a window handle, even if the window is not visible.
uFlags tells which fields of NOTIFYICONDATA are valid in single command.
As you see there are lots of fields in NOTIFYICONDATA, and if you are going to change just the icon of the notifyicon, you can leave other fields unchanged and set only hIcon field then pass the whole NOTIFYICONDATA to Shell_NotifyIcon.
If you want to change both icon and message, just set it to NIF_MESSAGE|NIF_ICON.
dwState
dwState can be used to control icon's visibility. If you specify NIF_STATE for uFlags, and NIS_HIDDEN for dwState and dwStateMask, it'll make notifyicon hidden.
dwStateMask
And in most case, just set dwStateMask as same as dwState. It just tells which bit of dwState is valid for the command:
The possible values are the same as those for dwState.
Example
You can find full example I've wrote at here: https://github.com/hallazzang/go-windows-programming/tree/master/example/gui/notifyicon
I have some fortran tests I would like to run in CTest using create_test_sourcelist. This is a utility that creates a driver in C or C++, which calls the fortran test routines and expects the signature:
int fortname(int argv, char** argc)
Can someone explain the correct way to interface this signature, probably with iso_c_bindings as I understand these are getting pretty standard. I believe it is the char** that is making me hurt -- there are plenty of examples around for the integer argument.
Thanks!
Assuming that the meaning of argc and argv in the context of a C program's main function apply, then you could do something like:
! Default binding label is already lower case, but for clarity
! it is good practice to specify the binding label explicitly.
function fortname(argc, argv) bind(c, name='fortname')
use, intrinsic :: iso_c_binding, only: c_int, c_ptr
implicit none
!----
! Note C std allows argc == 0
integer(c_int), intent(in), value :: argc
! Lower bound set to match C convention where element 0 probably
! is name of program. May be zero size.
type(c_ptr), intent(in) :: argv(0:argc-1)
! Function result.
integer(c_int) :: fortname
To convert those arguments across to something that is easier to use in Fortran (and further assuming that your Fortran processor supports all applicable parts of the Fortran 2003 standard, noting that deferred length character components are not currently supported by at least one commonly used processor) you could then...
!----
! Name of the program.
character(:), allocatable :: prog_name
! Type to use for arrays of pointers to variable length strings.
type :: string
character(:), allocatable :: item
end type string
! Our arguments. May be zero size.
type(string) :: arguments(argc-1)
integer :: i ! argument index.
!****
if (argc > 0) then ! argv has something useful
! make program name accessible to fortran code.
call c_f_string(argv(0), prog_name)
! make arguments accessible to fortran code.
do i = 1, size(arguments)
call c_f_string(argv(i), arguments(i)%item)
end do
else ! no useful information provided in argv
prog_name = ''
end if
! Work with arguments%item and prog_name...
print "(A)", prog_name
do i = 1, size(arguments) ; print "(A)", arguments(i)%item ; end do
fortname = 0
contains
! Copy a null terminated C string (specified via a non-null c_ptr) to an
! allocatable deferred length default character variable.
subroutine c_f_string(c_string, f_string)
use, intrinsic :: iso_c_binding, only: c_char, c_null_char, c_f_pointer
!----
type(c_ptr), intent(in) :: c_string
character(:), intent(out), allocatable :: f_string
!----
! Array for accessing string pointed at by C pointer
character(kind=c_char), pointer :: string_ptr(:)
integer :: i ! string index
interface
! Steal std C library function rather than writing our own.
function strlen(s) bind(c, name='strlen')
use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t
implicit none
!----
type(c_ptr), intent(in), value :: s
integer(c_size_t) :: strlen
end function strlen
end interface
!****
! Map C pointer to fortran character array
call c_f_pointer(c_string, string_ptr, [strlen(c_string)])
! Allocate fortran character variable to the c string's length
allocate(character(size(string_ptr)) :: f_string)
! Copy across (with possible kind conversion) characters
forall (i = 1:size(string_ptr)) f_string(i:i) = string_ptr(i)
end subroutine c_f_string
end function fortname
Your fortran declaration would be something like this (I think you got argc and argv mixed up so I swapped them):
function fortname(argc, argv) bind(c)
use iso_c_binding
integer(c_int), value :: argc
type(c_ptr) :: argv
end function
You then need to write some code to convert argc to a fortran type. You can convert c pointer to fortran pointers using the c_f_ptr instrinsic. The tricky bit is that you have the double indirection, since fortran doesn't support the concept of a pointer to a pointer. Possibly the following would work, which prints out each argument
type(c_ptr), pointer :: argv_f
character(c_char), pointer :: string_n
call c_f_ptr(argv, argv_f)
do n=1,argc
call_c_f_ptr(argvf(n), string_n)
print *, string_n
end do
Disclaimer: I haven't compiled or run this code!
If a dll exports some functions and the functions have only ordinal numbers, how can I call the functions?
Give me a short example please.
The documentation for GetProcAddress explains that you pass the integer ordinal in the low-order word of the lpProcName parameter. The MAKEINTRESOURCE macro can actually be used to make this a little easier:
int ordinal = 123;
HANDLE dll = LoadLibrary("MyDLL.dll");
FARPROC fn = GetProcAddress(dll, MAKEINTRESOURCE(ordinal));