/* 
 * TERMINAT.C -- Terminate Apps and Tasks
 *		 Copyright (c) 1991, Gordon Harris, Data Arts
 *		 3349 Humboldt Ave. S.
 *		 Minneapolis, MN 55408
 *
 *		 (612) 825-5436
 *
 *		 Comments to CIS [72611,620]
 */


#define WIN31
#define STRICT
#include <windows.h>
#include <windowsx.h>
#ifdef DEBUG
#include <debug.h>
#endif
#include <toolhelp.h>
#include "terminat.h"


char szAppName[] = "Terminat";
HINSTANCE   hInst;
MODULEENTRY me;
TASKENTRY   te;
WNDENUMPROC lpfn;

#define hLst GetDlgItem(hDlg, ID_LIST)
#define hBut GetDlgItem(hDlg, ID_CLOSE)

int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow)
   {
   DLGPROC lpfnDlg;
   hInst = hInstance;

   if (hPrevInst)
      return 0;

   lpfnDlg = (DLGPROC) MakeProcInstance((FARPROC)DlgProc, hInstance);
   DialogBox(hInstance, "TERMINAT", NULL, lpfnDlg);
   FreeProcInstance((FARPROC)lpfnDlg);
   return 0;
   }

BOOL _export CALLBACK AboutProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   {
   if (message == WM_COMMAND)
      {
      HANDLE_WM_COMMAND(OnCommand, hDlg, wParam, lParam);
      return TRUE;
      }
   return FALSE;
   }


BOOL _export CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
   {
   switch (message)
      {
      case WM_INITDIALOG:
	 return (BOOL) HANDLE_WM_INITDIALOG(OnInitDialog, hDlg, wParam, lParam);

      case WM_ICONERASEBKGND:
	 return (BOOL) HANDLE_WM_ICONERASEBKGND(OnIconEraseBkgnd, hDlg, wParam, lParam);

      case WM_SYSCOMMAND:
	 HANDLE_WM_SYSCOMMAND(OnSysCommand, hDlg, wParam, lParam);
	 return FALSE;

      case WM_ACTIVATEAPP:
	 HANDLE_WM_ACTIVATEAPP(OnActivateApp, hDlg, wParam, lParam);
	 return FALSE;

      case WM_COMMAND:
	 HANDLE_WM_COMMAND(OnCommand, hDlg, wParam, lParam);
	 return TRUE;

      case WM_DESTROY:
	 HANDLE_WM_DESTROY(OnDestroy, hDlg, wParam, lParam);
	 return FALSE;

      default:
	 return FALSE;
      }
   return FALSE;
   }

BOOL OnInitDialog(HWND hDlg, HWND hwndFocus, LPARAM lParam)
   {
   HMENU hMenu;

   hMenu = GetSystemMenu(hDlg,FALSE);
   DeleteMenu (hMenu, SC_MAXIMIZE, MF_BYCOMMAND);
   DeleteMenu (hMenu, SC_SIZE,	   MF_BYCOMMAND);
   AppendMenu(hMenu, MF_SEPARATOR, 0, (LPSTR)NULL);
   AppendMenu(hMenu, MF_STRING, ID_REREAD, (LPSTR)"&Reread task list");
   AppendMenu(hMenu, MF_STRING, ID_ABOUT,  (LPSTR)"A&bout Terminator...");

   /* Give our minimized dialog box an icon.. */
   SetClassWord(hDlg, GCW_HICON, (WPARAM) LoadIcon(hInst, szAppName));
   te.dwSize = sizeof(TASKENTRY);
   me.dwSize = sizeof(MODULEENTRY);
   lpfn = (WNDENUMPROC) MakeProcInstance((FARPROC) EnumProc, hInst);
   PostMessage(hDlg, WM_COMMAND, ID_GETLIST, 0L);
   return TRUE;
   }

BOOL OnIconEraseBkgnd(HWND hwnd, HDC hdc)
   {
   SetClassWord(hwnd, GCW_HICON, (WPARAM) LoadIcon(hInst, szAppName));
   return TRUE;
   }

void OnSysCommand(HWND hDlg, UINT cmd, int x, int y)
   {
   DLGPROC lpfnDlg;

   switch (cmd)
      {
      case ID_REREAD:
	 MessageBeep(MB_ICONQUESTION);
	 PostMessage(hDlg, WM_COMMAND, ID_GETLIST, 0L);
	 break;

      case ID_ABOUT:
	 lpfnDlg = (DLGPROC) MakeProcInstance((FARPROC)AboutProc, hInst);
	 DialogBox(hInst, "ABOUT", NULL, lpfnDlg);
	 FreeProcInstance((FARPROC)lpfnDlg);
	 break;

      case SC_CLOSE:
	 EndDialog(hDlg, TRUE);
      }
   }

void OnActivateApp(HWND hDlg, BOOL fActivate, HTASK htaskActDeact)
   {
   if (fActivate)
      PostMessage(hDlg, WM_COMMAND, ID_GETLIST, 0L);
   }

