/*

Name:  Andrew Krois

Date:  June 15, 1988

Function(s) demonstrated in this program: Int21Function4B

Windows version:  2.03

Windows SDK version:  2.00

Compiler version:  C 5.10

Description:  This is a Function created using Masm, and it corresponds
   with the MS-DOS interrupt 21 function 4BH.

Additional Comments:  This function can be used to spawn windows
   applications, as well as old MS-DOS applications from within a 
   windows application.  A method of sending command line arguments
   to the spawnded windows application is also discussed.

*/

#define NOMINMAX
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "WinSpawn.h"

HWND     hWndMain;
HANDLE   hInstMain;
char     szOutputBuffer1 [70];
char     szOutputBuffer2 [500];
char     szSpawnAppName  [40];
char     szCommandLine   [40];
HWND     hSpawnAppEdit, hExtensionEdit, hCommandLineEdit, hOK2;
FARPROC  lpProcSpawnDlgBox;
FARPROC  lpProcNewSpawnDlgBox;
FARPROC  lpProcOldSpawnApp;
FARPROC  lpProcOldExtension;
FARPROC  lpProcOldCommandLine;
char     szDlgSpawnAppName [40];
char     szDlgCommandLine [40];
char     szDlgExtension [4] = "EXE";

typedef struct {
         WORD   environment;
         LPSTR  commandline;
         LPSTR  FCB1;
         LPSTR  FCB2;
        } EXECBLOCK;
EXECBLOCK      exec;
WORD           wFCB1Contents[2];


/****************************************************************************/
/************************    Message Structure      *************************/
/****************************************************************************/

struct { char *szMessage; }
       Messages [] = {
"About",
"     This is a sample application to demonstrate the\n\
use  of  Interrupt 21 function 4B in spawning Windows\n\
applications, and MS-DOS applications from a Windows\n\
Windows application.  Program by Andrew Krois",

"Help Message",
"     This program demonstrates the use of the\n\
Int21Function4B function.  Use the menu to select\n\
either a MS-DOS application or a Windows application\n\
to be spawned.  The program will also send command\n\
line arguments to the spawned application.",

};	

/****************************************************************************/

void ProcessMessage (HWND, int); 

void ProcessMessage (hWnd, MessageNumber) 
     HWND     hWnd;
     int      MessageNumber;
{
     sprintf (szOutputBuffer1, "%s", Messages [MessageNumber]);
     sprintf (szOutputBuffer2, "%s", Messages [MessageNumber + 1]);
     MessageBox (hWnd, szOutputBuffer2, szOutputBuffer1, MB_OK);
}       

/****************************************************************************/

