[c++] Experimenting with the Windows API

403 views
Skip to first unread message

rb1147x

unread,
Feb 13, 2017, 10:48:03 PM2/13/17
to Haxe
Hi,

Tonight I explored accessing the Windows API from Haxe. My initial Googling provided me with these two articles: https://haxe.io/roundups/wwx/c++-magic/ and http://www.joshuagranick.com/2012/09/14/adding-inline-cpp-to-haxe-code/ ... so I quickly gave up on accessing Windows DLLs and started using 'c++ magic'. 

My first question: Is it possible to access the Windows API / Windows DLLs directly from Haxe? 

.. As for c++ magic, I started to play around with @:headerCode, @:functionCode and the Windows API. I wanted to see if and how I could get some of the Windows functions to work. I began at first with just trying 'untyped MessageBox()', like in one of the above linked articles. Then I moved onto FindWindow(). With Notepad open I was able to successfully find the window:


@:headerCode("#include <windows.h>")
class Main {
    static function main() {

        var hwnd = untyped FindWindow(0, "Untitled - Notepad");

        trace(hwnd); 

    }
}


Here, 'hwnd' returns true if Notepad is open and false if Notepad is not open.

I was not expecting true or false. I imagined the actual window handle (of which I believe is a pointer value) to be returned (because Haxe is magic!). And this is where I am now stuck. I've tried several of the cpp.Pointer methods hoping they would return the actual value. Most return errors during compilation. My first thought was that cpp.Pointer.fromHandle() would work, but instead of returning an error, it successfully compiles and returns

 Pointer(00000000)

from 'trace(cpp.Pointer.fromHandle(hwnd));'


So far, I've only been able to get the value to display with @:functionCode and writing it all in C. Of course, I still can't pass back the hwnd value, though.

@:headerCode("#include <windows.h>")
class Main {
    static function main() {

        var num = printMe(); 

        trace("\n" + num);

    }

    @:functionCode('
            HWND h;

            h = FindWindow(0, "Untitled - Notepad");

            printf("%p", h);

            return h;
        ')
    static function printMe(): Dynamic {
        return 0;
    }
}

In the above code, the pointer value gets printed from the printf() function, but trace("\n" + num); just returns 'true'.

So.... first is it possible to access the Windows API (or Windows DLLs) directly from Haxe?

And second, using c++ magic is there just no HWND type that maps to the Haxe cpp API?

Thanks!


Hugh

unread,
Feb 13, 2017, 11:57:36 PM2/13/17
to Haxe
The problem here is that hxcpp does not know what type is being returned from 'FindWindow', so you have to tell it using externs.
These days, you should avoid @:functionCode and 'untyped' and describe external functions with haxe types and "@:native".
The closest thing to 'HWND'  (handle) is a pointer-to-void.  So you can do:


typedef HWND = cpp.Pointer<cpp.Void>;


@:headerCode("#include <windows.h>")
class Test {


   
@:native("FindWindow") @:extern
   
public static function findWindow(className:String, windowName:String) : HWND return null;

   
static function main()
   
{
        trace
( findWindow(null, "Untitled - Notepad") );
   
}
}

the haxe compiler will replace little-f findWindow with big-f FindWindow because the '@:native' renames the function.
The hxcpp string will convert to a "const char *" automatically.  The return value will convert to a pointer (not a bool) since you have specified the return type.

Hugh

Hugh

unread,
Feb 14, 2017, 12:01:50 AM2/14/17
to Haxe
Actually, the correct definition should be:
public static function findWindow(className:cpp.ConstCharStar, windowName:cpp.ConstCharStar) : HWND return null;

You can still pass Strings to this, but you can also pass the more native "const char *" data types, and it the compiler creates some temp variables, they will be typed correctly.

rb1147x

unread,
Feb 14, 2017, 2:34:18 PM2/14/17
to Haxe
This is fantastic! Thank you!

Cambiata

unread,
Feb 16, 2017, 12:32:51 AM2/16/17
to Haxe
Thank you, Hugh!
Would love to see info about this in the manual and Code Cookbook.
(Might create a recepie myself.)

And it would be great if you could keep us informed about your project
and the progress, rb1147x! :-)

Jonas

rb1147x

unread,
Feb 16, 2017, 12:49:26 PM2/16/17
to Haxe
At the moment I'm just experimenting... In the past I've interacted with the WinAPI with VB6 and Free Pascal, but wanted to try with Haxe.

For this example I'm just trying to send a message (e.g. a mouse click, keyboard click, etc) to another running process. In this case, sending a mouse click to Notepad.

However, when trying to compile, I receive an error:

error C2664: 'BOOL PostMessageA(HWND,UINT,WPARAM,LPARAM)': cannot convert argument 1 from 'cpp::Pointer<void>' to 'HWND'

From Hugh's explanation and looking up Windows data types I'm not entirely sure why a conversion is needed though...


typedef HWND = cpp.Pointer<cpp.Void>;

@:headerCode("#include <windows.h>")
class Main {

    @:native("FindWindow") 
    @:extern
    public static function findWindow(className:cpp.ConstCharStar, windowName:cpp.ConstCharStar) : HWND return null;

    @:native("PostMessage")
    @:extern
    public static function postMessage(h:HWND, msg:cpp.UInt32, wParam:Int, lParam:Int) : Bool return null;


    static function main() {

        var h = findWindow(null, "Untitled - Notepad");
        trace(h);

        postMessage(h, 0x0201, 0 ,0);

    }        
}

Hugh

unread,
Feb 17, 2017, 12:51:10 AM2/17/17
to Haxe
Yes, the correct definition I think is:
@:native("HWND__") extern class HWNDStruct { }
typedef HWND = cpp.Pointer<HWNDStruct>;

 
And similarly for the other "HDC" etc handles.  So working example:


@:native("HWND__") extern class HWNDStruct { }
typedef HWND = cpp.Pointer<HWNDStruct>;


@:headerCode('#include <windows.h>
'
)
class RenameWindow {
   
@:native("SetWindowText") @:extern
   
public static function SetWindowText(h:HWND, text:cpp.ConstCharStar) : Bool return false;


   
@:native("FindWindow") @:extern
   
public static function findWindow(className:cpp.ConstCharStar, windowName:cpp.ConstCharStar) : HWND return null;


   
static function main()
   
{
       
var args = Sys.args();
       
if (args.length!=2)
         
Sys.println("Usage : RenameWindow fromName toName");
       
else
       
{
         
var h = findWindow(null, args[0]);
         
if (h==null)
             
Sys.println('Could not find window "${args[0]}"');
         
else
             
SetWindowText(h, args[1]);
       
}
   
}
}




rb1147x

unread,
Feb 17, 2017, 11:46:53 AM2/17/17
to Haxe
Thanks, Hugh. Where did you find this definition?
Reply all
Reply to author
Forward
0 new messages