BOOL dYield (void)
   {
   MSG msg;

   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
      {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
      }
   return FALSE;
   }

void dWait (unsigned nMsecs)
   {
   HCURSOR hcursor;
   DWORD dwTime = GetTickCount();
   hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
   while (GetTickCount() < dwTime + (DWORD) nMsecs)
      dYield();
   SetCursor(hcursor);
   }

#define TASKFLAG HIWORD(l)

void OnCommand(HWND hDlg, int id, HWND hwndCtl, UINT codeNotify)
   {
   int n, j;
   LONG   l;
   char szMsg[120];
   switch (id)
      {
      case ID_LIST:
	 n = ListBox_GetCurSel(hLst);
	 if (n == LB_ERR)
	    return;
	 l = ListBox_GetItemData(hLst, n);

	 if (codeNotify == LBN_SELCHANGE)
	    Button_Enable(hBut, HIWORD(l));

	 else if (codeNotify == LBN_DBLCLK)
	    {
	    if (HIWORD(l))
	       {
	       TaskFindHandle(&te, (HANDLE)LOWORD(l));
	       wsprintf(szMsg, "Task   %04X %s hInst %04X hModule %04X SS %04X SP %04X sTop %04X sMin %04X sBot %04X",
		     te.hTask, (LPSTR)te.szModule, te.hInst, te.hModule, te.wSS, te.wSP, te.wStackTop, te.wStackMinimum, te.wStackBottom);
	       }
	    else
	       {
	       ModuleFindHandle(&me, (HANDLE)LOWORD(l));
	       wsprintf(szMsg, "Module %04X %s refcount %d", me.hModule, (LPSTR)me.szExePath, me.wcUsage);
	       }
	    MessageBox(hDlg, szMsg, szAppName, MB_ICONINFORMATION | MB_OK);
	    }
	 return;

      case ID_GETLIST:
	 Button_Enable(hBut, FALSE);
	 SetWindowRedraw(hLst, FALSE);

	 j = ListBox_GetCurSel(hLst);
	 ListBox_ResetContent(hLst);

	 /* Enumerate the loaded modules.. */
	 me.dwSize = sizeof(MODULEENTRY);
	 ModuleFirst(&me);
	 do {
	    n = ListBox_AddString(hLst, me.szModule);
	    ListBox_SetItemData(hLst, n, MAKELONG(me.hModule,0)); // HIWORD == 0 == module
	    } while (ModuleNext(&me));

	 /* Now enumerate the tasks.. */
	 te.dwSize = sizeof(TASKENTRY);
	 TaskFirst(&te);
	 do {
	    /* Find the module which matches the task.. */
	    n = ListBox_FindString(hLst, 0, te.szModule);
	    /* Replace the module handle with the task handle.. */
	    if (n != LB_ERR)
	       ListBox_SetItemData(hLst, n, MAKELONG(te.hTask,1)); // HIWORD == 1 == task
	    } while (TaskNext(&te));

	 if (j != LB_ERR)
	    ListBox_SetCurSel(hLst, j);
	 else
	    ListBox_SetCurSel(hLst, 0);

	 SetWindowRedraw(hLst, TRUE);

	 InvalidateRect(hLst, NULL, TRUE);
	 return;

      case ID_TERMINATE:
	 n = ListBox_GetCurSel(hLst);
	 if (n == LB_ERR)
	    return;
	 l = ListBox_GetItemData(hLst, n);
	 /* If this is a task, terminate it.. */
	 if ( HIWORD(l) && IsTask( (HTASK) LOWORD(l)) )
	    TerminateApp((HANDLE)LOWORD(l), NO_UAE_BOX);
	 /* Else, reduce the reference count to 0.. */
	 else
	    {
	    j = 0;
	    while (n = FreeModule((HINSTANCE)LOWORD(l)))
	       {
	       if (j == n)
		  break;
	       j = n;
	       }
	    }

	 dWait(2000);
	 PostMessage(hDlg, WM_COMMAND, ID_GETLIST, 0L);
	 return;

      case ID_CLOSE:
	 n = ListBox_GetCurSel(hLst);
	 if (n == LB_ERR)
	    return;
	 l = ListBox_GetItemData(hLst, n);
	 if (HIWORD(l) && IsTask((HTASK) LOWORD(l)) )
	    EnumTaskWindows((HTASK)LOWORD(l), (WNDENUMPROC)lpfn, 0L); //Kill the app..
	 dWait(2000);
	 PostMessage(hDlg, WM_COMMAND, ID_GETLIST, 0L);
	 return;

      case ID_QUIT:
	 EndDialog(hDlg, TRUE);
	 return;
      }
   }

void OnDestroy(HWND hwnd)
   {
   FreeProcInstance((FARPROC)lpfn);
   }

BOOL _export CALLBACK EnumProc (HWND hwnd, LPARAM lParam)
   {
   PostMessage(hwnd, WM_CLOSE, 0, 0L);
   MessageBeep(MB_ICONEXCLAMATION);
   return 0;
   }