int PASCAL WinMain (hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
     HANDLE      hInstance, hPrevInstance ;
     LPSTR       lpszCmdLine ;
     int         nCmdShow ;
     {
     static char szAppName [] = "WinSpawn" ;
     static char szChildClass [] = "WinSpawnChild" ;
     HWND        hWnd ;
     WNDCLASS    wndclass ;
     MSG msg;

     if (!hPrevInstance) 
          {
          wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
          wndclass.lpfnWndProc   = WndProc ;
          wndclass.cbClsExtra    = 0 ;
          wndclass.cbWndExtra    = 0 ;
          wndclass.hInstance     = hInstance ;
          wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
          wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
          wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
          wndclass.lpszMenuName  = szAppName ;
          wndclass.lpszClassName = szAppName ;

          if (!RegisterClass (&wndclass))
               return FALSE ;

          }

     hWnd = CreateWindow (szAppName,            /* window class name       */
                    "Windows Spawn",            /* window caption          */
                    WS_OVERLAPPEDWINDOW,        /* window style            */
                    CW_USEDEFAULT,              /* initial x position      */
                    0,                          /* initial y position      */
                    CW_USEDEFAULT,              /* initial x size          */
                    0,                          /* initial y size          */
                    NULL,                       /* parent window handle    */
                    NULL,                       /* window menu handle      */
                    hInstance,                  /* program instance handle */
                    NULL) ;                     /* create parameters       */

     ShowWindow (hWnd, nCmdShow) ;
     UpdateWindow (hWnd) ;

     hWndMain  = hWnd;
     hInstMain = hInstance;

     lpProcSpawnDlgBox    = MakeProcInstance (SpawnDlgBoxProc, hInstance);
     lpProcNewSpawnDlgBox = MakeProcInstance (NewSpawnDlgBoxProc,hInstance);

     while (GetMessage(&msg, NULL, 0, 0))
     {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
     } 
     return (msg.wParam) ;     
     }

/****************************************************************************/

long FAR PASCAL WndProc (hWnd, iMessage, wParam, lParam)
HWND     hWnd ;
unsigned iMessage ;
WORD     wParam ;
LONG     lParam ;
{
 HMENU       hMenu;
 PAINTSTRUCT ps;

 switch(iMessage)
 {
  case WM_CREATE:
       hMenu = GetSystemMenu (hWnd, FALSE);

       ChangeMenu (hMenu, NULL, "&About", IDM_ABOUT, 
                   MF_APPEND | MF_STRING);
       break;

  case WM_SYSCOMMAND:
       switch (wParam) {
          case IDM_ABOUT:
               ProcessMessage (hWnd, 0);
               break;
          default:
               return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
       }
       break;

  case WM_COMMAND:
       switch (wParam) {

          case IDM_SPAWNIT:
               hMenu = GetSystemMenu (hWnd, NULL);
               ChangeMenu (hMenu, SC_CLOSE, "&Close", SC_CLOSE, 
                           MF_CHANGE | MF_DISABLED | MF_GRAYED);

               GlobalCompact(-1L);
               LockData(0);

               exec.environment = 0;
               exec.commandline = szCommandLine;

               wFCB1Contents[0] = 2;
               wFCB1Contents[1] = SW_SHOWNORMAL;
               exec.FCB1 = (LPSTR)wFCB1Contents;
               exec.FCB2 = (LPSTR)NULL;

               Int21Function4B(0, (LPSTR)szSpawnAppName,
                               (LPSTR)&exec);

               UnlockData(0);
               break;

          case IDM_CLOCK:
               sprintf (szSpawnAppName,"CLOCK.EXE");
               sprintf (szCommandLine, "");
               SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L);
               break;

          case IDM_DOSDIRSORT:			
               sprintf (szSpawnAppName,"COMMAND.COM");
               sprintf (szCommandLine, "%c /c dir | sort", 14);
               SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L);
               break;

          case IDM_DOSTYPE:			
               sprintf (szSpawnAppName,"COMMAND.COM");
               sprintf (szCommandLine, "%c /c type winspawn.c", 0x13);
               SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L);
               break;

          case IDM_NOTEPAD:
               sprintf (szSpawnAppName,"NOTEPAD.EXE");
               sprintf (szCommandLine, " WINSPAWN.C");
               SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L);
               break;

          case IDM_SPAWNALL:
               DialogBox (hInstMain, (LPSTR)"SpawnDlgBox", hWnd, 
                        lpProcSpawnDlgBox);
               sprintf (szSpawnAppName, "%s.%s", szDlgSpawnAppName,
                        szDlgExtension);
               sprintf (szCommandLine, "%c %s", strlen (szDlgCommandLine) + 1,
                        szDlgCommandLine);
               SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L);
               break;

          case IDM_HELP:
               ProcessMessage (hWnd, 2);
               break;
       }
       break;

  case WM_PAINT:
       BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
       EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
       break;

  case WM_DESTROY:
       PostQuitMessage(0);
       break;

  default:
  {
   return DefWindowProc (hWnd, iMessage, wParam, lParam) ;
  }
 }
 return (0L); 
}

/****************************************************************************/

