winapiexec

winapiexec is a small tool that allows to run WinAPI functions through command line parameters.

Syntax

The syntax is:
winapiexec.exe library.dll@FunctionName 123 unicode_text "a space"

If you don’t specify a library or use “k”, kernel32.dll is used.
If you specify “u” as a library, user32.dll is used.

Numbers are detected automatically. You can use hex numbers (like 0xFE) and use the minus sign (e.g. -5).
Strings are Unicode by default.

You can use special prefixes to specify parameter types:
$s:ansi – an ANSI string.
$u:unicode – a Unicode string (it’s Unicode by default, but you can use it to force numbers as strings).
$b:1024 – a zero-bytes buffer with the size you specify, in bytes.
$$:1 – a reference to another parameter, you can also use $$:0 for the program’s name (argv[0]).
$a:0,1,two,3 – an array of parameters, divided by commas. You can use all the prefixes here. Each parameter is a 32-bit number (64-bit for winapiexec64).
$a[1,2,$a[3,4],5] – an alternative syntax for an array of parameters. Allows to have nested arrays.
$$:3@2 – a reference to an item in an array of parameters, can have more than one indirection.

While referencing another parameter, note that they are processed by the order of execution, which means there’s no point to reference a parameter at the right side relative to the referencing one.
Also note that when a function returns, its first parameter (like library.dll@FunctionName) is replaced with the return value.

You can execute multiple WinAPI functions, one after the other, using a comma:
winapiexec.exe library.dll@FunctionName1 123 , library.dll@FunctionName2 456
You can also have nested functions, using parentheses:
winapiexec.exe library.dll@FunctionName1 ( library.dll@FunctionName2 456 )
In this case the return value of the internal function is passed as a parameter to the external function.

Download

zip winapiexec.zip (6.02 kB)

Source code

https://github.com/m417z/winapiexec

Examples

Here are some examples of what you can do:

Display temp path:
winapiexec.exe GetTempPathW 260 $b:520 , u@MessageBoxW 0 $$:3 $$:0 0x40

Greetings:
winapiexec.exe advapi32.dll@GetUserNameW $b:65534 $a:32767 , u@wsprintfW $b:2050 "Hello %s from %s" $$:2 $$:0 , u@MessageBoxW 0 $$:6 ... 0

Hide the taskbar for half a second, then show it:
winapiexec.exe u@ShowWindow ( u@FindWindowW Shell_TrayWnd 0 ) 0 , Sleep 500 , u@ShowWindow $$:3 5

Run Notepad for a second, then terminate it:
winapiexec.exe CreateProcessW 0 notepad.exe 0 0 0 0x20 0 0 $a:0x44,,,,,,,,,,,,,,,, $b:16 , Sleep 1000 , TerminateProcess $$:11@0 0

Show a message box and then create a new instance of the process:
winapiexec.exe u@MessageBoxW 0 Hello! :) 0 , CreateProcessW $$:0 ( GetCommandLineW ) 0 0 0 0x20 0 0 $a:0x44,,,,,,,,,,,,,,,, $b:16

Eject your disc drive 🙂
winapiexec.exe winmm.dll@mciSendStringW "open cdaudio" 0 0 0 , winmm.dll@mciSendStringW "set cdaudio door open" 0 0 0 , winmm.dll@mciSendStringW "close cdaudio" 0 0 0

And several more practical examples…

Copy some text into the clipboard:
winapiexec.exe lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) "Sample text" , GlobalUnlock $$:5 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:5 , u@CloseClipboard

Turn off and on monitor:
winapiexec.exe u@SendMessageW 0xFFFF 0x112 0xF170 2
winapiexec.exe u@SendMessageW 0xFFFF 0x112 0xF170 -1

Clear the icon cache:
winapiexec.exe shell32.dll@SHChangeNotify 0x08000000 0 0 0

Display the Start menu:
winapiexec.exe u@SendMessageW ( u@FindWindowW Shell_TrayWnd 0 ) 0x111 305 0
Run task manager:
winapiexec.exe u@SendMessageW ( u@FindWindowW Shell_TrayWnd 0 ) 0x111 420 0
More tricks like the last two can be found here.

Posted in Releases, Software by Michael (Ramen Software) on January 8th, 2011.
Tags:

222 Responses to “winapiexec”

  1. xpclient says:

    What would be the command to show the Quick launch? 🙂

  2. mike says:

    I have the clock hidden in the system tray (windows 7) so I just want to know if there is a way to open the clock window (ex: http://windows7themes.net/pics/windows-7-taskbar-clock.jpg) via command line?

    Thanks in advance and keep up the good work

  3. Anonymous says:

    Does winapiexec allow sending an e-mail with custom message text and attachments via the default e-mail client?
    A while ago I tried to find a way to modify the default text Windows forces upon the user (“Your message is ready to be sent with the following file or link attachments:”) but I think I gave up.
    I think I was trying to take advantage of Windows’ simple image resizing interface. There may be other ways to achieve this (AutoHotkey), though.

  4. Mark Hopkins says:

    I took the UNIX/POSIX language BC, a while back, and upgraded it practically into a C interpreter, called C-BC. I can take some of that code and language design, remake it into a command shell and adapt it into your program’s source code, if you wish.

    C-BC has the “include” directive, so it has the ability to load modules containing pre-defined routines as well.

    The proposed extension would be invoked by just calling “winapiexec.exe” with no command-line arguments. Alternatively, it might be invoked with an argument like $@ to start the shell in mid-command. Or, the modified program might be given a different name, such as wsh.exe, mssh.exe or winsh.exe.

    The main question on my mind is how much of C-BC’s facilities to keep intact. I’d probably take out or replace its data types (extended precision numbers, strings, arrays and pointers) with a simpler system of types (bytes, words, strings, arrays). On the other hand, the temptation is strong to go into the opposite direction and throw in the whole type system of a modern language: polymorphism, abstract types, classes and all.

    The other question, of course, is what unforeseen consequences there will be in combining a command-line windows API processor with a programming language interpreter.

    If you’re interested, send an e-mail note.

    • Hi Mark,

      1995, huh? I was 4 back then 😛

      I can take some of that code and language design, remake it into a command shell and adapt it into your program’s source code, if you wish.

      If I wish? I won’t mind.

      the temptation is strong to go into the opposite direction and throw in the whole type system of a modern language: polymorphism, abstract types, classes and all.

      Polymorphism and classes in a command shell? o_O

      Do I get it right, that by command shell you mean something like cmd.exe? I’m not very familiar with UNIX/POSIX OSes, but from what I understand, you want to extend the syntax to include C-BC functions, to allow e.g. to create a while loop from command line?

      A couple of examples of what would it look like or what would it be able to do will help me get the idea better.

      Regards.

      • Mark says:

        You were 4? That’s a pretty good memory. Though I have to admit, my earliest memory was some time around the age of 3-6 months.

        But C-BC was put out in October 1993, not 1995. The source is 4000 lines and I was always intending on putting threaded multitasking directly in C-BC. This would yield a vastly simplified wrapper for WinAPI, if it is properly integrated with it. It goes the other way too. It’s easier to put multithreading in the language if it can deferred to native OS API’s. The 2010 extensions to C/C++ may also help, though they’re 20 years overdue.

        I’ll back away a little from all this to think more about everything — especially with Windows and even PC’s quickly falling out of date.

        But yes, in answer to your question: shells do loops, branches and other control flow as a matter of course. Take a look at the page on C-shell at http://en.wikipedia.org/wiki/C_shell and there are similar features are in Window shell, too … http://en.wikipedia.org/wiki/Cmd.exe and even in DOS… http://en.wikipedia.org/wiki/COMMAND.COM which is what Windows shell was up until Windows XP.

        But nobody pulls out the Windows API up front. I also found this comparison for command line shells:
        http://en.wikipedia.org/wiki/Comparison_of_command_shells

        Scripting languages, do control flow too, like these:
        Perl: http://en.wikipedia.org/wiki/Perl
        Python: http://en.wikipedia.org/wiki/Python_(programming_language)

        both of which has more contemporary systems of data types built into them.

        But after thinking about all this, it might actually be better to focus on mobile systems (or even Linux), rather than Windows.

        • You were 4? That’s a pretty good memory. Though I have to admit, my earliest memory was some time around the age of 3-6 months.

          I found the article in Google, and just wanted to say it was written a long time ago. I surely wasn’t interested in programming when I was 4.

          Anyway, winapiexec is a tiny <4 KB tool that I wrote for no specific purpose. The nice thing about it is that you can create a shortcut that would do some unique stuff, e.g. showing the system clock.

          I’ve never used it in a shell script, and I assume that if a single command line for winapiexec is not enough, it might be worth to just write the code in e.g. C, or even in a scripting language such as Lua (which appears to support calling WinAPI functions).

  5. Jegimeco says:

    Please a command to enable/disable windows shadows in Windows 7 x64 on the fly. Thanks.

  6. Bizarre™ says:

    Does anyone know how to decommit private bytes for a specific process using this program?

  7. Aquilai says:

    Avast Anti-Virus blocked my download before it started stating winapiexec is a suspicious Win32:MDE-B [Susp] item. Could you contact Avast to have it allowed?

  8. Iron Slippers says:

    А можно этой чудо-программкой запустить команду “Minimize all”, ну и соответственно обратно?

    • “Minimize all”:
      winapiexec.exe u@SendMessageW ( u@FindWindowW Shell_TrayWnd 0 ) 0x111 419 0

      Обратно оно не работает. Для этого можно использовать “Show desktop”:
      winapiexec.exe u@SendMessageW ( u@FindWindowW Shell_TrayWnd 0 ) 0x111 407 0

      • IronSlippers says:

        Спасибо. До этого у меня вот такая веселая конструкция была:
        chp.exe —> cmdow.exe —> ярлык с командой
        =)

  9. Sleeping_Dragon says:

    Is there a command for this tool to do manual garbage collection? If so, can it also be done on a specific process?

  10. YouCrazyKids says:

    Hi there, I’m attempting to use winapiexec through a batch file to read the system idle time (using the User32.dll function GetLastInputInfo), but don’t understand how it would be expressed in the batch file. Is it even possible using winapiexec? My attempt was:

    winapiexec User32.dll@GetLastInputInfo(LastInputInfo)

    The GetLastInputInfo function description from Microsoft is really cryptic. Any help you can give would be appreciated. Thanks!

    • Hi,

      GetLastInputInfo is a bit complicated, as it expects a reference of a structure.

      Here’s an example of how it can be done:
      winapiexec.exe u@GetLastInputInfo $a:8,0 , InterlockedExchange $b:4 $$:2@1 , InterlockedExchange $$:5 0

      According to the documentation, this will return “The tick count when the last input event was received.”.

      The current tick count can be retrieved with the GetTickCount function:
      winapiexec.exe GetTickCount

      • Dragos says:

        Hi, I was just about to ask about this when I saw this post, I’ve tried the code but it did not work.

        I’m running Windows 8.1 (x86), does this work on your end?

        Thank you

          • Dragos says:

            Thank you Michael!

            I wasn’t calling it right, it works with your example but it seems to get something else rather that what I’ve expected.

            GetTickCount gets the time passed sinced the last restart/power on but what I need is GetLastInputInfo wich “retrieves the time of the last input event.”

            I’ve found something made with AutoIt, here:
            https://www.autoitscript.com/forum/topic/139331-idle-process-udf/
            and I guess I’ll stick with this for the moment.

            Thank you once again for your fast reply (it was late last night for me to respond) and best regards!

            PS: btw nice hack for ResHacker 🙂

            • what I need is GetLastInputInfo wich “retrieves the time of the last input event.”

              By subtracting the GetTickCount result from the GetLastInputInfo result, you can get the number of milliseconds the PC was idle. I don’t know what you’re into, so I can’t give a more specific advice.

              Seems like the code in the link you posted calls GetLastInputInfo repeatedly, until the value changes, which means that the user is not idle anymore.

  11. highend says:

    Hi,

    would it be possible to use SHGetKnownFolderPath from shell32.dll to return the real folder if we supply the GUID?

    E.g.: “{4BD8D571-6D19-48D3-BE97-422220080E43}”
    which is the GUID for “My Music”. Many of the new GUIDs (SkyDrive / OneDrive on Win 8.1) aren’t present in the User Shell Folder (registry path) so SHGetKnownFolderPath is the the only viable option 😉

    • Hi,

      Yeah, that’s possible:
      winapiexec.exe shell32.dll@SHGetKnownFolderPath $a:0x4BD8D571,0x48D36D19,0x224297BE,0x430E0820 0 0 $b:4 , u@MessageBoxW 0 $$:5@0 $$:0 0x40

      The GUID format is not straightforward, so I wrote a small conversion script:
      http://ideone.com/nkZhtb

      Click on fork, replace the GUID, and run it right in the browser 🙂

      <?php
      
      $guid = '{4BD8D571-6D19-48D3-BE97-422220080E43}';
      
      $p = '#{?([0-9A-F]{8})-'.
      	'([0-9A-F]{4})-'.
      	'([0-9A-F]{4})-'.
      	'([0-9A-F]{2})([0-9A-F]{2})-'.
      	'([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})}?#';
      preg_match($p, strtoupper($guid), $m);
      echo sprintf('0x%s,0x%s%s,0x%s%s%s%s,0x%s%s%s%s', 
      	$m[1], 
      	$m[3], $m[2], 
      	$m[7], $m[6], $m[5], $m[4], 
      	$m[11], $m[10], $m[9], $m[8]);
      
  12. highend says:

    Hi RaMMicHaeL,

    thanks for your reply and posting the necessary command line, much appreciated!

    Works perfectly fine (the .php code for putting the 0x… things together as well.

    Is there a way to return the output to stdout (e.g. when called from inside a dos box) instead of a real window?

    Regards,
    Highend

    • Here you go:

      winapiexec.exe shell32.dll@SHGetKnownFolderPath $a:0x4BD8D571,0x48D36D19,0x224297BE,0x430E0820 0 0 $b:4 , AttachConsole -1 , WriteConsoleW ( GetStdHandle -11 ) $$:5@0 ( lstrlenW $$:5@0 ) $b:4 0

      Note that by default the process starts in the background, so the output order could get mixed up. You can use START /WAIT to fix this:

      START /WAIT winapiexec.exe shell32.dll@SHGetKnownFolderPath $a:0x4BD8D571,0x48D36D19,0x224297BE,0x430E0820 0 0 $b:4 , AttachConsole -1 , WriteConsoleW ( GetStdHandle -11 ) $$:5@0 ( lstrlenW $$:5@0 ) $b:4 0

  13. highend says:

    Just incredible…

    Thanks again!

    Regards,
    Highend

  14. David.M says:

    Hi

    I having trouble understanding how WinApiExec replicates C structures. I know it can create arrays but how do you control how many bytes each array member takes up? Some API structures have a mix of different width members. Also can you explain the array referencing syntax a little more. What does $$:5@0 reference? Is the 0 array one which is passed to the executable?

    Regards

    David.M

    • Hi David,

      See the example with CreateProcess (“Run calculator for a second, then terminate it”).
      $a is an array of doublewords, and because most structures are padded, this should fit nicely. If it’s not padded, you’ll have to hack around, similarly to what I did above with GUIDs:
      http://rammichael.com/winapiexec/comment-page-1#comment-4417

      What does $$:5@0 reference?

      $$:5 is the fifth argument. $$:5@0 is equivalent to this in C:
      ((DWORD *)argv[5])[0];

      In the example above (with the GUIDs), the fifth argument holds a pointer to a string, so argv[5] is a pointer to a pointer.

  15. David.M says:

    Hi

    Thanks for the info, I understand the syntax now. Is there a why to return the output to the global atom table? I use a scripting language that could get the data from athe atom table rather than the console.

    Regards

    David.M

  16. David Paul says:

    Hi,
    I need to refresh after changing registry keys
    “HKCU \ Software \ Microsoft \ Windows \ CurrentVersion \ Internet Settings \ ProxyEnable” to 0/1 DWORD.

    It is about turning off the proxy in the registry. But after that change the system knows that proxy was changed and only works when the ticks manually in the GUI.

    Thanks for your time

    David Paul

    • Andy says:

      I needed to do the same thing and managed to accomplish this task in AutoIt with the following code, you should be able to port it from this code to what ever you prefer

      DllCall(‘WININET.DLL’, ‘long’, ‘InternetSetOption’, ‘int’, 0, ‘long’, 39, ‘str’, 0, ‘long’, 0)

  17. sheldon says:

    Hi
    I try to change taskbar icons size on the fly without terminating explorer process
    So long I came up with this script (Windows 7):

    @echo off
    (reg add “hkcu\software\microsoft\windows\currentversion\explorer\advanced” /v TaskbarSmallIcons /t REG_DWORD /d 0 /f)>NUL
    winapiexec.exe u@SendMessageW ( u@FindWindowW Shell_TrayWnd 0 ) 0x111 413 0
    ping 192.0.2.2 -n 1 -w 1 > nul
    nircmd.exe dlg “” “” click OK

    Could you please take a look at this? How to make this shorter or at least replace nircmd with winapiexec

    Regards
    sheldon

  18. peter says:

    I would like to send a message to the taskbar window that will restore all firefox windows, then another message that will minimize them. Minimizing is less important than restoring, since there are other ways to do that. I can’t figure out how to use winapiexec to send the correct message.

    Here is why I want to do this. I use the auto-hide feature of taskbar, and in addition place it at the left of my screen to maximize readability of a large number of open windows.

    Windows has the “helpful” feature that taskbar will not autohide as long as some window is demanding focus. Unfortunately, it is often impossible to determine what window that is. In the case of firefox, this happens every time, because some windows put up a modal dialog for passwords, or other warning. Usually, the FF taskbar icons are not grouped, so getting taskbar to autohide requires multiple operations. Thus, I want to create a desktop shortcut to do it. Nircmd almost is enough, but for example I do not know FF window class.

  19. peter says:

    Thanks.

    Knowing the window class might be enough to use Nircmd to do what I want.

    BTW, as a former c++ programmer, you’d think I could just write a few lines of code, but re-learning all the details of how to use the Windows API is not a torture I want to endure a second time. (And, these days I would have to compile in visual studio, not g++ under linux, yet another form of torture.)

    • peter says:

      Oh, actually I guess it is “gcc”.

      Thanks.

      Knowing the window class might be enough to use Nircmd to do what I want.

      BTW, as a former c++ programmer, you’d think I could just write a few lines of code, but re-learning all the details of how to use the Windows API is not a torture I want to endure a second time.(And, these days I would have to compile in visual studio, not g++ under linux, yet another form of torture.)

  20. peter says:

    For the benefit of those who might stumble upon my question in the future, it turned out that I did not need to know the window class after all; it was sufficient to know the process name for Nircmd.

    The following nircmd invocation accomplishes what I wanted:

    nircmd.exe win activate process “firefox.exe”

    That restores all firefox windows. BTW, using the class instead will also restore windows built on firefox, such as icedragon, which is essentially a branded firefox. However, the command line above does not allow selecting which profile’s process’s windows get restored. (I.e., does not differentiate among groups.)

  21. DV says:

    Fantastic small tool! Exactly what I was looking for (or was thinking about writing something similar myself).
    The only thing I’d be happy to see in addition would be a 64-bit version of the very same tool to be able to deal with 64-bit dlls.

  22. DV says:

    Just curious: what is the programming language of winapiexec?

    And let me show an example of using winapiexec to put some unicode text into the clipboard. ( Inspired by http://stackoverflow.com/questions/1264137/how-to-copy-string-to-clipboard-in-c )

    Example 1: places the text “Sample text” into the clipboard:
    winapiexec kernel32@GlobalAlloc 0x0042 8192 , kernel32@GlobalLock $$:1 , kernel32@lstrcpyW $$:5 “Sample text” , kernel32@GlobalUnlock $$:1 , user32@OpenClipboard 0 , user32@SetClipboardData 13 $$:1 , user32@CloseClipboard

    Example 2: something more useful – placing path to current directory into the clipboard:
    winapiexec kernel32@GetCurrentDirectoryW 512 $b:1024 , kernel32@GlobalAlloc 0x0042 8192 , kernel32@GlobalLock $$:5 , kernel32@lstrcpyW $$:9 $$:3 , kernel32@GlobalUnlock $$:5 , user32@OpenClipboard 0 , user32@SetClipboardData 13 $$:5 , user32@CloseClipboard

    • Just curious: what is the programming language of winapiexec?

      C, with one function in inline assembly.

      And let me show an example of using winapiexec

      Cool. I really like that such a small tool of 4 KB can do so much.

      A couple of notes:

      • kernel32 can be replaced with k, or omitted at all. user32 can be replaced with u.
        e.g. kernel32@GlobalAlloc -> GlobalAlloc. user32@OpenClipboard -> u@OpenClipboard.
      • Calls can be nested. e.g.:
        kernel32@GlobalAlloc 0x0042 8192 , kernel32@GlobalLock $$:1 -> kernel32@GlobalLock ( kernel32@GlobalAlloc 0x0042 8192 )

      All in all, the first example can look like this:
      winapiexec.exe lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) "Sample text" , GlobalUnlock $$:5 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:5 , u@CloseClipboard

      • DV says:

        OK, C is good! Optimistically it means: to produce a 64-bit binary, just a different target machine needs to be specified during the compilation of the very same source file! (Though, pessimistically it means that additionally amd64-related paths to headers, libraries and so on must exist and must be specified for the compilation; plus some compiler-specific flags and/or environment variables.)
        Anyway, looking at disassembled code, I’ve noticed usage of LoadLibraryW, but not of FreeLibrary. I mean, to be 100% safe, it would be better to call FreeLibrary after the library is no more needed. (Surely, FreeLibrary needs to be called only for libraries loaded via LoadLibraryW – and not for libraries acquired via GetModuleHandle.)

        • To produce a 64-bit binary, I’ll have to rewrite that one assembly function to 64-bit. And because Visual Studio doesn’t support 64-bit inline assembly, I’ll have to find another way to integrate it with the C code.

          As of FreeLibrary: because winapiexec is usually a short-lived process, I don’t free memory and don’t unload the libraries. For libraries, MSDN states the following:

          The system unloads a module when its reference count reaches zero or when the process terminates (regardless of the reference count).

          Therefore, it looks to me that everything is 100% safe as is.

          • DV says:

            You are right.
            As for the assembly, looks like the 64-bit asm code needs to be located inside a separate .asm file. (I was looking at the sources of http://akelpad.sourceforge.net/files/plugs/Scripts.zip as an example. There are source files ISystemFunction.c, ISystemFunction.h and ISystemFunction64.asm inside the archive. And the Build-x64.cmd includes such line: “ML64 /c ISystemFunction64.asm”)

  23. winapiexec v1.1 was just released.

    Release notes:
    * A 64-bit version.
    * An additional syntax for arrays. Allows to have nested arrays.
    Example: $a[a,b,$a[c,d],e].
    * A little bit safer: if arguments are missing (16 at most), zero values are being used instead of random values on the stack. For example:
    winapiexec.exe u@wsprintfW $b:2050 %p,%p,%p,%p , u@MessageBoxW 0 $$:2 $u: 0

    As for the 64-bit version, note that not every command which works for the 32-bit version works for the 64-bit version without changes.
    For example, this command:
    winapiexec.exe shell32.dll@SHGetKnownFolderPath $a:0x4BD8D571,0x48D36D19,0x224297BE,0x430E0820 0 0 $b:4 , u@MessageBoxW 0 $$:5@0 $$:0 0x40
    Has to be adjusted like this:
    winapiexec64.exe shell32.dll@SHGetKnownFolderPath $a:0x48D36D194BD8D571,0x430E0820224297BE 0 0 $b:8 , u@MessageBoxW 0 $$:5@0 $$:0 0x40

  24. EliadTech says:

    Hi RaMMicHaeL.

    First, this seems like a really great tool.

    I can’t figure out how to pass a boolean value to the API function (specifically User32@BlockInput).

    I’ve tried 1/0 and True/False, and both seem to fail. (Though there’s no output, so I’m flying blind here…)

    Any suggestions?

    • BOOL is defined as int, so 1/0 should do.
      But note that according to MSDN:

      The thread that blocked input unexpectedly exits without calling BlockInput with fBlock set to FALSE. In this case, the system cleans up properly and re-enables input.

  25. EliadTech says:

    Here’s my script:
    cls
    winapiexec64.exe user32.dll@BlockInput 1
    Timeout /T 5
    winapiexec64.exe user32.dll@BlockInput 0

    During the timeout it sohould be blocked, right? But it ain’t working…

    • Two things:
      * After your first use of winapiexec64.exe, the process terminates. Therefore, the blocking resets (read my reply above).
      * Seems like you can successfully call BlockInput only as administrator.

      This command seems to work if launched as administrator:
      winapiexec64.exe u@BlockInput 1 , Sleep 5000 , u@BlockInput 0

  26. EliadTech says:

    Right, I had the CMD process in mind…
    I’ve a Posh script that use the same function, and I could’ve sworn that it worked without admin rights…

    Thanks for the tool and the support.

  27. DTM says:

    Just so that you are aware :: Your other stuff is great!

    WinAPI Exec fails on my machine.

    ERROR : winapiexec.exe is not a valid Win32 application.

    Is it just my machine? WinXP SP3

    Compile time switches? /IncludeDeadOSFuncs =)

    Thanks!!!

  28. DTM says:

    The file from dropbox:
    winapiexec.exe 2015.08.15 11:51PM

    SHA : 46e4d50b8812457ae27ca1aad178d59e6f7efcd4

    Caused:
    VS.JIT Debugger Popup
    An unhandled win32 exception occurred in winapiexec.exe [3704]

    =\

    For what it’s worth…
    My WinXP SP3 has almost ALL of WBEM ripped out, if that matters.
    It HAS .NET minimum install to run all major software.
    .NET Optimizer and many other nonessential services are disabled.

    This tiny WinAPI executor that you’ve built seems like it would
    be very useful for tiny tasks that Windows can perform much
    easier than .BAT

    Although the current build fails your timely response is VERY
    appreciated. Don’t misunderstand nor underestimate!

  29. DTM says:

    Nothing about WinAPIexec in the event logs.

    I’m beginning to suspect it has to do calls into MUI and/or NLS since I’ve ripped those out of this WinXP also.

    Likely the issue is beyond your control. I use English only.

    On another thought:
    It’s my understanding that RESHACKER does not recompile
    unicode strings within edited EXE & DLL properly. I could be wrong.

    My SHELL32.DLL is heavily edited, thus, any calls into SHELL32.DLL
    unicode strings may cause WinAPIexec.exe to fail?

    Conclusion:

    Your efforts on behalf of my OS are greatly appreciated.
    I fully expect WinAPIexec runs flawlessly on a stock installation
    (or mildly customized WinXP SP3++).

    • I can’t see a reason for winapiexec not to work if e.g. reshacker, which is much more complex, works.

      If you’d like to investigate further, download and run OllyDbg, open winapiexec with it, run it, and make a screenshot of what you see. If you’re not willing to be bothered, then never mind 🙂

  30. DTM says:

    I neglected to mention:
    WinAPIexec.exe
    SHA : 46e4d50b8812457ae27ca1aad178d59e6f7efcd4

    DOES execute the simple statements as your example above:
    :: winapiexec.exe u@ShowWindow ( u@FindWindowW Shell_TrayWnd 0 ) 0 , Sleep 500 , u@ShowWindow $$:3 5

    It hides the SysTray. It breaks somewhere thereafter.

    Compound statements in your examples always break.

    Nothing in event logs.

    In any event, the ZIP that you posted is only missing the README.
    I might suggest adding your site & contact info into the README.

  31. DTM says:

    Using OllyDBG 1.10
    SHA : b08e0b5f1a3633bd6d0a6a71b54c13477cd3c991

    WinAPIexec.exe
    SHA : 46e4d50b8812457ae27ca1aad178d59e6f7efcd4

    CMD Line args:
    GetTempPathW 260 $b:520 , u@MessageBoxW 0 $$:3 $$:0 0x40

    Breaks with:

    UNICODE “Stack error on argument number %d”

    Any unicode breakage would be no surprise to me
    (As I’ve noted aboove). I could be wrong again.
    I haven’t DBG for at least 20 years
    (LONG before Win32 existed).

  32. DTM says:

    That fixed the WinXP issue.

    WinAPIexec.exe
    SHA : c1cd5777883451b702bd71fe93d2de28c6918f27

    Runs all the examples above flawlessly.

    NOW, it’s time to kick ass and chew bubblegum.

    And I’m all outta gum… =)

    Thanks for behaving like a human in this world overrun by aliens (and their iPhones). It’s very refreshing. My wife says Thanks & Hi!

  33. Matt says:

    Im new to programming and using api’s, I have found a function in shell32.dll using dll export viewer called SHChangeNotify however when i try to reference it using winapiexec64.exe shell32.dll@SHChangeNotify, H8000000, H0, 0, 0 it states that it could not find procedure SHChangeNotify in module shell32.dll

    Thanks

    Matt

    • winapiexec tries to find an export with the name “SHChangeNotify,” (note the comma). You need to use spaces – see the examples above.
      Also, H8000000 is parsed as a string. See documentation. For hexadecimal numbers, you can use 0x8000000.

  34. Mexxxi says:

    I’m trying to detach a VHD with winapiexec, but no luck so far:

    winapiexec64.exe virtdisk.dll@DetachVirtualDisk (k@CreateFileW “\.\PhysicalDrive3” GENERIC_READ NULL OPEN_EXISTING FILE_ATTRIBUTE_NORMAL NULL) DETACH_VIRTUAL_DISK_FLAG_NONE 0

    What am I doing wrong?

    Thanks

    Mex

    • I’m not familiar with the API, but syntax-wise, you need to put a space between the parentheses and the other arguments. Also, winapiexec doesn’t recognize constants such as FILE_ATTRIBUTE_NORMAL or even NULL (what did you expect from a 4 KB tool?). They are being interpreted as strings. Use numbers instead, such as 0 instead of NULL.

      • Mexxxi says:

        Thank you for your quick reply and your heads up. That got me off the ground 🙂

        I almost have it working, just a small problem: I’m trying to chain two API-calls. The first one is needed to get a handle which I need for the second API. I created a buffer with $b:4 in API1 and referenced it with $$: in API, yet it seems that not the value of the handle is being passed, but the pointer address instead. Is there any way to pass the handle? The syntax looks like this:

        function1 (param1, param2, param3, _out_handle)
        function2 (_in_handle)

        winapiexec.exe library.dll@function1 param1 param2 param3 $b:4 , library.dll@function2 §§:5

        Btw, I love the ultra-tiny size of this tool. In this day and age where even mere file headers can exceed winapiexec’s size, I’m stunned to see such a small, yet functional tool in action 🙂

  35. NikolaS says:

    Hi, can winapiexec be used to disable registry redirection and reflection for a registry key on 64 bit Windows so that 32 bit command line tool (like subinacl or any other) can access redirected keys? Could you show me some example for that?

  36. h-h says:

    Hi,

    thanks for this great tool!

    What do you think about something like this: !$a:1,2,3

    “!” means dereferencing. The idea is to pass data structures by value.

    • Hi,

      I don’t see much use for it, especially since data structures are not directly supported by winapiexec, only word-sized arrays.
      For the rare cases where WinAPI functions receive data structures by value (e.g. PtInRect), the structure is usually small, and the call is equivalent to passing every field of the structure as a parameter.
      With the case of PtInRect, one can use the following signature:
      BOOL PtInRect(const RECT *lprc, LONG pt_x, LONG pt_y);

      • h-h says:

        the call is equivalent to passing every field of the structure as a parameter.

        Yeah, you’re right. So then that’s the way it should be used.

  37. h-h says:

    Am I right that stdcall is the only calling convention winapiexec supports? If yes, do you plan on supporting cdecl and possibly other calling conventions too?

    • Both stdcall and cdecl are supported. You can notice that one of the call examples use wsprintfW, which is cdecl. Both work as the stack is being restored manually.
      Other calling conventions, such as fastcall, are not supported. I don’t plan to add support for other calling conventions, as winapiexec is mostly targeted at WinAPIs, and I don’t think that anything other than stdcall and cdecl is used.

  38. h-h says:

    Are you able to access the standard input stream? Otherwise: Would you please enable this? This way, you could pipe the output of a command to winapiexec which then displays it in a message box. I think you should be able to access the data as ANSI and Unicode.

    • It’s certainly possible to access the output stream, as demonstrated here.
      I believe that something similar can be done with the input stream, but I’m not familiar enough with the console API to implement what you’re asking for.

      Here’s my 5-minutes attempt, and it kind of captures the input, but doesn’t work with piping:
      winapiexec.exe AttachConsole -1 , ReadConsoleW ( GetStdHandle -10 ) $b:2048 1024 $b:4 0 , u@MessageBoxW 0 $$:9 test 0

      Run the command, then input some strings. That’s what you’ll see:
      http://i.imgur.com/5fUMvuh.png

      I’m not sure why test1 isn’t being captured, and test2 is. Go play with it, and let me know if you find a solution 🙂

    • Steven says:

      I know the post I am replying to is 7 years old, it is more for those looking for an alternative as I also consider the comment section as documentation

      This is how I would do it in git-bash ( or MSYS2 for that matter)

      Define Message.box function

      MessageBox.Show()
      {
      local lStdin=/dev/stdin
      local lTitle=”${1:-“Title”}”

      path/to/winapiexec.exe u@MessageBoxW 0 “$( cat “$lStdin” )” “$lTitle” 0
      }

      Example use

      cat /s/commands.txt | MessageBox.Show “File Content”

  39. Marco says:

    Hi RaMMicHaeL,
    first of all thanks for writing such an awesome tool, its incredible what can be achieved with it!

    However I have not been able to do what Im trying to and was hoping you could point me in the right direction.

    Ive been trying to use “winapiexec.exe comdlg32.dll@GetOpenFileNameA” to pop up a file selection dialog and somehow get the return value as something that can be access by the batch process itself, but I am at a loss. First trying to fire up the dialog window, because It seems to take a structure that I have been unable to provide, and second I don’t know how I would save the returned value in a way that the the rest of the batch script can read.

    Thanks for your help.

  40. Marco says:

    In case someone is trying to do something similar, here is the call I made (that does NOT work) :
    winapiexec.exe comdlg32.dll@GetOpenFileNameA 52 0 0 0 0 0 0 $b:260 260 0 $b:260 260 0 ratAttack 0x1000 0 $b:260 0 $b:260 htm 0 0 0

    • Thy this command:
      winapiexec.exe comdlg32.dll@GetOpenFileNameA $a:76,0,0,0,0,0,0,$b:260,260,0,0,0,$s:ratAttack,0x1000,0,$s:htm,0,0,0 , u@MessageBoxA 0 $$:2@7 $s:ratAttack 0

      • Marco says:

        Ahh, I see where I got it wrong :

        Besides not counting the correct size of the structure correctly, somehow I made some obvious parameter order mistakes.

        I attribute this to exhaustion!

        There is one think however I cannot seem to understand :
        According to the MSDN API reference docs, the OPENFILENAME structure has the default extension lpstrDefExt element on the 16 position, however this does not work.

        Your command above works because it puts the default extension on the 17 position (nFileExtension : a zero-based offset word according t0 MDSN).

        How is it that putting the default extension on the 17 position works?
        By the way, it has to be $s:htm

        Thanks.

        • Besides not counting the correct size of the structure correctly, somehow I made some obvious parameter order mistakes.

          Well, you’ve passed the structure variables as parameters, instead of passing a single parameter, which should be the pointer to the structure.

          How is it that putting the default extension on the 17 position works?

          nFileOffset and nFileExtension are WORDs, so they both use one doubleword argument.

          By the way, it has to be $s:htm

          Right, fixed it in my comment.

          • Marco says:

            This is awesome!

            I am now able to choose the file, however Im still struggling about how to send this output to a batch file.

            I thought about saving it to an env var, but I cant get the simple call to k@SetEnvironmentVariableA to work!

            This is what I tried so far :
            winapiexec.exe comdlg32.dll@GetOpenFileNameA $a:76,0,0,0,0,0,0,$b:260,260,0,0,0,$s:ratAttack,0x1000,0,$s:htm,0,0,0 , k@SetEnvironmentVariableA $s:filename $$:2@7

  41. dev. says:

    Hi RaMMicHaeL,

    first let me say, this tool is really awesome.
    Great work dude, thank you so much.

    Iam playing around with some Windows File Management Functions, but iam not able to copy the filename/extension etc. from the path to the clipboard.
    Can you please rebuild the following lines to put the return value into the clipboard and not to a messagebox.

    winapiexec shlwapi@PathFindExtensionW $u:”C:\Users...\winapiexec\Textfile.txt” , u@MessageBoxW 0 $$:1 $$:0 0x40
    winapiexec shlwapi@PathFindFileNameW $u:”C:\Users...\winapiexec\Textfile.txt” , u@MessageBoxW 0 $$:1 $$:0 0x40

    • Hi,

      You have an example of copying text to the clipboard in the post above.

      Here’s your first example, rewritten:

      winapiexec shlwapi@PathFindExtensionW $u:"C:\Users...\winapiexec\Textfile.txt" , lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) $$:1 , GlobalUnlock $$:8 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:8 , u@CloseClipboard

      • dev. says:

        This is so useful. I have been searching so long for a portable tool that copies such simple things to clipboard.
        I would welcome a detailed description, like instruction about winapiexec, because i didnt really understand the syntax.
        However.. Thank you again for your help and for this great tool, love it.

        • like instruction about winapiexec

          You have it in the post on the top of the page. If you have any specific questions, I can try to help you sort them out.

          • dev. says:

            Sure, read it multiple times, but its not very easy to understand.
            Can you please help me in the following case. I cant get the WNetGetUniversalName function run.
            Due MSDN:

            WNetGetUniversalName(LPCTSTR lpLocalPath, DWORD dwInfoLevel, LPVOID lpBuffer, LPDWORD lpBufferSize)

            WNetGetUniversalName should return the the unc path of S:\files\textfile.txt which resides physically on \server1\myshare and mapped as s:\ on my workstation.
            So the return value should be \server1\myshare\files\textfile.txt, but somehow it returns the local path s:\files\textfile.txt.

            lpLocalPath ….. S:\files\textfile.txt
            dwInfoLevel ….. UNIVERSAL_NAME_INFO_LEVEL = 1
            lpBuffer …….. struct _UNIVERSAL_NAME_INFO { LPTSTR lpUniversalName; } UNIVERSAL_NAME_INFO;
            lpBufferSize …. 512

            Following your instructions (if i understand correctly) the command should be:
            winapiexec mpr@WNetGetUniversalNameW $u:”S:\files\textfile.txt” 1 $a:$b:1024 512 , lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) $$:2@1 , GlobalUnlock $$:11 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:11 , u@CloseClipboard

            Am I wrong?

            • The call looks correct, and the fact that it returns some string (and not crashes) probably means that it is correct. I’m not familiar with the WNetGetUniversalNameW function, perhaps you should pass different flags or something.

              Have you tried to write a sample program in e.g. C, to verify that the API does what you expect it to do?

  42. dev. says:

    Well, I just compiled the example C++ code from MSDN, result is as expected: \server1\myshare\files\textfile.txt

    Output:
    Calling WNetGetUniversalName with Local Path = S:\files\textfile.txt
    WNetGetUniversalName returned success for InfoLevel=UNIVERSAL_NAME_INFO_LEVEL
    Universal name = \server1\myshare\files\textfile.txt

    This winapiexec call returns: S:\files\textfile.txt
    winapiexec mpr@WNetGetUniversalNameW $u:”S:\files\textfile.txt” 1 $a:$b:1024 512 , lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) $$:2 , GlobalUnlock $$:11 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:11 , u@CloseClipboard

    This returns nothing:
    winapiexec mpr@WNetGetUniversalNameW $u:”S:\files\textfile.txt” 1 $a:$b:1024 512 , lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) $$:2@1 , GlobalUnlock $$:11 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:11 , u@CloseClipboard

    Can you please take a look. It seems like something is wrong with my access to the struct buffer.

    • I’m not sure that I can test it, as I don’t have a network drive or something like that. But now I see that you’re fetching the second argument, not the forth one. Also, you’re using index 1 instead of 0.
      Try:

      winapiexec mpr@WNetGetUniversalNameW $u:"S:\files\textfile.txt" 1 $a:$b:1024 512 , lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) $$:4@0 , GlobalUnlock $$:11 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:11 , u@CloseClipboard

  43. MaaartenG says:

    I love this little tool! Thank you Michael!

    I managed to do a refresh of Explorer in pure winapiexec after changing Explorer view settings, like Show hidden files (as mentioned in http://rammichael.com/winapiexec#comment-4805 )
    Well, sort of….

    The basic is: read these settings (through @SHGetSetSettings) and write these same settings back right afterwards (also with SHGetSetSettings). This will force a refresh of explorer (desktop and file-manager):

    winapiexec64.exe shell32.dll@SHGetSetSettings (shell32.dll@SHGetSetSettings ww 0x00000002 0) 0x00000002 1

    Problem is, this command will only run once. The next time you run it, nothing (visible) happens.
    Cause of this is probably the “ww” in the command above. That is my random placeholder for what should be something SHGetSetSettings really understands and can handle.
    But as I’m no programmer (at all!!), this is the best I could do.
    Maybe it inspires some real programmer to make this work as it should …

    BTW: Microsoft documentation says SHGetSetSettings is supported up until WinXP, but does fine on Win10 x64

  44. MaaartenG says:

    Turns out I can do a little better 🙂 But still: not enough ..

    The explorer settings are in a SHELLSTATE structure, which is -as I see it – effectively a set of 32 bits, each representing it’s own setting.
    So $b:32 should do instead of “ww”, I guess

    In the first version I let it read/write only 1 setting; now I jus do them all

    winapiexec64.exe shell32.dll@SHGetSetSettings (shell32.dll@SHGetSetSettings $b:32 0xFFFFFFFF 0) 0xFFFFFFFF 1

  45. MaaartenG says:

    Got it!
    $b:32 should be $b:4 of course (bits vs bytes)

    This code is working perfectly here to refresh the desktop:

    start /wait winapiexec64.exe shell32.dll@SHGetSetSettings (shell32.dll@SHGetSetSettings $b:4 0xFFFFFFFF 0) 0xFFFFFFFF 1

    (P.S. Sorry for the mess(-ages). I could not edit my own messages somehow.

    • I’m not familiar with the SHGetSetSettings function, but your command is clearly wrong, and if it works, it does by pure accident.
      You don’t use spaces near the parentheses, so the command is interpreted like this:

      call shell32.dll@SHGetSetSettings with 6 arguments:
      Argument 1 (string): (shell32.dll@SHGetSetSettings
      Argument 2 (buffer): $b:4
      Argument 3 (number): 0xFFFFFFFF
      Argument 4 (string): 0)
      Argument 5 (number): 0xFFFFFFFF
      Argument 6 (number): 1

      Now, SHGetSetSettings expects 3 arguments, so the rest are ignored. Argument 3 is not zero, so you’re setting new shell settings. And it seems like those end up being garbage values.

  46. Stamimail says:

    Can we make winapiexec to work with 2 commands?
    like, there are 2 different commands to:
    HideTaskkbar
    and
    UnHideTaskkbar

    The user wants to make and use one shortcut key to Hide/Unhide Taskkbar.

  47. Stamimail says:

    The same problem as above for:
    Hide/UnHide Explorer Navigation Pane.

    Can we make it with winapiexec? How?

  48. BeGreenMedia says:

    I want to copy some numbers into the clipboard:
    winapiexec64.exe lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) “123456789011121311” , GlobalUnlock $$:5 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:5 , u@CloseClipboard

    not working

    • The number is parsed as a number, and not as a string. The quotes don’t really have an effect here, except for allowing to have spaces, etc. Try the following:

      winapiexec64.exe lstrcpyW ( GlobalLock ( GlobalAlloc 0x0042 8192 ) ) $u:123456789011121311 , GlobalUnlock $$:5 , u@OpenClipboard 0 , u@SetClipboardData 13 $$:5 , u@CloseClipboard

  49. Adam says:

    It seems it can not display a number returned from another function call, like that:
    winapiexec.exe SetThreadExecutionState 0x80000040 , u@MessageBoxW 0 $$:1 $$:0 0x40

    Because the return value is considered as a str pointer rather than a number. Does anyone know how to convert the number to a string?

    • Adam says:

      I get it by myself, the following will get the number converted to a string:
      winapiexec.exe u@wsprintfW $b:17 %lx ( SetThreadExecutionState 0x80000040 ) , u@MessageBoxW 0 $$:2 $$:0 0x40

      This is a great tool to call dll api.

Leave a Reply to EliadTech