Newsgroups: comp.lang.smalltalk
Path: cantaloupe.srv.cs.cmu.edu!bb3.andrew.cmu.edu!nntp.sei.cmu.edu!cis.ohio-state.edu!math.ohio-state.edu!howland.reston.ans.net!ix.netcom.com!netcom.com!pencin
From: pencin@netcom.com (Russell Pencin)
Subject: Re: HELP!! Running Win Executables
Message-ID: <44kkc4$1sea_001@netcom.com>
Keywords: Win3.11 VW2.0 IBM/PC External Processes .EXE Executable
Sender: pencin@netcom9.netcom.com
Organization: NETCOM On-line Communication Services (408 261-4700 guest)
X-Newsreader: News Xpress Version 1.0 Beta #4
References: <449ivf$1298@msunews.cl.msu.edu>
Date: Sat, 30 Sep 1995 23:37:40 GMT
Lines: 166

I hope this doesn't break anyone's reader....

  VisualWorks InfoNote 002

               Launching MS-Windows and DOS
              Applications from VisualWorks
              Version 1.5 January 13, 1992
  Submitted by: Mike Khaw

  VisualWorks on MS-Windows, in conjunction with CPOK (the C
  Programming ObjectKit), makes it possible to access external procedures from
  a VisualWorks image and launch applications using the built-in runtime
  external code support.  This includes DOS and Windows applications and
  .BAT files that run under enhanced-mode Windows.

  Note: Before actually using this example, you should obtain a copy of the
  Windows SDK Programmer's Reference Volume 2: Functions and refer to it
  for detailed information on parameters and return values.

  In order to launch applications from VisualWorks, you need to:

  o Install CPOK into your VisualWorks image (see the CPOK Release
  Notes).  You should also read the CPOK documentation.
  o Define a subclass of ExternalInterface that calls the Windows API
  function named WinExec.
  o Write the method that launches the DOS application.

  Define the ExternalInterface subclass
  Using the system browser, define the following class.  Place this class 
either in an existing class category or create a new one if desired.

      ExternalInterface  subclass:  #WindowsKernel

        includefiles: 
        includedirectories:
        libraryfiles: 'KERNEL.DLL'
        librarydirectories:
        generatemethods:
        bevirtual: false

        instanceVariableNames:
        classVariableNames:
        pooldictionaries: "
        category: 'External-Interface'

  This subclass, WindowsKernel, uses the Windows' DLL KERNEL.DLL so we
  type this in after libraryfiles.  You also need to specify the category.
  In this example we use External-Interface'.  You may want to create your
  own category.  The pooldictionaries will be filled in automatically when you 
  accept this method.

  Define the method to make the external call

  Once you have defined the class WindowsKernel, you need to create the
  following instance method under a method protocol named 'procedures':

     WinExec: aString   newWindowState: aShortInteger

        <C: short  _far  _pascal  WinExec(char _far *, short)>

  This method actually makes the call to the DLL procedure.  Common
  convention is to use the actual procedure name as the first keyword of the
  method name.

  Once you have typed the above into the browser, accept it.

  In this method, we supply two parameters: the name of the application to run
  (aString) and how we want the window opened (aShortlnteger).

  aString contains the command line (filename plus optional parameters) for
  the application to be launched.  This string can contain a pathname.  See
  the Windows SDK Programmer's Reference for the search order if a path is not
  specified.

  aShortInteger specifies how a Windows application window is to be shown.
  See the Windows SDK Programnier's Reference under ShowWindow for a
  list of possible values.  See the SDK C header file windows.h for the
  integer values corresponding to the various SW_    parameters.

  If successful, the return value for this method will identify the instance
  of the loaded module.  If the return value is a number less than 32, then
  the launch was unsuccessful.

  Define the method that uses the procedure

  On the class side of WindowsKernel in a protocol named 'utilities', we add
        the following method.

  Note:  The comment line contains the message used to execute this method.
         You can highlight the text between the quotes, bring up an <operate>
         menu and select do it.

 We send the message WinExec>newWindowState; with the name of the DOS
 application and provide a newWindowState; in this case, SW_SHOW.  Note also
 that we trap for the return values that indicate errors by testing status.   
 If the launch is unsuccessful, we can notify the user.

        WinExec:  aString  newWindowState:  aShortlnteger

           WindowsKernel WinExec:'notepad' newWindowState: l.

       	| status |
	status := self new WinExec: aString newWindowState: aShortInteger.
	status > 31 ifTrue:  [^ status].
 	status = 0 ifTrue: [self error: 'Windows is out of memory.'].
	status = 2  ifTrue:  [self  error: 'Windows reports File not found.'].
	status = 3  ifTrue: [self  error: 'Windows reports Path not found.'].
	status = 5  ifTrue:  [self  error: 'Attempt to dynamically link to    
				a task.'].
	status = 6  ifTrue:  [self  error: 'Library requires separate data
				 segments for each task.'].
	status = 10 ifTrue: [self error: 'Incorrect Windows version.'].
	status = 11 ifTrue: [self error: 'Invalid EXE file.'].
	status = 12 ifTrue: [self error: 'OS/2 application.'].
	status = 13 ifTrue:: [self error: 'DOS 4.0 application.'].
	status = 14 ifTrue:: [self error: 'Unknown EXE type.'].
	status = 15 ifTrue: [self error: 'Attempt in protected mode to
				 load .EXE from earlier version of Windows.'].
	status = 16 ifTrue: [self error: 'Attempt to load 2nd instance of EXE
			 containing multiple writeable data segments,'].
	status = 17 ifTrue: [self error: 'Attempt in large-frame EMS mode to
				load 2nd instance of application that links
				non-shareable DLLs already  in   use.'].
 	self error: ['Undocumented error return from WindowsKernel.']



Note: In this example, we create a new instance of the interface for every use
of WinExec.  This can be inefficient because of the overhead involved 
in creating interface instances.  If we were making this call frequently, our
application should create an instance of WindowsKernel and invoke the method 
on the instance side.

Using this method

  Having created these methods, we can now launch DOS and Windows
  applications from our VisualWorks image.

  To test what we've done so far:

  * Create a VisualWorks interface.
  * Place an action button on the canvas.
  * Create a method for the button that executes:

        WindowsKernel WinExec: 'notepad' newWindowState: 1.

  * Install the canvas and open it.

--------------------------------------------------------------
Russell L. Pencin		| Smalltalk Training
The Smalltalk Brewery, Inc	| Smalltalk Mentoring
(415) 961-8948 (V)		| ParcPlace/Digitalk Training
(415) 964-4356 (F)		| Speed and Space Tuning
+-------------------------------------------------------------*
*   Handcrafted Objects with only the finest ingredients      *
+-------------------------------------------------------------*








  VisualWorks InfoNote 002    4

