#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <stdio.h>
#include <memory.h>
#include "resource.h"
#include "afxres.h"
#include "pstart.h"

HINSTANCE hInst;
char szAppName[]  = "PStartApp";
char szAppTitle[] = "Process Starter";

// Параметры запуска процессов
DWORD dwCreationFlags;

// Флаг ожидания завершения процессов
BOOL  fWaitTermination;

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------
int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;
  
  // Сохраняем идентификатор приложения
  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
    // Если было, выдвигаем окно приложения на
    // передний план
    if(IsIconic(hWnd))
	    ShowWindow(hWnd, SW_RESTORE);
	  SetForegroundWindow(hWnd);
    return FALSE;
  }

  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  wc.cbSize = sizeof(WNDCLASSEX);
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICONSM), 
    IMAGE_ICON, 16, 16, 0);
  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), 
    IMAGE_ICON, 32, 32, 0);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU);
  wc.lpszClassName = szAppName;
  if(!RegisterClassEx(&wc))
    if(!RegisterClass((LPWNDCLASS)&wc.style))
	  return FALSE;
    
  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle, 
     WS_OVERLAPPEDWINDOW, 
     CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 
     NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно и запускаем цикл 
  // обработки сообщений
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);
  while(GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, 
        LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hWnd, WM_COMMAND,    WndProc_OnCommand);

	default:
      return(DefWindowProc(hWnd, msg, wParam, lParam));
  }
}

// -----------------------------------------------------
// Функция WndProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void WndProc_OnCommand(HWND hWnd, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  switch (id)
  {
    // Отображаем диалоговую панель для выбора
    // программного файла и запускаем процесс
    case ID_FILE_STARTPROCESS:
    {
      StartProcess(hWnd);
      break;
    }

    case ID_FILE_OPTIONS:
    {
      // Отображаем диалоговую панель, предназначенную
      // для настройки параметров запуска процессов
      DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 
        hWnd, DlgProc);
      break;
    }
    
    case ID_FILE_EXIT:  
    {
	    // Завершаем работу приложения
      PostQuitMessage(0);
	    return 0L;
	    break;
    }
	  
  	case ID_HELP_ABOUT:
    {
      MessageBox(hWnd, 
        "Process Starter\n"
        "(C) Alexandr Frolov, 1996\n"
        "Email: frolov@glas.apc.org",
        szAppTitle, MB_OK | MB_ICONINFORMATION);
	     return 0L;
	     break;
    }

  	default:
	    break;
  }
  return FORWARD_WM_COMMAND(hWnd, id, hwndCtl, codeNotify,
    DefWindowProc);
}

