{"id":576,"date":"2009-04-17T09:43:44","date_gmt":"2009-04-17T09:43:44","guid":{"rendered":"http:\/\/www.mjtnet.com\/blog\/?p=576"},"modified":"2009-04-17T09:50:56","modified_gmt":"2009-04-17T09:50:56","slug":"working-with-windows-api-functions","status":"publish","type":"post","link":"https:\/\/www.mjtnet.com\/blog\/2009\/04\/17\/working-with-windows-api-functions\/","title":{"rendered":"Working with Windows API Functions"},"content":{"rendered":"<p><a href=\"http:\/\/www.mjtnet.com\/macro_scheduler.htm\">Macro Scheduler<\/a>&#8216;s LibFunc command allows you to run functions contained inside DLLs. \u00a0A DLL, or\u00a0Dynamic Link Library, is a file which contains functions that other programs can use. \u00a0Windows\u00a0includes a number of DLLs containing lots of functions that make Windows tick, and other applications\u00a0are able to call them. \u00a0These functions are known as the Windows API (Application Programming Interface). Using LibFunc a Macro\u00a0Scheduler script can access some of these functions too.<\/p>\n<p>The Windows API Reference can be found here:<br \/>\n<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa383749(VS.85).aspx\"> http:\/\/msdn.microsoft.com\/en-us\/library\/aa383749(VS.85).aspx<\/a><\/p>\n<p>This provides a list of functions which you can browse alphabetically or by category.<\/p>\n<p><strong>Data Types<\/strong><\/p>\n<p>Before I go on I should mention data types. \u00a0Not every Windows API function can be used by Macro\u00a0Scheduler. \u00a0This is because Macro Scheduler does not know about every possible Windows data type. \u00a0Macro Scheduler currently only knows about integers, long integers and strings. Almost any function that\u00a0requires or returns integer and\/or character based data can be called. \u00a0But anything that requires,\u00a0for example, a record structure or a callback function can not be used.<\/p>\n<p>The API documentation lists the Windows data types here:<br \/>\n<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa383751(VS.85).aspx\"> http:\/\/msdn.microsoft.com\/en-us\/library\/aa383751(VS.85).aspx<\/a><\/p>\n<p>Many of these are based on the same fundamental data types. \u00a0E.g. all the HANDLE types are just\u00a0unsigned numbers, so are supported by Macro Scheduler&#8217;s long integer. \u00a0LPTSTR and LPCTSTR are\u00a0interchangeable with strings.  From this list only CALLBACK and FLOAT are NOT compatible.<\/p>\n<p>So, as long as the function requires or returns only bools, integers or strings, we should be able to\u00a0use the function in Macro Scheduler. \u00a0Note that BOOLs are really just integers. \u00a0A BOOL is an integer\u00a0with value 1 (true) or 0 (false).<\/p>\n<p><strong>An Example: CopyFile<\/strong><\/p>\n<p>Let&#8217;s look at a Windows API function and how we can use it in Macro Scheduler.<\/p>\n<p>Take a look at the <strong>CopyFile<\/strong> function:<br \/>\n<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa363851(VS.85).aspx\"> http:\/\/msdn.microsoft.com\/en-us\/library\/aa363851(VS.85).aspx<\/a><\/p>\n<p>At the top of the page we are told what this function does:<\/p>\n<p><em>&#8220;Copies an existing file to a new file.&#8221;<\/em><\/p>\n<p>We are then given the syntax. \u00a0You&#8217;ll notice that it is provided using C++ syntax. \u00a0It certainly\u00a0helps if you know C++ but it is not essential and hopefully this example will help you understand\u00a0what the syntax definition is telling us:<\/p>\n<pre>BOOL WINAPI CopyFile(\r\n\u00a0\u00a0__in \u00a0LPCTSTR lpExistingFileName,\r\n\u00a0\u00a0__in \u00a0LPCTSTR lpNewFileName,\r\n \u00a0__in \u00a0BOOL bFailIfExists\r\n);<\/pre>\n<p>The first thing this tells us is that CopyFile returns a BOOL (0 or 1). \u00a0Inside the parenthesis we\u00a0see that the function requires three parameters. \u00a0The first two are of type LPCTSTR. \u00a0For our\u00a0purposes this means it is a string. \u00a0The third parameter is a BOOL again.<\/p>\n<p>We are then told what each parameter is for, what the function returns and various remarks.<\/p>\n<p>While the names of the parameters are quite self explanatory the documentation gives us more detail. \u00a0So we can see that the first parameter lpExistingFileName represents the name of an existing file,\u00a0lpNewFileName is what we set to the name of the new file we want to copy to, and bFailIfExists can be\u00a0set to true (1) to make the function fail if the new file already exists or false (0) to overwrite.<\/p>\n<p>We are told that the function returns zero if the function fails, or non zero if it succeeds.<\/p>\n<p><strong>DLL and Function Name<\/strong><\/p>\n<p>At the end of the page is some information crucial to us in the Requirements section. \u00a0This tells us\u00a0which versions of the operating system support this function and what DLL it is contained in &#8211;\u00a0Kernel32.dll in this case. \u00a0Note also that it tells us the alias names of the function. \u00a0In this case\u00a0CopyFileA for the ANSI version and CopyFileW for the unicode version (Why &#8220;W&#8221; not &#8220;U&#8221; I hear you ask\u00a0&#8211; W stands for WideString, a special form of string which can contain double byte characters).<\/p>\n<p>So, putting it all together, we end up with the following LibFunc call:<\/p>\n<pre name=\"code\" class=\"macroscript\">LibFunc>kernel32.dll,CopyFileA,result,c:\\source.txt,c:\\my docs\\new.txt,0<\/pre>\n<p>From left to right LibFunc takes the DLL name, then the function name, a variable which should return\u00a0the result of the call and then the values to pass to the function.  One thing to be aware of is that DLL function names are case sensitive.  Make sure the function name is entered into the LibFunc command exactly as specified in the API documentation.<\/p>\n<p>Try the above line with a real filename to see it in action.<\/p>\n<p><strong>Passing by Reference<\/strong><\/p>\n<p>Some DLL functions modify the values being passed to them. \u00a0Parameters are passed by reference rather\u00a0than by value. \u00a0This means that what you&#8217;re really passing is a pointer to the memory address that\u00a0stores that value, rather than just the value itself. \u00a0So when the function changes that value we can\u00a0see the new value after the call.\u00a0<\/p>\n<p>The way LibFunc handles this is that it puts each parameter value into an array, using the name of\u00a0the return variable specified. \u00a0So if you specify the return value as &#8220;result&#8221; and the function takes\u00a03 parameters LibFunc would return result, result_1, result_2, and result_3 where result contains the\u00a0function result and result_1 to result_3 contain the values of the passed parameters which might have\u00a0changed if the function modifies them.<\/p>\n<p>Here&#8217;s an example of a Windows API function which returns data in a passed parameter:<\/p>\n<p><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms724373(VS.85).aspx\">http:\/\/msdn.microsoft.com\/en-us\/library\/ms724373(VS.85).aspx<\/a><\/p>\n<pre>UINT WINAPI GetSystemDirectory(\r\n\u00a0\u00a0__out \u00a0LPTSTR lpBuffer,\r\n\u00a0\u00a0__in \u00a0 UINT uSize\r\n);<\/pre>\n<p>Note that the first parameter has the word &#8220;out&#8221; in front of it. \u00a0This signifies that its value is\u00a0set by the function. \u00a0The function also returns an integer. \u00a0If we read the docs we see that the function\u00a0writes the system directory in lpBuffer and returns the number of characters written to lpBuffer.<\/p>\n<p>So I can use the following code to get the system directory:<\/p>\n<pre name=\"code\" class=\"macroscript\">LibFunc>Kernel32,GetSystemDirectoryA,dir,buffer,255\r\nMidStr>dir_1,1,dir,sys_dir\r\nMessageModal>System Directory: %sys_dir%<\/pre>\n<p>Note that I&#8217;ve set the return variable to &#8220;dir&#8221;. We can pass any old value in buffer, but I&#8217;ve used\u00a0&#8220;buffer&#8221; here to make it obvious what it does. \u00a0Remember that LibFunc creates an array named after the\u00a0result variable. \u00a0So we get &#8220;dir&#8221; containing the number of characters written to the buffer, dir_1\u00a0containing the buffer itself and dir_2 will just be 255 because that&#8217;s what we passed in but isn&#8217;t\u00a0changed by the function as it is an &#8220;__in&#8221; parameter.<\/p>\n<p>We set the maximum buffer size to 255. \u00a0So we need to extract only the characters returned, which is\u00a0the reason why the function tells you how many characters it output. \u00a0So I&#8217;ve used MidStr to extract\u00a0only those characters from the returned buffer.<\/p>\n<p><strong>Windows Constants<\/strong><\/p>\n<p>Many times we need to know the value of a Windows Constant. \u00a0The documentation for a function may\u00a0refer to the name of a constant you need to use with the function. \u00a0E.g.:<\/p>\n<p>ShowWindow<br \/>\n<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms633548(VS.85).aspx\">http:\/\/msdn.microsoft.com\/en-us\/library\/ms633548(VS.85).aspx<\/a><\/p>\n<pre>BOOL ShowWindow( \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0HWND hWnd,\r\n\u00a0\u00a0 \u00a0int nCmdShow\r\n)<\/pre>\n<p>The docs say that nCmdShow specifies how the window is to be shown and says it can be one of the\u00a0following values: SW_FORCEMINIMIZE, SW_HIDE, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE and so on. \u00a0These\u00a0are Windows Constants.<\/p>\n<p>In Windows development languages such as C++ and Delphi these constants are defined in the header\u00a0files. In Macro Scheduler they are not defined, so we need to define them ourselves:<\/p>\n<pre name=\"code\" class=\"macroscript\">Let>SW_RESTORE=9<\/pre>\n<p>But, I hear you ask, how do I know that SW_RESTORE&#8217;s value is 9? \u00a0Well, if you have a development\u00a0environment like Visual Studio or Delphi installed you can find out by searching the header files.\u00a0<\/p>\n<p>However, if you don&#8217;t have this facility there&#8217;s a very handy free tool from Microsoft snappily\u00a0titled &#8220;P\/Invoke Interop Assistant&#8221; which contains a database of Windows functions and constants you\u00a0can search. \u00a0You can download it from:<\/p>\n<p><a href=\"http:\/\/www.codeplex.com\/clrinterop\">http:\/\/www.codeplex.com\/clrinterop<\/a><\/p>\n<p>Under the &#8220;SigImp Search&#8221; tab enter the constant you are looking for and it will tell you its value.<\/p>\n<p>The Windows header files give the constant values in hexadecimal, so if obtaining them from the header files you will need to convert to decimal.  The Windows Calculator is handy for doing this.  &#8220;P\/Invoke Interop Assistant&#8221; also shows the values in hexadecimal, but if you click the &#8220;Generate&#8221; button it will create C# or VB code with the value declared as an integer.<\/p>\n<p><strong>STDCALL Calling Convention<\/strong><\/p>\n<p>Finally, a note about calling conventions. \u00a0When a DLL is created the programmer can decide in what\u00a0order parameters should be passed to the functions and who should clean up afterwards. \u00a0Windows API\u00a0functions use the &#8220;stdcall&#8221; calling convention in which arguments are passed from right to left and\u00a0the callee, i.e. the DLL, is responsible for cleaning the stack. \u00a0This therefore is the calling\u00a0convention supported by LibFunc. \u00a0You don&#8217;t need to worry about this when calling Windows API\u00a0functions. \u00a0But if you come to working with third party or custom DLLs, or ones you have created\u00a0yourself, you will need to make sure the DLL uses the stdcall convention.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Macro Scheduler&#8216;s LibFunc command allows you to run functions contained inside DLLs. \u00a0A DLL, or\u00a0Dynamic Link Library, is a file which contains functions that other programs can use. \u00a0Windows\u00a0includes a number of DLLs containing lots of functions that make Windows tick, and other applications\u00a0are able to call them. \u00a0These functions are known as the Windows [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[6],"tags":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/posts\/576"}],"collection":[{"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/comments?post=576"}],"version-history":[{"count":16,"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions"}],"predecessor-version":[{"id":592,"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions\/592"}],"wp:attachment":[{"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/media?parent=576"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/categories?post=576"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.mjtnet.com\/blog\/wp-json\/wp\/v2\/tags?post=576"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}