BOOL FAR PASCAL SpawnDlgBoxProc (hDlg, iMessage, wParam, lParam)
HWND hDlg;
unsigned iMessage;
WORD wParam;
LONG lParam;
{
     int Index;
     char szChange [10];
     long lReturn;

     switch (iMessage) {
     case WM_INITDIALOG:
       SendDlgItemMessage (hDlg, IDD_DLGSPAWNAPPNAME, EM_LIMITTEXT,
                           (WORD)40, 0L);
       SendDlgItemMessage (hDlg, IDD_DLGCOMMANDLINE, EM_LIMITTEXT,
                           (WORD)40, 0L);
       SendDlgItemMessage (hDlg, IDD_DLGEXTENSION, EM_LIMITTEXT,
                           (WORD)10, 0L);
         SetDlgItemText (hDlg, IDD_DLGEXTENSION, szDlgExtension);

       hSpawnAppEdit = GetDlgItem (hDlg, IDD_DLGSPAWNAPPNAME);
         lpProcOldSpawnApp = 
                  (FARPROC) GetWindowLong (hSpawnAppEdit, GWL_WNDPROC);
         SetWindowLong (hSpawnAppEdit, GWL_WNDPROC, 
                        (LONG)lpProcNewSpawnDlgBox);
         SendMessage (hSpawnAppEdit, EM_SETSEL, 0, MAKELONG (0,32767));

       hExtensionEdit = GetDlgItem (hDlg, IDD_DLGEXTENSION);
         lpProcOldExtension =
                  (FARPROC)GetWindowLong (hExtensionEdit, GWL_WNDPROC);
         SetWindowLong (hExtensionEdit, GWL_WNDPROC, 
                        (LONG)lpProcNewSpawnDlgBox);
         SendMessage (hExtensionEdit, EM_SETSEL, 0, MAKELONG (0,32767));

       hCommandLineEdit = GetDlgItem (hDlg, IDD_DLGCOMMANDLINE);
         lpProcOldCommandLine = 
                  (FARPROC) GetWindowLong (hCommandLineEdit, GWL_WNDPROC);
         SetWindowLong (hCommandLineEdit, GWL_WNDPROC, 
                        (LONG)lpProcNewSpawnDlgBox);
         SendMessage (hCommandLineEdit, EM_SETSEL, 0, MAKELONG (0,32767));

       hOK2 = GetDlgItem (hDlg, IDOK);
     
       return TRUE;
       break;

     case WM_COMMAND:
       switch (wParam) {
         case IDOK:            
              GetDlgItemText (hDlg, IDD_DLGSPAWNAPPNAME,szDlgSpawnAppName,40);
              GetDlgItemText (hDlg, IDD_DLGCOMMANDLINE, szDlgCommandLine,40);
              GetDlgItemText (hDlg, IDD_DLGEXTENSION, szDlgExtension, 4) ;
              EndDialog (hDlg, TRUE);
              break;

         default:
              return FALSE;
      }
    default:
      return FALSE;
  }
  return TRUE;
}

/****************************************************************************/

BOOL FAR PASCAL NewSpawnDlgBoxProc  (hWnd, iMessage, wParam, lParam) 
     HWND     hWnd;
     unsigned iMessage; 
     WORD     wParam;
     LONG     lParam;
{
     switch (iMessage) {
       case WM_GETDLGCODE:
            return (DLGC_WANTALLKEYS);

       case WM_CHAR:
            if ((wParam == VK_TAB) || (wParam == VK_RETURN)) {
                SendMessage (hWndMain, WM_USER, 0, 0L);
                SetFocus (FindNextWindow (hWnd));
                return TRUE;
            }
            else {
              if (hWnd == hSpawnAppEdit) 
                return ((BOOL)CallWindowProc (lpProcOldSpawnApp, hWnd, 
                        iMessage, wParam, lParam));

              if (hWnd == hExtensionEdit) 
                return ((BOOL)CallWindowProc (lpProcOldExtension, hWnd, 
                        iMessage, wParam, lParam));

              if (hWnd == hCommandLineEdit) 
                return ((BOOL)CallWindowProc (lpProcOldCommandLine, hWnd, 
                        iMessage, wParam, lParam));
            }
            break;

       default:
         if (hWnd == hSpawnAppEdit)
            return ((BOOL)CallWindowProc (lpProcOldSpawnApp, hWnd,
                    iMessage, wParam, lParam));

         if (hWnd == hExtensionEdit)
            return ((BOOL)CallWindowProc (lpProcOldExtension, hWnd,
                    iMessage, wParam, lParam));

         if (hWnd == hCommandLineEdit)
            return ((BOOL)CallWindowProc (lpProcOldCommandLine, hWnd, 
                    iMessage, wParam, lParam));
     }
}

/****************************************************************************/

HWND FindNextWindow (hWnd)
     HWND   hWnd;
{
     if (hWnd == hSpawnAppEdit)         return hExtensionEdit;
     if (hWnd == hExtensionEdit)        return hCommandLineEdit;
     if (hWnd == hCommandLineEdit)      return hOK2;
     return NULL;
}