// -----------------------------------------------------
// Функция StartProcess
// -----------------------------------------------------
void StartProcess(HWND hwnd)
{
  OPENFILENAME ofn;
  STARTUPINFO si;
  PROCESS_INFORMATION pi;
  char szBuf[256];
  DWORD dwExitCode;

  char szFile[256];
  char szDirName[256];
  char szFileTitle[256];
  char szFilter[256] = "Programs\0*.exe\0Any Files\0*.*\0";
  char szDlgTitle[] = "Start Process";


  memset(&si, 0, sizeof(STARTUPINFO));
  si.cb = sizeof(si);
  
  memset(&ofn, 0, sizeof(OPENFILENAME));
  GetCurrentDirectory(sizeof(szDirName), szDirName);
  szFile[0] = '\0';

  // Подготавливаем структуру для выбора файла
  ofn.lStructSize     = sizeof(OPENFILENAME);
  ofn.hwndOwner       = hwnd;
  ofn.lpstrFilter     = szFilter;
  ofn.lpstrInitialDir = szDirName;
  ofn.nFilterIndex    = 1;
  ofn.lpstrFile       = szFile;
  ofn.nMaxFile        = sizeof(szFile);
  ofn.lpstrFileTitle  = szFileTitle;
  ofn.nMaxFileTitle   = sizeof(szFileTitle);
  ofn.lpstrTitle      = szDlgTitle;
  ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST
    | OFN_HIDEREADONLY;

  // Выводим на экран диалоговую панель, предназначенную
  // для выбора файла
  if(GetOpenFileName(&ofn))
  {
    // Если файл выбран, запускаем его на выполнение
    if (*ofn.lpstrFile)
    {
      // Создаем процесс
      if(CreateProcess(NULL, ofn.lpstrFile, NULL, NULL,
        FALSE, dwCreationFlags, NULL, NULL, &si, &pi))
      {
        // Если было указано, что нужно ждать завершение 
        // процесса, выполняем такое ожидание
        if(fWaitTermination)
        {
          // Освобождаем идентификатор задачи запущенного
          // процесса, так как он нам не нужен
          CloseHandle(pi.hThread);
          
          // Выполняем ожидание завершения процесса
          if(WaitForSingleObject(pi.hProcess, 
            INFINITE) != WAIT_FAILED)
          {
            // Получаем и отображаем код завершения процесса
            GetExitCodeProcess(pi.hProcess, &dwExitCode);

            sprintf(szBuf, "Process terminated\n"
              "Exit Code = %lX", dwExitCode);
      
            MessageBox(hwnd, szBuf, 
              szAppTitle, MB_OK | MB_ICONINFORMATION);
          }

          // Освобождаем идентификатор процесса
          CloseHandle(pi.hProcess);
        }

        // Если процесс был запущен без ожидания,
        // освобождаем идентификаторы задачи и процесса
        else
        {
          CloseHandle(pi.hProcess);
          CloseHandle(pi.hThread);
        }
      }
      
      // Если про запуске процесса произошла ошибка,
      // получаем и отображаем ее код
      else
      {
        sprintf(szBuf, "CreateProcess: error %ld", 
          GetLastError());
      
        MessageBox(hwnd, szBuf, 
          szAppTitle, MB_OK | MB_ICONEXCLAMATION);
      }
    }
  }
}

// -----------------------------------------------------
// Функция DlgProc
// -----------------------------------------------------
LRESULT WINAPI
DlgProc(HWND hdlg, UINT msg, WPARAM wParam, 
        LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hdlg, WM_INITDIALOG, DlgProc_OnInitDialog);
    HANDLE_MSG(hdlg, WM_COMMAND,    DlgProc_OnCommand);

	default:
    return FALSE;
  }
}

// -----------------------------------------------------
// Функция DlgProc_OnInitDialog
// -----------------------------------------------------

BOOL DlgProc_OnInitDialog(HWND hdlg, HWND hwndFocus, 
                          LPARAM lParam)
{
  // По умолчанию мы будем запускать процессы
  // с нормальным приоритетом без ожидания
  // их завершения
  CheckDlgButton(hdlg, IDC_NORMAL, 1);
  return TRUE;
}

// -----------------------------------------------------
// Функция DlgProc_OnCommand
// -----------------------------------------------------
#pragma warning(disable: 4098)
void DlgProc_OnCommand(HWND hdlg, int id, 
  HWND hwndCtl, UINT codeNotify)
{
  switch (id)
  {
    case IDOK:
    {
      dwCreationFlags = 0;
      fWaitTermination = FALSE;  

      // Устанавливаем класс приоритета
      if(IsDlgButtonChecked(hdlg, IDC_Realtime))
      {
        dwCreationFlags = REALTIME_PRIORITY_CLASS;  
      }
      else if(IsDlgButtonChecked(hdlg, IDC_HIGH))
      {
        dwCreationFlags = HIGH_PRIORITY_CLASS;  
      }
      else if(IsDlgButtonChecked(hdlg, IDC_NORMAL))
      {
        dwCreationFlags = NORMAL_PRIORITY_CLASS;  
      }
      else if(IsDlgButtonChecked(hdlg, IDC_IDLE))
      {
        dwCreationFlags = IDLE_PRIORITY_CLASS;  
      }

      // Проверяем и устанавливаем режим ожидания
      if(IsDlgButtonChecked(hdlg, IDC_TERMINATION))
      {
        fWaitTermination = TRUE;
      }
      
      EndDialog(hdlg, 0);
      return TRUE;
    }

    case IDCANCEL:
    {
      EndDialog(hdlg, 0);
      return TRUE;
    }

  	default:
	    break;
  }
  return FALSE;
}
