chessgui has asked for the wisdom of the Perl Monks concerning the following question:

I've managed to put together an XS module which is an interface to the Windows MessageBox function (my ultimate goal is to speak to the System Tray). The XS code:
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "windows.h" MODULE = Mytest PACKAGE = Mytest int hello(input) unsigned int input CODE: int x=MessageBox(NULL,TEXT("Text"),TEXT("Caption"),input); RETVAL=x; OUTPUT: RETVAL
This code works. However if I want to use the 'UINT' data type (which is in the original declaration of the function) instead of 'unsigned int' the make fails:
Error: 'UINT' not in typemap in Mytest.xs, line 12 Please specify prototyping behavior for Mytest.xs (see perlxs manual)
The perlxs manual says that prototypes can be enabled and disabled but I find no guidance for how to use a predefined C prototype.

Replies are listed 'Best First'.
Re: Prototype problem for XS module
by syphilis (Archbishop) on Feb 05, 2012 at 18:40 UTC
    I suspect you'll fix the problem with UINT if you just have a file named 'typemap'(located in the same directory as the xs file) that contains simply:
    UINT T_UV
    That should tell perl to treat "UINT" as a "T_UV" (unsigned int) .... and perl knows all about the "T_UV" type and how to deal with it, courtesy of perl/lib/ExtUtils/typemap.

    (Btw, you don't need to include windows.h - it has already been pulled in by perl.h.)

    Here's a little Inline::C demo that works only if said typemap is present:
    # try.pl use warnings; use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C =><<'EOC'; UINT hello() { UINT x = 17; return x; } EOC $x = hello(); print $x; # On Windows: # Outputs 17 if typemap is present, # Otherwise outputs "Undefined subroutine &main::hello called at try.p +l line 16."



    Cheers,
    Rob
      Fair enough. It works with my XS code as well. (Also true that windows.h is pulled in by default.)

      Now my main problem with NOTIFYICONDATA itself that it needs a hWnd parameter. In other words if I want to have a notify icon I have to have a main window. Currently I have a standalone application which creates a notify icon:
      int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR + lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX icc; WNDCLASSEX wc; LPCTSTR MainWndClass = TEXT("Template"); HWND hWnd; HACCEL hAccelerators; HMENU hSysMenu; MSG msg; // Initialise common controls. icc.dwSize = sizeof(icc); icc.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&icc); // Class for our main window. wc.cbSize = sizeof(wc); wc.style = 0; wc.lpfnWndProc = &MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = (HICON) LoadImage(hInstance, MAKEINTRESOURCE +(IDI_APPICON), IMAGE_ICON, 0, 0, LR_SHARED); wc.hCursor = (HCURSOR) LoadImage(NULL, IDC_ARROW, IMAGE +_CURSOR, 0, 0, LR_SHARED); wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); wc.lpszClassName = MainWndClass; wc.hIconSm = (HICON) LoadImage(hInstance, MAKEINTRESOUR +CE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_SHARED); // Register our window classes, or error. if (! RegisterClassEx(&wc)) { MessageBox(NULL, TEXT("Error registering window class."), TEXT +("Error"), MB_ICONERROR | MB_OK); return 0; } // Create instance of main window. hWnd = CreateWindowEx(0, MainWndClass, MainWndClass, WS_OVERLAPPED +WINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 320, 200, NULL, NULL, +hInstance, NULL); // Error if window creation failed. if (! hWnd) { MessageBox(NULL, TEXT("Error creating main window."), TEXT("Er +ror"), MB_ICONERROR | MB_OK); return 0; } // Create notify icon NOTIFYICONDATA nid; nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hWnd; nid.uID = 100; nid.uVersion = NOTIFYICON_VERSION; nid.uCallbackMessage = WM_MYMESSAGE; nid.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcscpy(nid.szTip, TEXT("Notify Icon")); nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; Shell_NotifyIcon(NIM_ADD, &nid); // Load accelerators. hAccelerators = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_AC +CELERATOR)); // Add "about" to the system menu. hSysMenu = GetSystemMenu(hWnd, FALSE); InsertMenu(hSysMenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); InsertMenu(hSysMenu, 6, MF_BYPOSITION, ID_HELP_ABOUT, TEXT("About" +)); // Show window and force a paint. ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Main message loop. while(GetMessage(&msg, NULL, 0, 0) > 0) { if (! TranslateAccelerator(msg.hwnd, hAccelerators, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } // Finished so withdraw notify icon Shell_NotifyIcon(NIM_DELETE, &nid); return (int) msg.wParam; }
      However in the XS code I guess I can't have a WinMain function.
Re: Prototype problem for XS module
by BrowserUk (Patriarch) on Feb 05, 2012 at 17:15 UTC

    Not an answer to your XS problem, but ActiveState Perl comes with the message box call built-in. Try this:

    perl -MWin32 -E"say'The man, he say: ',Win32::MsgBox('Is this what you + are after?',4,'Just a question')==6 ?'yes':'no'"

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

      Thanks a lot. I used to be an ActiveState customer. Recently I switched to Strawberry since it seemed (and later proved) to be more capable of installing CPAN modules. However I feel more and more that the functionality of even CPAN modules is limited when it comes to interfaces to Windows API. (For example in the Win32::GUI module when I speak to the System Tray a bubble pops up which makes a noise - I don't want this noise). Ceterum censeo there is a need to do it myself and make API calls directly through XS code.
        Thanks a lot. I used to be an ActiveState customer. Recently I switched to Strawberry

        Well, Win32 is a CPAN module too.

        (For example in the Win32::GUI module when I speak to the System Tray a bubble pops up which makes a noise - I don't want this noise).

        The audible alert is a OS user interface feature, not an application feature. That is, a windows user can elect to turn off audible alerts -- it's about the first thing I do when I do a new install -- or not. But it is, and should be, the application users choice to have audible alerts, not the application writers.

        Ceterum censeo there is a need to do it myself and make API calls directly through XS code.

        Learning XS is not a bad thing to do. Though you may well find it a frustrating exercise.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        The start of some sanity?

Re: Prototype problem for XS module
by Anonymous Monk on Feb 05, 2012 at 16:16 UTC
      I'm new to XS programming. I've tried to declare the 'uType' input field to the function as 'UINT' (since this is the way in C the function is declared):
      int WINAPI MessageBox( __in_opt HWND hWnd, __in_opt LPCTSTR lpText, __in_opt LPCTSTR lpCaption, __in UINT uType );
      My first impression from the error message was that I'm completely forbidden to use windows.h declared data types. Now I see that I can use them safely _inside_ a function. The problem only arises with the declaration and passing of args to the function (which is not a big deal: I want to pass only very simple input to the sub, rather use complicated types like NOTIFYICONDATA inside the sub).
Re: Prototype problem for XS module
by Anonymous Monk on Feb 05, 2012 at 16:18 UTC