|  | 
		
			| Under the Hood : Running AheadBy Bruce Johnson
 |  |  | 
    
      |  |  |  | 
  
	This article was first published in
	
Clarion Online
	Volume 1, issue 1 and is reproduced here with permission
	
 In this column Ill be discussing the Windows 32 bit Application Programming
      Interface (Win32 API). Generally Clarion does a good job of hiding most
      of the API complexity from you but there are still functions in the API
      that are available, and useful, to the programmer who is prepared to dig
      a little deeper.
 
 As we progress with this journey though the API well build up a function
      library that you can use in your everyday applications. Well make
      full use of templates to make using these functions easier and more reusable
      from one application to another. Well also see some of the benefits
      of 32-bit programming.
 
 In this first column well explore the 32-bit function called CreateProcess,
      along with some related functions. Apart from creating a process well
      also be able to stall the current process until the child shuts down. In
      addition to this our function will return a handle which we can use to terminate
      the process as well. Well do this using the TerminateProcess function.
 
 The Clarion RUN function is a simpler version of CreateProcess. CreateProcess
      however has some additional functionality that can come in handy when used
      at the right time. Essentially CreateProcess, and Run, allow you to start
      a program from within another program. In CW2 this was all that RUN allowed
      you to do. In the new Clarion 4 (C4) one parameter has been added which
      allows you to wait until the program you call has finished running before
      continuing with the caller program. CreateProcess, can however do even more.
 
 Now the idea is to create a wrapper function, called ARUN, in our library
      to remove some of the complexity. What were aiming for is a function
      that allows us more power than the Run function, but still isnt as
      complex as the full CreateProcess function. For example in calling our wrapper
      well use strings instead of cstrings, well allow omittable parameters
      (with suitable defaults) and well remove parameters that dont
      interest us for now.
 
 Although CreateProcess can do a lot, most of it is beyond what we need.
      For example if youre writing a debugger then CreateProcess has flags
      that you would need. Its unlikely though that you would write a debugger
      in Clarion so we dont need to worry about things like that. Im
      not going to go into all the flags that can be set, but Im going to
      focus on the ones youd most likely use. Specifically ARUN will offer
      the following features:
 
      In addition to this, inside ARUN I will use the GetLastError and WaitForSingleObject
    functions (both Win32 API functions) to provide the following additional functionality;It can control the priority of the new process ( how much time it gets
        to run). This is useful for launching things like background processes.
        Remember Windows is a multitasking OS and part of that means moving background
        processing to where it belongs, into the background.It can specify the initial state of the window of the new process (maximized,
        minimized etc.) Sometimes you want a program to start, but not to come
        immediately to the front. For example you may want to incorporate the
        Windows calculator in your app. You can run the calculator, but run it
        in a minimized state. Then its available immediately to the user
        whenever they need it. It can give the process its own environment space (its own path for
        example). This is very useful for running legacy DOS applications. For
        example Clarion Professional Developer (an early version of Clarion for
        DOS) created programs that made use of Environment variables like CLAVM0.
        By launching programs with their own environment space you save having
        to do complicated install functions like changing the AutoExec.Bat.It can start the process in a different directory. This is useful if
        the program and data reside in different directories, as is often the
        case on a network.It can set the position and size of the first window of the new process.
        This means you have more control over how the program is going to look
        when it opens. 
      To round it off ARUN will return a process handle (if it is successful) that
    will contain a handle to the new process. We can use this handle, and the
    TerminateProcess function, to terminate the child process if we want to. TerminateProcess
    is a bit of a mouthful to remember so well create a wrapper function,
    called ENDRUN to end a program started with the RUN statement.GetLastError returns the most recent windows error. Thus if the ARUN
        fails this function will return the error value so that ARUN can return
        it to you. It is essential to get the maximum error information back from
        a function so that when it fails you can quickly identify the cause of
        the problem.WaitForSingleObject. This function allows the calling program to efficiently
        wait for the called program to terminate before execution resumes. This
        is particularly useful where you are running another program to complete
        a task, and when that task completes you want to resume processing the
        current application.  
 An obvious sidebar here: a logical step from here is to be able to terminate
    the current program from within itself. So you might be wondering how to get
    hold of the handle of the current program. However the solution here is to
    remember the HALT command provided by the Clarion language, which performs
    that functionality for us already.
 
 Here is the prototype of CreateProcess as it appears in the Win32 SDK. (This
    is using a C compatible prototype statement).
 
 BOOL CreateProcess(
 LPCTSTR lpApplicationName,                
    // pointer to name of executable module
 LPTSTR lpCommandLine,                     
    // pointer to command line string
 LPSECURITY_ATTRIBUTES lpProcessAttributes, // pointer to process security
    attributes
 LPSECURITY_ATTRIBUTES lpThreadAttributes,  // pointer to thread
    security attributes
 BOOL bInheritHandles,                     
    // handle inheritance flag
 DWORD dwCreationFlags,                    
    // creation flags
 LPVOID lpEnvironment,                     
    // pointer to new environment block
 LPCTSTR lpCurrentDirectory,               
    // pointer to current directory name
 LPSTARTUPINFO lpStartupInfo,              
    // pointer to STARTUPINFO
 LPPROCESS_INFORMATION lpProcessInformation // pointer to PROCESS_INFORMATION
 );
 
 At first this looks a real mouthful !! However lets go through it piece by
    piece and see that its actually not that bad.
 
 Before looking at what everything does, lets translate this into a more familiar
    Clarion prototype. Firstly in C the type the function returns is placed before
    the function name, in this case BOOL. (Incidentally if theres nothing
    before the name then its assumed the function returns a Long in 32 bit
    and a Short in 16 bit. If the function returns nothing, i.e. its a procedure,
    then the return type is VOID).
 
 Another point to bear in mind is that the Win API uses Pascal parameter passing
    techniques and you also need to use the RAW attribute since this is a non-Clarion
    DLL. Actually the Raw attribute is only necessary in certain cases, but it
    does no harm on the others, so I put it in on all API calls to make thinking
    easier. The Name attribute isnt strictly necessary yet, but youll
    see in a minute that it comes in handy. So far our prototype looks like this..
 
 CreateProcess ( ??
    ), Byte, Pascal, Raw, Name(CreateProcess)
 
 Now let's look at the parameters that it takes. Actually although it looks
    complicated the types tell you what they are. For example LP stands for long
    pointer, things ending in STR are a string and so on. Actually when dealing
    with the API strings are always Cstrings, and are usually passed using a pointer
    in this way - so get used to the LPSTR construction ! As you can see in the
    above they come in a variety of flavors, but in Clarion all of these flavors
    become a *CSTRING.
 
 The two Security Attribute parameters are only used in Windows NT. As we want
    our function to work for both Windows 95 and Windows NT well set these
    to Null, i.e. 0. This means that in Windows NT the process we create will
    get default security settings.
 
 Bool as we mentioned earlier is a BYTE, and Dword stands for Double Word.
    A Word in C is the same as a USHORT in Clarion, and a Dword is the same as
    a ULONG in Clarion. The LPVoid type is also a pointer, but in this case its
    a pointer to a group of strings. Well examine this one more closely
    in a moment. The last two parameters are pointers to groups that contain a
    number of options and flags and things like that. Its in these groups
    (which Windows is very keen on) that most of the complexity, and indeed most
    of the power, of API functions is revealed. The groups are documented inside
    the library source code for those that are interested. Actually the first
    group, SRARTUPINFO, sets a lot of the options for CreateProcess, and PROCESS_INFORMATION
    contains a number of handles that are returned by the function.
 
 So our eventual prototype looks like this:
 
 CreateProcess ( *CString, *CString,
    Long, Long, Byte, Ulong, *CString, *CString, |
 *StartupInfo, *ProcessInfo ), Byte, Pascal, Raw, Name(CreateProcess)
 
 The name of the wrapper function is called ARUN. It is prototyped as...
 
 ARUN (String, <String>, <String>,
    <Long>, <Long>, <Long>, <Long>, <Long>, <Long>,<Long>),
    Long, Proc
 
 ... and is documented as...
 
 ARUN (Program,
    StartInDirectory, EnvironmentBlock,
    Priority, InitialState,
    Xpos, Ypos, Width,
    Height, Wait)
 
 Program
 
 This is the name of the program, including its path (if necessary) and any
    command line parameters it may take.
 
 Start In Directory
 
 This is the directory in which the program should initially start.
 
 Environment Block
 
 Some programs, especially legacy DOS and Windows 3.1 programs use the Environment
    space to store startup settings. This can be a problem when running from Windows
    as these settings usually require changes to the AutoExec.Bat, which in Windows
    95 is something to avoid.
 
 CreateProcess lets you specify an environment space specifically for a program.
    This is passed to the function as a list of null-terminated strings, terminated
    itself by a null. For example:
 
 EnvStr String(512) ! note we use
    a clarion string here
 code
 EnvStr = (path=c:\dos;c:\windows<0>clavm0=e:\<0><0>)
 
 Note that each setting is separated by a <0>
    and the whole string is terminated by a
    <0> as well.
 
 Priority
 
 You set the priority of the new process to one of 0,1,2,3 or 4.
 
      Idle priority. This is the lowest priority. The new process will only
        run if the system is idle. This is ideal for housekeeping type programs,
        and background process type programs.Normal priority. This is the default if this parameter is omitted. If
        the parameter is 0 then this is also the priority used. This is the same
        priority as other Windows programs.High priority. This preempts other windows programs and gets most of
        the available CPU time. This should be used with care as it stops other
        programs from getting time.RealTime priority. This is the highest priority possible. It preempts
        all other windows processes including the mouse and hard disk cache. This
        should only be used with extreme care. Initial State
 
 You can set the new program to open in one of the following modes (valid values
    0,1,2,3).
 
      Note that some programs, especially Clarion programs, may not respond to this
    requested behavior.Normal ( new program gets the focus). This is the default if the parameter
        is omitted or set to 0.Maximized (new program gets the focus )Minimized ( calling program keeps the focus ) 
 Xpos, Ypos, Width, Height
 
 These parameters determine the starting position, and size of the program.
    Note that although these apply they may not be obvious immediately. For example
    if the program is open maximized, then these positions will only apply when
    the window is "Restored".
 
 Wait
 
 This determines if the program must wait or not for the new program to finish
    before carrying on. If this is set to 0 (or omitted) then the program doing
    the calling (the Parent) carries on immediately after running the child. If
    this is set to 1 then the Parent waits until the Child has terminated before
    it continues.
 
 ARUN Returns
 
 The function returns a long containing one of the following:
 
      Example0 - The program called ran correctly, and the function waited for the
        called program to terminate before returning.>0 - The program called ran correctly and the function returned immediately
        with the ProcessIdentifier of the new program that is running. This identifier
        ( often referred to in Windows as a Handle ) is needed if we want to make
        use of the ENDRUN function.<0 - The program called could not run for some reason. The returned
        value is the error code multiplied by -1. In other words if the error
        code was 2, then the function would return -2. Note that this error code
        is a Windows error, as returned by GetLastError, not a Clarion error.
        The specific error message can be checked by looking up the error code
        in a file called WinError.Clw. This file is included with the library
        files.  
 result long
 code
 result = aRun ('c:\windows\notepad.exe','d:\secwin') ! run the notepad
    starting in the d:\Secwin dir.
 result = aRun (c:\windows\notepad.exe,,,,,,,,,1) ! start the notepad,
    and wait for it to finish.
 result = aRun (c:\windows\calc.exe,,,,3) ! run the calculator, but
    start it minimized.
 EndRun (Result) ! Close the calculator opened in the above line
 
 Next lets look at the TerminateProcess Function, and the wrapper well
    make called ENDRUN.
 
 Not surprisingly TerminateProcess is a lot simpler than CreateProcess, and
    requires far fewer parameters. Nevertheless we can still simplify it a little.
 
 BOOL TerminateProcess(
 HANDLE hProcess,  // handle to the process
 UINT uExitCode   // exit code for the process
 );
 
 By now you should be used to the layout as well as the BOOL
    data type. Both HANDLEs
    and UINTs are
    ULONGS
    in the Win32 API. So a Clarion prototype of the function is;
 
 TerminateProcess(ULong, ULong), Byte, Pascal, Name(TerminateProcess)
 
 The first parameter is a process identifier, as returned by the CreateProcess
    function. The second is the exit code that the program should return when
    it closes. Return codes are almost never used in Windows programs, so our
    wrapper function, ENDRUN,
    will simplify the call by setting this to 0. ENDRUN
    is prototyped as follows:
 
 ENDRUN ( Ulong )
 
 and documented as follows
 
 ENDRUN ( ProcessID )
 
 ProcessID
 
 A Process Identifier as returned by the ARUN
    function.
 
 Example
 
 result long
 code
 result = aRun ('c:\windows\notepad.exe','d:\secwin') ! run the notepad
    starting in the d:\Secwin dir.
 ! do some code here
 ENDRUN(result)
 
 The included files include a project library with source code for the
	ARUN
    and ENDRUN
    functions, a simple template for using in your apps, and the WinError.Clw
    errors file. The template defines a single global extension which adds the
    prototypes to your app for you, and includes the library in your project.
    You will need to register the template in your template registry, as well
    as compile the project and copy the API.LIB file from your \cw20\obj directory
    to your \cw20\lib directory.
 
 As a last note, remember that ARUN
    and ENDRUN
    are 32 bit functions. Thus they cannot be used in 16 bit programs.
 
 
 © 1997, Online Publications, Inc. Reproduced
      with permission.
 
 
 
	© 2012 CapeSoft Software CC
 |