Hello, everybody. Happy to introduce my new project - Winim.
I like Nim, and I usually coding under Windows. There is a oldwinapi for Windows API wrapper. But it is old and incompleted. So I start this project. Compare to oldwinapi, this module:
Install
nimble install winim
MessageBox Example
import winim
MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
Interface Example
import os, winim
var
pIL: ptr IShellLink
pPF: ptr IPersistFile
try:
CoInitialize(nil)
if CoCreateInstance(&CLSID_ShellLink, nil, CLSCTX_LOCAL_SERVER, &IID_IShellLink, cast[ptr PVOID](&pIL)).FAILED: raise
defer: pIL.Release()
if pIL.QueryInterface(&IID_IPersistFile, cast[ptr PVOID](&pPF)).FAILED: raise
defer: pPF.Release()
if pIL.SetPath(getAppFilename()).FAILED or pPF.Save("link.lnk", true).FAILED: raise
except:
echo "something wrong !!"
COM Example
import winim.com
comScript:
var dict = CreateObject("Scripting.Dictionary")
dict.add("a", "the")
dict.add("b", "quick")
dict.add("c", "fox")
dict.item("c") = "dog" # this line needs comScript macro
for key in dict:
echo key, " => ", dict.item(key)
More details on website.
Very nice but I think it should adhere to NEP-1.
I think we should just call it the "style guide", it's not even called NEP-1 in the wiki anymore.
WSH scripts in VBScript and in Nim are looking so alike, and so easy to translate!
Thanks a lot!
This is really cool and I've been meaning to port COM to Nim myself, so will definitely be using this.
Only thing I thought was the '&' for address seems like going backwards - why port the & symbol from other languages when you can write .addr and it works the same?
Aside from that niggle, I'm looking forward to trying this out! :D
First of all, I need a way to get the pointer to a const object. So I can write:
QueryInterface(&IID_IPersistFile)
instead of:
var iid = IID_IPersistFile
QueryInterface(addr iid)
And then, I need a way to get the address of string/wstring/mstring to pass into windows API. Choosing & symbol to do these seems naturally. At last, since this symbol already have these two functions, so I let it do more, get all variables' address.
BTW, for string/wstring/mstring, & symbol is not the same as addr. It more like s[0].addr but aware nil.
Here is the demo for extract all the constants from associated typelib. I will add this function in next version.
import winim.com
let word = CreateObject("Word.Application")
var disp = word.unwarp
var tinfo: ptr ITypeInfo
var tlib: ptr ITypeLib
var index: UINT
var kind: TYPEKIND
disp.GetTypeInfo(0, 0, addr tinfo)
tinfo.GetContainingTypeLib(addr tlib, addr index)
tlib.GetTypeInfoCount()
for i in 0..<tlib.GetTypeInfoCount():
tlib.GetTypeInfoType(UINT i, addr kind)
if kind == TKIND_ENUM:
var tinfoEnum: ptr ITypeInfo
var attr: ptr TYPEATTR
var desc: ptr VARDESC
var name: BSTR
var nameCount: UINT
tlib.GetTypeInfo(UINT i, addr tinfoEnum)
tinfoEnum.GetTypeAttr(addr attr)
for j in 0..<int attr.cVars:
tinfoEnum.GetVarDesc(UINT j, addr desc)
if desc.varkind == VAR_CONST:
tinfoEnum.GetNames(desc.memid, addr name, 1, addr nameCount)
echo $name, " = ", desc[].lpvarValue[].toVariant
word.Quit
COM_FullRelease()
not the author but...
machine and translation by hand of mingw windows related apis mostly nim "entry" points for winapi There is not a unified stdlib quality interface for all things critical like Go has for example (x/windows). No idea about the size.
@Ward, How to use SetWindowLongPtrW in Nim ? This is my Wndproc signature
proc RED_WndProc*(hwnd: HWND, message: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT {.stdcall} =
And this the call site;
OldWndProc = SetWindowLongPtrW(result, GWLP_WNDPROC, RED_WndProc)
When using function name as it is, the result is this - Error: type mismatch: got <HWND, int literal(-4), proc (hwnd: HWND, message: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT{.stdcall, locks: <unknown>.}>
Then i tried with this
OldWndProc = SetWindowLongPtrW(result, GWLP_WNDPROC, cast[LONG](RED_WndProc))
And the result is - Error: type mismatch: got <LONG_PTR> but expected 'WNDPROC = proc (P1: HWND, P2: UINT, P3: WPARAM, P4: LPARAM): LRESULT{.stdcall.}'
Then i tried with this -
OldWndProc = SetWindowLongPtrW(result, GWLP_WNDPROC, cast[WNDPROC](RED_WndProc))
Error: type mismatch: got <HWND, int literal(-4), WNDPROC> but expected one of:
Is it a replacement for oldwinapi?
Yes.
Does it add wrapper classes around the winapi stuff or does it just provide nim-ish entry points for it?
No wrapper classes.
How much does it add to the application's size?
It don't add application's size, unless you use the winstr or com module.
Could existing oldwinapi code be migrated piecemeal to winim?
I think so, but need to test.
Winim looks great.
Any suggestions for how to cross compile a 32 bit exe from a Linux box. Coding on my Windows laptop is awful! ! !
Something like this worked for oldwinapi:
nim --cpu:i386 --os:windows c -r hellomsg
By the way, the nim.cfg in the working directory is:
i386.windows.gcc.path = "/usr/bin"
i386.windows.gcc.exe = "i686-w64-mingw32-gcc"
i386.windows.gcc.linkerexe = "i686-w64-mingw32-gcc"
When I tried the above I got a linker(?) error like:
/etcetc/.nimble/pkgs/winim-2.5.1/winim/inc\..\lib\winim32.res: No such file or directory
Although I can see the winim32.res file as:
/etcetc/.nimble/pkgs/winim-2.5.1/winim/lib/winim32.res
I never could get cross compiling to 64 bit exe to work on my projects.