home *** CD-ROM | disk | FTP | other *** search
/ PC Shareware 1996 December / PC_Shareware-1996-12.iso / windows / spectrum / sources / wspecem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-13  |  44.4 KB  |  1,307 lines

  1.  
  2. /* WSpecem.c : Windows interface for WSpecem emulator.
  3.  *
  4.  * Copyright 1996 Rui Fernando Ferreira Ribeiro.
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. #define APPNAME "SpecEmulApp"
  22.  
  23.  
  24. // main window client area size
  25. #define X_CORD 256
  26. #define Y_CORD 192
  27.  
  28. /*
  29.  *    WSpecEm.C
  30.  *
  31.  */
  32.  
  33. #include <windows.h>    // Defines bulk of Windows functions and such...
  34. #include <windowsx.h>
  35. #include <mmsystem.h>   // Defines additional Multi-Media functions...
  36. #include <shellapi.h>   // Drag-and-drop
  37. #include <string.h>
  38. #include "env.h"
  39. #include "snd/wave.h"
  40.  
  41. #if !defined(WIN32)
  42.    /*#include "c:/wing/include/wing.h"*/ // Defines WinG functions. Not use on Win32
  43.    #include "wing.h"
  44. #endif
  45.  
  46. #include <stdlib.h>            
  47. #include "wspecem.h"            // Local header
  48.  
  49. //  ==========================================================================
  50. //  GLOBAL VARIABLES ---------------------------------------------------------
  51. //  ==========================================================================
  52.  
  53. extern unsigned char keybd_buff[8]; /* Spectrum key states */
  54. extern unsigned char joystick;      /* Joystick positions  */
  55.  
  56. // callback function to interface
  57. extern BOOL CALLBACK DoPoke(HWND,UINT,WPARAM,LPARAM);
  58. extern BOOL CALLBACK DoSpeed(HWND,UINT,WPARAM,LPARAM);
  59.  
  60. char    szAppName[]= APPNAME;   // A handy string to identify this app
  61. char    szTitle[] = "Spectrum Emulator"; // For the title bar
  62.  
  63. HINSTANCE hInstApp;     // A handle that identifies this 'process'
  64. HWND      hwndApp;      // A handle that identifies the main window
  65. HPALETTE  hpalApp;      // A handle that identifies the main palette
  66. BOOL      fAppActive;   // A boolean that refers to this app being 'foreground'
  67.  
  68. // var to track state paused/not paused
  69. static BOOL NotPaused = 1;
  70.  
  71. // Define a structure that we will be using for keeping information about the
  72. // image we are currently drawing into.
  73. typedef struct _IMAGE {
  74.     BITMAPINFOHEADER bi;  // Bitmap header information.
  75.     RGBQUAD aColors[256]; // Palette color table
  76.     union { // Now for the pointer to the data buffer we can whack on:
  77.         LPVOID  lpvData; // This is the type that WinG likes to deal with
  78.         LPBYTE  lpIndex; // This is just to make it easier for us to access it
  79.     } data;
  80. } _IMAGE;
  81. _IMAGE image; // Contains most necessary information about the image to display
  82.  
  83.  
  84. // Define a structure for holding our palette data. This is the color palette
  85. // that will be assigned to both the above image, and be selected into the
  86. // 'Device Context' for the screen so we will have an 'Identity' palette which
  87. // will make for much faster screen updating.
  88. typedef struct _PALETTE
  89. {
  90.     WORD Version;
  91.     WORD NumberOfEntries;
  92.     PALETTEENTRY aEntries[256];
  93. } _PALETTE;
  94. _PALETTE LogicalPalette = {0x300, 256}; // The 'logical' palette we will use
  95.                     // "0x300" = Windows 3.0 or later
  96.                     // "256" = Number of colors
  97.  
  98. long Orientation = 1; // Bitmap Orientation: TopDown=1, BottomUp=-1
  99. HDC hdcImage = NULL;  // A handle to the Device Context for our image
  100.  
  101. HBITMAP gbmOldMonoBitmap = 0;   // Storage for the 'original' bitmap from our
  102.                 // Device Context, we need to restore it
  103.                 // later on, so we need to save it here.
  104.  
  105. /* RGB 'Spectrum' colors */
  106. static unsigned short rgbvals[16][3]={
  107.            /* Normal colours */
  108.           { 0x00, 0x00, 0x00}, { 0x00, 0x00, 0xcf},
  109.           { 0xcf, 0x00, 0x00}, { 0xcf, 0x00, 0xcf},
  110.           { 0x00, 0xcf, 0x00}, { 0x00, 0xcf, 0xcf},
  111.           { 0xcf, 0xcf, 0x00}, { 0xcf, 0xcf, 0xcf},
  112.  
  113.           /* Brigth colours */
  114.           { 0x00, 0x00, 0x00}, { 0x00, 0x00, 0xff},
  115.           { 0xff, 0x00, 0x00}, { 0xff, 0x00, 0xff},
  116.           { 0x00, 0xff, 0x00}, { 0x00, 0xff, 0xff},
  117.           { 0xff, 0xff, 0x00}, { 0xff, 0xff, 0xff}
  118. };
  119.  
  120. unsigned char ChangeFlashTime = 0; /* count time till inverting colours */
  121.  
  122. //  ==========================================================================
  123. //  FUNCTION DEFINITIONS -----------------------------------------------------
  124. //  ==========================================================================
  125.  
  126. // Forward declarations for all functions.
  127. // Listed in order they appear in this source listing
  128.  
  129. BOOL AppInit(HINSTANCE hInst,HINSTANCE hPrev,int sw);
  130. LONG FAR PASCAL AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
  131. BOOL AppPaint (HWND hwnd, HDC hdc);
  132. LONG AppCommand (HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
  133. BOOL FAR PASCAL AppAbout(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
  134. void AppExit(void);
  135.  
  136.  
  137. /*----------------------------------------------------------------------------*\
  138. |   WinMain( hInst, hPrev, lpszCmdLine, cmdShow )                              |
  139. |                                                                              |
  140. |   Description:                                                               |
  141. |       The main procedure for the App.  After initializing, it just goes      |
  142. |       into a message-processing loop until it gets a WM_QUIT message         |
  143. |       (meaning the app was closed).                                          |
  144. |                                                                              |
  145. |   Arguments:                                                                 |
  146. |       hInst           instance handle of this instance of the app            |
  147. |       hPrev           instance handle of previous instance, NULL if first    |
  148. |       szCmdLine       ->null-terminated command line                         |
  149. |       cmdShow         specifies how the window is initially displayed        |
  150. |                                                                              |
  151. |   Returns:                                                                   |
  152. |       The exit code as specified in the WM_QUIT message.                     |
  153. |                                                                              |
  154. \*----------------------------------------------------------------------------*/
  155. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
  156. {
  157.    MSG     msg;
  158.  
  159.    // NOTE: On Win32, hPrev will -always- be NULL
  160.  
  161.    // Do application initialization stuff
  162.    if (!AppInit(hInst,hPrev,sw)) {
  163.       return 0; // Something failed to initialize
  164.    }
  165.  
  166.    init_emul(hInst);
  167.  
  168.    /* If there is a snapshot in the command line, it is opened */
  169.    if(szCmdLine[0])
  170.       open_sna(szCmdLine);
  171.  
  172. #if !defined(WIN32)
  173.    /*{
  174.    WORD (FAR  PASCAL *SetPriority)(WORD, WORD);
  175.  
  176.    SetPriority = GetProcAddress(GetModuleHandle("KERNEL"), "SetPriority");
  177.    if(SetPriority != NULL) */
  178.                           /* -32, 15 -- numbers below 0 are locking system */
  179.    /*    SetPriority(GetCurrentTask(), (WORD)0);
  180.    else          
  181.       MessageBox(NULL, "!!!", "Not worked", MB_ICONHAND);
  182.    } */
  183. #endif
  184.  
  185.  
  186.    // Poll for messages from event queue.
  187.    // loop continues until WM_QUIT is encountered
  188.    for (;;) {
  189.       if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE)) {
  190.      if (msg.message == WM_QUIT) {
  191.         // When WM_QUIT comes through, we're DONE!
  192.         break;
  193.         }
  194.      TranslateMessage(&msg); // Messages for menu keys
  195.      DispatchMessage(&msg); 
  196.      }
  197.       else
  198.       {
  199.          if(NotPaused)
  200.         execute();
  201.  
  202.      if(!IsIconic(hwndApp))
  203.      {
  204.         static char FrameCounter = 0;
  205. #if defined(WINDOWS_SOUND)
  206.             static unsigned short freq;
  207. #endif
  208.         static unsigned short mscStart = 0;
  209.  
  210.         // if window needs a update
  211.         if(WindowDirty)
  212.         {
  213.            if(FrameCounter++ == ScreenUpdate)
  214.            {
  215.               FrameCounter = 0;
  216.               // Just force a redraw
  217.               InvalidateRect (hwndApp, NULL, FALSE);
  218.                }
  219.          }
  220.            
  221.  
  222.          if(NotPaused)
  223.          {
  224.             if(++ChangeFlashTime == 100)
  225.             {
  226.                // if it's time to invert colours...
  227.               ChangeFlashTime = 0; // reset counter
  228.               FlashState ^= 1;     // signal colours inverted
  229.               WindowDirty = 1;     // force a window redraw
  230.                   if(FrameCounter > 1)
  231.              FrameCounter = ScreenUpdate-2;
  232.              }
  233.            
  234. #if defined(WINDOWS_SOUND)
  235.             /* Can anyone put Windows .WAV sound to work?
  236.              */
  237.             freq = do_int_tasks();
  238. #endif
  239.             /* Watch for 20ms */
  240.             while((timeGetTime() - mscStart) < 20);
  241. #if defined(WINDOWS_SOUND)
  242.             /* More bits needed to Windows .WAV sound... */
  243.             StopSnd();
  244.             FPlaySnd((float)freq, -1, 11025, 8, 1);
  245. #endif
  246.             mscStart = timeGetTime();
  247.          }
  248.       } /* Iconic */
  249.       else
  250.              /* if program is in icon form and not paused, pause it */
  251.          if(NotPaused)
  252.          {
  253.         PostMessage(hwndApp, WM_COMMAND, IDM_PAUSE, 0L);
  254.          }
  255.     }
  256.       }
  257.       AppExit();        // Do application exiting stuff
  258.  
  259.       return msg.wParam;
  260. }
  261.  
  262. /*----------------------------------------------------------------------------*\
  263. |   AppInit( hInst, hPrev)                                                     |
  264. |                                                                              |
  265. |   Description:                                                               |
  266. |       This is called when the application is first loaded into               |
  267. |       memory.  It performs all initialization that doesn't need to be done   |
  268. |       once per instance.                                                     |
  269. |                                                                              |
  270. |   Arguments:                                                                 |
  271. |       hInstance       instance handle of current instance                    |
  272. |       hPrev           instance handle of previous instance                   |
  273. |       sw              window showmode                                        |
  274. |                                                                              |
  275. |   Returns:                                                                   |
  276. |       TRUE if successful, FALSE if not                                       |
  277. |                                                                              |
  278. \*----------------------------------------------------------------------------*/
  279. BOOL AppInit(HINSTANCE hInst,HINSTANCE hPrev,int sw)
  280. {
  281.    WNDCLASS cls;
  282.    char szBuf[260];
  283.  
  284.    // read options
  285.    GetWindowsDirectory((LPSTR)szBuf, 259);
  286.    strcat(szBuf, "\\wspecem.ini");
  287.    open_sna((LPSTR)szBuf);
  288.  
  289.    // Save instance handle for DialogBoxs as a global variable
  290.    hInstApp = hInst;
  291.  
  292.    if (!hPrev) {
  293.       // We don't already have a version running, so we need to
  294.       // register our window class with the system
  295.       cls.hCursor        = LoadCursor(NULL,IDC_ARROW);
  296.       cls.hIcon          = LoadIcon(hInst,szAppName);
  297.       cls.lpszMenuName   = szAppName;
  298.       cls.lpszClassName  = szAppName;
  299.       cls.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  300.       cls.hInstance      = hInst;
  301.       cls.style          = CS_BYTEALIGNCLIENT | CS_VREDRAW
  302.              | CS_HREDRAW | CS_DBLCLKS;
  303.       cls.lpfnWndProc    = (WNDPROC)AppWndProc;
  304.       cls.cbWndExtra     = 0;
  305.       cls.cbClsExtra     = 0;
  306.  
  307.       if (!RegisterClass(&cls)) {
  308.      return FALSE; // Failed to register class. No need to continue.
  309.       }
  310.    }
  311.    hwndApp = CreateWindow (szAppName,           // Class name
  312.                szTitle,             // Caption
  313.                WS_OVERLAPPEDWINDOW, // Style bits
  314.                CW_USEDEFAULT, 0,    // Position (x,y)
  315.                // Size (w,h)
  316.                X_CORD*Scale+GetSystemMetrics(SM_CYFRAME)*2,
  317.                Y_CORD*Scale+GetSystemMetrics(SM_CXFRAME)*2+
  318.                  GetSystemMetrics(SM_CYMENU) +
  319.                  GetSystemMetrics(SM_CYCAPTION),
  320.                  (HWND)NULL,    // Parent window (no parent)
  321.                  (HMENU)NULL,   // use class menu
  322.                  hInst,         // handle to current process instance
  323.                  (LPSTR)NULL    // no params to pass on
  324.                );
  325.  
  326.    if (hwndApp) {
  327.       ShowWindow(hwndApp,sw); // Time to display the window.
  328.       return TRUE;
  329.       }
  330.    else
  331.       {
  332.       return FALSE; // Failed to create window. No need to continue
  333.       }
  334. }
  335.  
  336. /*----------------------------------------------------------------------------*\
  337. |   Resize( )                                                                  |
  338. |                                                                              |
  339. |   Description:                                                               |
  340. |       This is called when the main window is about to be resized.            |                                         |
  341. |                                                                              |
  342. |   Returns:                                                                   |
  343. |       TRUE if successful, FALSE if not                                       |
  344. |                                                                              |
  345. \*----------------------------------------------------------------------------*/
  346. BOOL ResizeWindow(void)
  347. {
  348.    HWND hwndAppOld = hwndApp;
  349.  
  350.    /* It's important destroying the window only after we have created
  351.      a new one, or else we'll lose messages
  352.     */  
  353.    hwndApp = CreateWindow (szAppName,           // Class name
  354.                szTitle,             // Caption
  355.                WS_OVERLAPPEDWINDOW, // Style bits
  356.                CW_USEDEFAULT, 0,    // Position (x,y)
  357.                X_CORD*Scale+GetSystemMetrics(SM_CYFRAME)*2,// Size (w, h)
  358.                Y_CORD*Scale+GetSystemMetrics(SM_CXFRAME)*2+
  359.                  GetSystemMetrics(SM_CYMENU) +
  360.                  GetSystemMetrics(SM_CYCAPTION),
  361.                  (HWND)NULL,    // Parent window (no parent)
  362.                  (HMENU)NULL,   // use class menu
  363.                  hInstApp,      // handle to current process instance
  364.                  (LPSTR)NULL    // no params to pass on
  365.                );
  366.  
  367.    if (hwndApp) {
  368.       DestroyWindow(hwndAppOld);
  369.       ShowWindow(hwndApp,SW_SHOW); // Time to display the window.
  370.       return TRUE;
  371.       }
  372.    else
  373.       {
  374.       return FALSE; // Failed to create window. No need to continue
  375.       }
  376. }
  377.  
  378. /*----------------------------------------------------------------------------*\
  379. |   AppWndProc( hwnd, uiMessage, wParam, lParam )                              |
  380. |                                                                              |
  381. |   Description:                                                               |
  382. |       The window proc for the app's main (tiled) window.  This processes all |
  383. |       of the parent window's messages.                                       |
  384. |                                                                              |
  385. \*----------------------------------------------------------------------------*/
  386. LONG FAR PASCAL AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  387. {
  388.    //static int XOffset, YOffset;
  389.    static int dxClient, dyClient; // The 'Client' size. (drawing area of window)
  390.    PAINTSTRUCT ps;
  391.    HDC hdc;
  392.    UINT uMappedColors;
  393.    HMENU hmenu;
  394.  
  395.    switch (msg) {
  396.       case WM_CREATE:
  397.      // This occures during 'CreateWindow' time. Here is where we can
  398.      // easily initialize some things for this window.
  399.      srand ((int)GetTickCount()); // initialize the random seed
  400.      //SetTimer(hwnd, 1, 1, NULL);  // start up the WM_TIMER messages
  401.  
  402.      DragAcceptFiles( hwnd , TRUE );
  403.  
  404. #if defined(WINDOWS_SOUND)
  405.      /* Init wave driver */
  406.      FInitSnd(); /* if true, init sucessfull*/
  407. #endif
  408.  
  409.      // Init options on the menu
  410.      hmenu = GetMenu(hwnd);
  411.      CheckMenuItem(hmenu, IDM_SIZE1,  (Scale==1)?MF_CHECKED:MF_UNCHECKED);
  412.      CheckMenuItem(hmenu, IDM_SIZE2,  (Scale==2)?MF_CHECKED:MF_UNCHECKED);
  413.      CheckMenuItem(hmenu, IDM_SIZE3,  (Scale==3)?MF_CHECKED:MF_UNCHECKED);
  414.      CheckMenuItem(hmenu, IDM_SIZE4,  (Scale==4)?MF_CHECKED:MF_UNCHECKED);
  415.      CheckMenuItem(hmenu, IDM_SOUND,  (bSoundOn)?MF_CHECKED:MF_UNCHECKED);
  416.      CheckMenuItem(hmenu, IDM_COLOUR, (bFlashOn)?MF_CHECKED:MF_UNCHECKED);
  417.      CheckMenuItem(hmenu, IDM_MODEL3, (bModel3)?MF_CHECKED:MF_UNCHECKED);
  418.      CheckMenuItem(hmenu, IDM_DEBUG, MF_UNCHECKED);
  419.      break;
  420.  
  421.        //case WM_TIMER:
  422.        //         break;
  423.  
  424.        case WM_ACTIVATEAPP:
  425.       // The application z-ordering has changed. If we are now the
  426.       // foreground application wParm will be TRUE.
  427.       fAppActive = (BOOL)wParam;
  428.       break;
  429.  
  430.       case WM_ERASEBKGND:
  431.      return TRUE;
  432.      /* break; */
  433.  
  434.       case WM_SIZE:
  435.      // This message comes to us because the window size has been
  436.      // changed. It also comes to us when the application is first
  437.      // being executed.
  438.      dxClient = LOWORD(lParam); // The 'new' width of our window
  439.      dyClient = HIWORD(lParam); // The 'new' height of our window
  440.  
  441.      if(!hdcImage)   {
  442.         //  Create a new WinGDC and 8-bit WinGBitmap
  443.         HBITMAP hbm;
  444.         int Counter;
  445.         HDC Screen;
  446.         //RGBQUAD far *pColorTable;
  447.  
  448.         //  Get WinG to recommend the fastest DIB format
  449. #if defined(WIN32)
  450.         if (FALSE) {
  451. #else
  452.            if(WinGRecommendDIBFormat((BITMAPINFO far *)&image.bi)) {
  453. #endif
  454.           //  make sure it's 8bpp and remember the orientation
  455.           image.bi.biBitCount = 8;
  456.           image.bi.biCompression = BI_RGB;
  457.           Orientation = -1;
  458.           }
  459.            else {
  460.           //  set it up ourselves
  461.           image.bi.biSize = sizeof(BITMAPINFOHEADER);
  462.           image.bi.biPlanes = 1;
  463.           image.bi.biBitCount = 8;
  464.           image.bi.biCompression = BI_RGB;
  465.           image.bi.biSizeImage = 0;
  466.           image.bi.biClrUsed = 0;
  467.           image.bi.biClrImportant = 0;
  468.           }
  469.  
  470.            image.bi.biWidth = X_CORD;
  471.            image.bi.biHeight = Y_CORD * Orientation;
  472.  
  473.            //  create an identity palette from the DIB's color table
  474.  
  475.            // Get the Device Context of the screen
  476.            Screen = GetDC(HWND_DESKTOP);
  477.  
  478.  
  479.            // Get the 20 system colors as PALETTEENTRIES
  480.            GetSystemPaletteEntries(Screen,0,10,LogicalPalette.aEntries);
  481.            GetSystemPaletteEntries(Screen,246,10,LogicalPalette.aEntries
  482.             + 246);
  483.  
  484.            // Only a few DCs available, free this up so we aren't a hog
  485.            ReleaseDC(0,Screen);
  486.  
  487.            // Initialize the logical palette and DIB color table
  488.            // Note that we are doing this as double entries. Making
  489.            // sure that we keep both tables -identical- this is to
  490.            // make sure that we can end up with an 'identity palette'
  491.            // which means that both the colortable assigned to the DIB
  492.            // and the palette entries associated with the palette
  493.            // that is selected into the Device Context are identical.
  494.            for(Counter = 0; Counter < 10; Counter++) {
  495.           // copy the system colors into the DIB header
  496.           // WinG will do this in WinGRecommendDIBFormat,
  497.           // but it may have failed above so do it here anyway
  498.  
  499.           // The low end colors...
  500.           image.aColors[Counter].rgbRed =
  501.                 LogicalPalette.aEntries[Counter].peRed;
  502.           image.aColors[Counter].rgbGreen =
  503.                 LogicalPalette.aEntries[Counter].peGreen;
  504.           image.aColors[Counter].rgbBlue =
  505.                 LogicalPalette.aEntries[Counter].peBlue;
  506.           image.aColors[Counter].rgbReserved = 0;
  507.           LogicalPalette.aEntries[Counter].peFlags = 0;
  508.  
  509.           // And the high end colors...
  510.           image.aColors[Counter + 246].rgbRed =
  511.             LogicalPalette.aEntries[Counter + 246].peRed;
  512.           image.aColors[Counter + 246].rgbGreen =
  513.             LogicalPalette.aEntries[Counter + 246].peGreen;
  514.           image.aColors[Counter + 246].rgbBlue =
  515.                 LogicalPalette.aEntries[Counter + 246].peBlue;
  516.           image.aColors[Counter + 246].rgbReserved = 0;
  517.           LogicalPalette.aEntries[Counter + 246].peFlags = 0;
  518.           }
  519.  
  520.            // Now fill in all of the colors in the middle to reflect
  521.            // the colors that we are wanting.
  522.            for(Counter = 10;Counter < (10+16);Counter++) {
  523.           image.aColors[Counter].rgbRed =
  524.             LogicalPalette.aEntries[Counter].peRed =
  525.                 rgbvals[Counter-10][0];
  526.           image.aColors[Counter].rgbGreen =
  527.             LogicalPalette.aEntries[Counter].peGreen =
  528.                 rgbvals[Counter-10][1];
  529.           image.aColors[Counter].rgbBlue =
  530.                 LogicalPalette.aEntries[Counter].peBlue =
  531.                 rgbvals[Counter-10][2];
  532.           image.aColors[Counter].rgbReserved = 0;
  533.  
  534.           // In order for this to be an identity palette, it is
  535.           // important that we not only get this color, but that
  536.           // we get it in THIS location. Using PC_NOCOLLAPSE tells
  537.           // the system not to 'collapse' this entry to another
  538.           // palette entry that already has this color.
  539.           LogicalPalette.aEntries[Counter].peFlags = PC_NOCOLLAPSE;
  540.           }
  541.  
  542.            // The logical palette table is fully initialized.
  543.            // All we have to do now, is create it.
  544.            hpalApp = CreatePalette((LOGPALETTE far *)&LogicalPalette);
  545.  
  546.            //  Create a WinGDC and Bitmap, then select away
  547. #if defined (WIN32)
  548.            // Create a DC compatible with current screen
  549.            hdcImage = CreateCompatibleDC (NULL);
  550. #else
  551.            hdcImage = WinGCreateDC();
  552. #endif
  553.            image.bi.biWidth = X_CORD;
  554.            image.bi.biHeight = Y_CORD * Orientation;
  555.  
  556. #if defined (WIN32)
  557.         hbm = CreateDIBSection (hdcImage, (BITMAPINFO far *)&image.bi, DIB_PAL_COLORS, &image.lpvData, NULL, 0);
  558. #else
  559.         hbm = WinGCreateBitmap(hdcImage,(BITMAPINFO far *)&image.bi, &image.data.lpvData);
  560. #endif
  561.         // Make sure that 'biSizeImage' reflects the
  562.         // size of the bitmap data.
  563.         image.bi.biSizeImage = (image.bi.biWidth * image.bi.biHeight);
  564.         image.bi.biSizeImage *= Orientation;
  565.         //  Store the old hbitmap to select back in before deleting
  566.         gbmOldMonoBitmap = (HBITMAP)SelectObject(hdcImage, hbm);
  567.         PatBlt(hdcImage, 0,0,dxClient,dyClient, BLACKNESS);
  568.         }
  569.         break;
  570.  
  571.       case WM_COMMAND:
  572.      return AppCommand(hwnd, msg, wParam, lParam);
  573.  
  574.       case WM_PALETTECHANGED:
  575.      if ((HWND)wParam == hwnd) {
  576.         break;
  577.         }
  578.  
  579.      // fall through to WM_QUERYNEWPALETTE
  580.  
  581.     case WM_QUERYNEWPALETTE:
  582.        hdc = GetDC(hwnd);
  583.  
  584.        if (hpalApp) {
  585.           SelectPalette(hdc, hpalApp, FALSE);
  586.           }
  587.  
  588.        uMappedColors = RealizePalette(hdc);
  589.        ReleaseDC(hwnd,hdc);
  590.  
  591.        if (uMappedColors>0) {
  592.           InvalidateRect(hwnd,NULL,TRUE);
  593.           return TRUE;
  594.           }
  595.        else
  596.           {
  597.           return FALSE;
  598.           }
  599.        /* break; */
  600.  
  601.  
  602.       case WM_PAINT:
  603.  
  604.      if(NotPaused && bFlashOn)
  605.         do_flash(); // Spectrum specific
  606.  
  607.      // hack for flushing byte buffer
  608.      writebyte(0x4000, readbyte(0x4000) );
  609.  
  610.      // Update main window
  611.      hdc = BeginPaint(hwnd,&ps);
  612.      SelectPalette(hdc, hpalApp, FALSE);
  613.      RealizePalette(hdc);
  614.      AppPaint (hwnd,hdc);
  615.      EndPaint(hwnd,&ps);
  616.      return 0L;
  617.  
  618.       case WM_KEYDOWN:
  619.      /* map PC keys in the array that simulates the
  620.         Spectrum keyboard (key down)
  621.       */
  622.      switch(wParam)
  623.         {
  624.         case '1':      keybd_buff[3] |= ~0xFE; break;
  625.         case '2':      keybd_buff[3] |= ~0xFD; break;
  626.         case '3':      keybd_buff[3] |= ~0xFB; break;
  627.         case '4':      keybd_buff[3] |= ~0xF7; break;
  628.         case '5':      keybd_buff[3] |= ~0xEF; break;
  629.         case 'Q':      keybd_buff[2] |= ~0xFE; break;
  630.         case 'W':      keybd_buff[2] |= ~0xFD; break;
  631.         case 'E':      keybd_buff[2] |= ~0xFB; break;
  632.         case 'R':      keybd_buff[2] |= ~0xF7; break;
  633.         case 'T':      keybd_buff[2] |= ~0xEF; break;
  634.         case 'A':      keybd_buff[1] |= ~0xFE; break;
  635.         case 'S':      keybd_buff[1] |= ~0xFD; break;
  636.         case 'D':      keybd_buff[1] |= ~0xFB; break;
  637.         case 'F':      keybd_buff[1] |= ~0xF7; break;
  638.         case 'G':      keybd_buff[1] |= ~0xEF; break;
  639.         case VK_SHIFT:
  640.                if(((lParam >> 16) & 0x7F) == 0x2A)
  641.                   keybd_buff[0] |= ~0xFE; /* CAPS SHIFT */
  642.                else
  643.                   keybd_buff[7] |= ~0xFD; /* SYMBOL SHIFT */
  644.                break;
  645.         case 'Z':  keybd_buff[0] |= ~0xFD; break;
  646.         case 'X':  keybd_buff[0] |= ~0xFB; break;
  647.         case 'C':  keybd_buff[0] |= ~0xF7; break;
  648.         case VK_DIVIDE:
  649.                keybd_buff[7] |= ~0xFD;
  650.         case 'V':  keybd_buff[0] |= ~0xEF; break;
  651.         case '0':  keybd_buff[4] |= ~0xFE; break;
  652.         case '9':  keybd_buff[4] |= ~0xFD; break;
  653.         case '8':  keybd_buff[4] |= ~0xFB; break;
  654.         case '7':  keybd_buff[4] |= ~0xF7; break;
  655.         case '6':  keybd_buff[4] |= ~0xEF; break;
  656.         case 'P':  keybd_buff[5] |= ~0xFE; break;
  657.         case 'O':  keybd_buff[5] |= ~0xFD; break;
  658.         case 'I':  keybd_buff[5] |= ~0xFB; break;
  659.         case 'U':  keybd_buff[5] |= ~0xF7; break;
  660.         case 'Y':  keybd_buff[5] |= ~0xEF; break;
  661.         case VK_RETURN: keybd_buff[6] |= ~0xFE; break;
  662.         case 'L':  keybd_buff[6] |= ~0xFD; break;
  663.         case VK_ADD:
  664.                keybd_buff[7] |= ~0xFD;
  665.         case 'K':  keybd_buff[6] |= ~0xFB; break;
  666.         case VK_SUBTRACT:
  667.                keybd_buff[7] |= ~0xFD;
  668.         case 'J':  keybd_buff[6] |= ~0xF7; break;
  669.         case 'H':  keybd_buff[6] |= ~0xEF; break;
  670.  
  671.         case VK_ESCAPE:
  672.                keybd_buff[0] |= ~0xFE; /* CAPS SHIFT */
  673.  
  674.         case VK_SPACE:      keybd_buff[7] |= ~0xFE; break;
  675.         case 'M':  keybd_buff[7] |= ~0xFB; break;
  676.         case 'N':  keybd_buff[7] |= ~0xF7; break;
  677.         case VK_MULTIPLY:
  678.                keybd_buff[7] |= ~0xFD;
  679.         case 'B':  keybd_buff[7] |= ~0xEF; break;
  680.  
  681.  
  682.         /* Special keys */
  683.         case VK_TAB: keybd_buff[0] |= ~0xFE;
  684.              keybd_buff[7] |= ~0xFD;
  685.              break;
  686.  
  687.         case VK_BACK: keybd_buff[0] |= ~0xFE; /* CAPS SHIFT */
  688.               keybd_buff[4] |= ~0xFE;
  689.               break;
  690.  
  691.         /* kempston joystick */
  692.         case VK_LEFT:  joystick |= 2; break;
  693.         case VK_RIGHT: joystick |= 1; break;
  694.         case VK_UP:    joystick |= 8; break;
  695.         case VK_DOWN:  joystick |= 4; break;
  696.         case VK_CONTROL: joystick |= 16; break;
  697.         /* Sinclair joystick */
  698.         case VK_NUMPAD5:
  699.         case VK_NUMPAD0: keybd_buff[0] |= ~0xFE;
  700.                  keybd_buff[4] |= ~0xFE; /* 0 - fire  */
  701.                  break;
  702.         case VK_NUMPAD4: keybd_buff[0] |= ~0xFE;
  703.                  keybd_buff[3] |= ~0xEF; /* 5 - left  */
  704.                  break;
  705.         case VK_NUMPAD6: keybd_buff[0] |= ~0xFE;
  706.                  keybd_buff[4] |= ~0xFB; /* 8 - right */
  707.                  break;
  708.         case VK_NUMPAD8: keybd_buff[0] |= ~0xFE;
  709.                  keybd_buff[4] |= ~0xF7; /* 7 - up    */
  710.                  break;
  711.         case VK_NUMPAD2: keybd_buff[0] |= ~0xFE;
  712.                  keybd_buff[4] |= ~0xEF; /* 6 - down  */
  713.                  break;
  714.         }
  715.         return 0L;
  716.  
  717.   case WM_KEYUP:
  718.         /* map PC keys in the array that simulates the
  719.           Spectrum keyboard (key up)
  720.          */
  721.         switch(wParam)
  722.         {
  723.         case '1': keybd_buff[3] &= 0xFE; break;
  724.         case '2': keybd_buff[3] &= 0xFD; break;
  725.         case '3': keybd_buff[3] &= 0xFB; break;
  726.         case '4': keybd_buff[3] &= 0xF7; break;
  727.         case '5': keybd_buff[3] &= 0xEF; break;
  728.         case 'Q': keybd_buff[2] &= 0xFE; break;
  729.         case 'W': keybd_buff[2] &= 0xFD; break;
  730.         case 'E': keybd_buff[2] &= 0xFB; break;
  731.         case 'R': keybd_buff[2] &= 0xF7; break;
  732.         case 'T': keybd_buff[2] &= 0xEF; break;
  733.         case 'A': keybd_buff[1] &= 0xFE; break;
  734.         case 'S': keybd_buff[1] &= 0xFD; break;
  735.         case 'D': keybd_buff[1] &= 0xFB; break;
  736.         case 'F': keybd_buff[1] &= 0xF7; break;
  737.         case 'G': keybd_buff[1] &= 0xEF; break;
  738.         case VK_SHIFT:
  739.           if(((lParam >> 16) & 0x7F) == 0x2A)
  740.              keybd_buff[0] &= 0xFE; /* CAPS SHIFT */
  741.           else
  742.              keybd_buff[7] &= 0xFD; /* SYMBOL SHIFT */
  743.           break;
  744.         case 'Z': keybd_buff[0] &= 0xFD; break;
  745.         case 'X': keybd_buff[0] &= 0xFB; break;
  746.         case 'C': keybd_buff[0] &= 0xF7; break;
  747.         case VK_DIVIDE:
  748.               keybd_buff[7] &= 0xFD;
  749.         case 'V': keybd_buff[0] &= 0xEF; break;
  750.         case '0': keybd_buff[4] &= 0xFE; break;
  751.         case '9': keybd_buff[4] &= 0xFD; break;
  752.         case '8': keybd_buff[4] &= 0xFB; break;
  753.         case '7': keybd_buff[4] &= 0xF7; break;
  754.         case '6': keybd_buff[4] &= 0xEF; break;
  755.         case 'P': keybd_buff[5] &= 0xFE; break;
  756.         case 'O': keybd_buff[5] &= 0xFD; break;
  757.         case 'I': keybd_buff[5] &= 0xFB; break;
  758.         case 'U': keybd_buff[5] &= 0xF7; break;
  759.         case 'Y': keybd_buff[5] &= 0xEF; break;
  760.         case VK_RETURN:keybd_buff[6] &= 0xFE; break;
  761.         case 'L': keybd_buff[6] &= 0xFD; break;
  762.         case VK_ADD:
  763.               keybd_buff[7] &= 0xFD;
  764.         case 'K': keybd_buff[6] &= 0xFB; break;
  765.         case VK_SUBTRACT:
  766.               keybd_buff[7] &= 0xFD;
  767.         case 'J': keybd_buff[6] &= 0xF7; break;
  768.         case 'H': keybd_buff[6] &= 0xEF; break;
  769.  
  770.         case VK_ESCAPE:
  771.               keybd_buff[0] &= 0xFE; /* CAPS SHIFT */
  772.  
  773.         case VK_SPACE:      keybd_buff[7] &= 0xFE; break;
  774.         case 'M': keybd_buff[7] &= 0xFB; break;
  775.         case 'N': keybd_buff[7] &= 0xF7; break;
  776.         case VK_MULTIPLY:
  777.               keybd_buff[7] &= 0xFD;
  778.         case 'B': keybd_buff[7] &= 0xEF; break;
  779.         case VK_TAB:
  780.           keybd_buff[0] &= 0xFE;
  781.           keybd_buff[7] &= 0xFD;
  782.           break;
  783.  
  784.         case VK_BACK: keybd_buff[0] &= 0xFE; /* CAPS SHIFT */
  785.               keybd_buff[4] &= 0xFE;
  786.               break;
  787.  
  788.         /* kempston joystick */
  789.         case VK_LEFT:  joystick &= ~2; break;
  790.         case VK_RIGHT: joystick &= ~1; break;
  791.         case VK_UP:    joystick &= ~8; break;
  792.         case VK_DOWN:  joystick &= ~4; break;
  793.         case VK_CONTROL: joystick &= ~16; break;
  794.  
  795.          /* Sinclair joystick */
  796.             case VK_NUMPAD5:
  797.         case VK_NUMPAD0: keybd_buff[0] &= 0xFE;
  798.                  keybd_buff[4] &= 0xFE; /* 0 - fire  */
  799.                  break;
  800.         case VK_NUMPAD4: keybd_buff[0] &= 0xFE;
  801.                  keybd_buff[3] &= 0xEF; /* 5 - left  */
  802.                  break;
  803.         case VK_NUMPAD6: keybd_buff[0] &= 0xFE;
  804.                  keybd_buff[4] &= 0xFB; /* 8 - right */
  805.                  break;
  806.         case VK_NUMPAD8: keybd_buff[0] &= 0xFE;
  807.                  keybd_buff[4] &= 0xF7; /* 7 - up    */
  808.                  break;
  809.         case VK_NUMPAD2: keybd_buff[0] &= 0xFE;
  810.                  keybd_buff[4] &= 0xEF; /* 6 - down  */
  811.                  break;
  812.  
  813.         /* shortcut key for saveas and load a' la Z80 */
  814.  
  815.         case VK_F2:
  816.               PostMessage(hwnd, WM_COMMAND, IDM_SAVEAS, 0L);
  817.               break;
  818.  
  819.         case VK_F3:
  820.               PostMessage(hwnd, WM_COMMAND, IDM_OPEN, 0L);
  821.               break;
  822.  
  823.         /* for PAUSE */
  824.         case VK_F4:
  825.               PostMessage(hwnd, WM_COMMAND, IDM_PAUSE, 0L);
  826.               break;
  827.  
  828.         /* for RESET */
  829.         case VK_F5:
  830.               PostMessage(hwnd, WM_COMMAND, IDM_RESET, 0L);
  831.               break;
  832.  
  833.         }
  834.         return 0L;
  835.  
  836.     case WM_DROPFILES:      // handles drag-and-drop messages (files)
  837.        {
  838.        HANDLE Handle = (HANDLE)wParam;
  839.        int nFileLength;    // length of file name
  840.        char *pszFileName;  // name of file
  841.  
  842.        nFileLength  = DragQueryFile( Handle , 0 , NULL, 0 );
  843.        pszFileName = (char*)malloc(nFileLength + 1);
  844.        DragQueryFile( Handle , 0, pszFileName, nFileLength + 1 );
  845.        DragFinish( Handle );      // signal reception of message
  846.        open_sna(pszFileName);     // open file
  847.        free((char *)pszFileName); // free buffer
  848.  
  849.        // handle special case if paused
  850.        if(!NotPaused)
  851.            {
  852.           NotPaused = 1;
  853.           PostMessage(hwnd, WM_COMMAND, IDM_PAUSE, 0L);
  854.            }
  855.  
  856.        return 0L;
  857.        }
  858.  
  859.      case WM_CLOSE:                      // finish application    
  860.        DragAcceptFiles( hwnd , FALSE );  // close drag-and-drop
  861.        /*KillTimer (hwnd, ID_TIMER) ;*/
  862. #if defined(WINDOWS_SOUND)
  863.        // Close wave driver
  864.        CloseSnd();
  865. #endif
  866.        DestroyWindow(hwnd);
  867.        PostQuitMessage(0);
  868.        break;
  869.  
  870.      }
  871.  
  872.      // pass messages to windows default handler
  873.      return DefWindowProc(hwnd,msg,wParam,lParam);
  874. }
  875.  
  876.  
  877. /*----------------------------------------------------------------------------*\
  878. |   AppPaint(hwnd, hdc)                                                        |
  879. |                                                                              |
  880. |   Description:                                                               |
  881. |       The paint function.                                                    |                       
  882. |                                                                              |
  883. |   Arguments:                                                                 |
  884. |       hwnd             window painting into                                  |
  885. |       hdc              display context to paint to                           |
  886. |                                                                              |
  887. |   Returns:                                                                   |
  888. |       nothing                                                                |
  889. |                                                                              |
  890. \*----------------------------------------------------------------------------*/
  891. BOOL AppPaint (HWND hwnd, HDC hdc)
  892. {
  893.    DWORD l;
  894.    RECT rc;
  895. #if defined (WIN32)
  896.    BYTE *lpData;
  897. #else
  898.    BYTE __huge *lpData;
  899. #endif
  900.  
  901.    GetClientRect (hwnd, &rc); // Get the size of the window on the screen
  902.  
  903.    // And slam the image onto the screen:
  904. #if defined (WIN32)
  905.    // ************************
  906.    BitBlt(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top, hdcImage, 0, 0, SRCCOPY);
  907.    // ************************
  908. #else
  909.    WinGStretchBlt(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
  910.         hdcImage, 0, 0, X_CORD, Y_CORD);
  911. #endif
  912.    WindowDirty = 0;
  913.    return TRUE;
  914. }
  915.  
  916. /*----------------------------------------------------------------------------*\
  917. |   pixel_host()                                                               |
  918. |                                                                              |
  919. |   Description:                                                               |
  920. |       Draw a point of (x,y) coord, of colour [colour] in the WinG bitmap     |
  921. |                                                                              |
  922. \*----------------------------------------------------------------------------*/
  923. void pixel_host(unsigned short x, unsigned short y, UCHAR colour)
  924. {
  925.   // The data in our bitmap image is in 8bit chunks. Each element is an
  926.   // index value to the colortable that is associated with the bitmap,
  927.   // which, since we took pains to create an 'identity palette', is also
  928.   // the same as the palette currently selected into this device context.
  929.  
  930. #if defined (WIN32)
  931.    *((BYTE *)image.data.lpIndex+((y*X_CORD)+x)) = colour+10;
  932. #else
  933.    *((BYTE __huge *)image.data.lpIndex+((y*X_CORD)+x)) = colour+10;
  934. #endif
  935. }
  936.  
  937.  
  938. /*----------------------------------------------------------------------------*\
  939. |   AppCommand(hwnd, msg, wParam, lParam )                                     |
  940. |                                                                              |
  941. |   Description:                                                               |
  942. |       handles WM_COMMAND messages for the main window (hwndApp)              |
  943. |       of the parent window's messages.                                       |
  944. |                                                                              |
  945. \*----------------------------------------------------------------------------*/
  946. LONG AppCommand (HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  947. {
  948.    FARPROC fpAbout;
  949.    int idItem;
  950.    //HWND hwndCtl;
  951.    WORD wNotifyCode;
  952.  
  953. #if defined(WIN32)
  954.    idItem = LOWORD(wParam);         // WIN32: control or menu item identifier
  955.    hwndCtl = (HWND)lParam;          // WIN32: handle of control
  956.    //wNotifyCode = HIWORD(wParam);    // WIN32: notification message
  957. #else
  958.    idItem = wParam;                 // WIN16: control or menu item identifier
  959.    //hwndCtl = (HWND) LOWORD(lParam); // WIN16: handle of control
  960.    //wNotifyCode = HIWORD(lParam);    // WIN16: notification message
  961. #endif
  962.  
  963.    switch(idItem) {
  964.       HMENU hmenu;
  965.       BOOL  menu_state;
  966.       static char CaptionCopy[100];
  967.  
  968.       case IDM_OPEN:
  969.      open_menu(hwndApp);
  970.  
  971.      // handle special case if paused
  972.      if(!NotPaused)
  973.          {
  974.         NotPaused = 1;
  975.         PostMessage(hwnd, WM_COMMAND, IDM_PAUSE, 0L);
  976.      }
  977.  
  978.      InvalidateRect(hwnd,NULL,FALSE);
  979.      break;
  980.  
  981.       case IDM_SAVE:
  982.      save_snap();
  983.      break;
  984.  
  985.       case IDM_SAVEAS:
  986.      open_menu_save(hwndApp);
  987.      InvalidateRect(hwnd,NULL,FALSE);
  988.      break;
  989.  
  990.       case IDM_ABOUT:
  991.      fpAbout = MakeProcInstance ((FARPROC)AppAbout, hInstApp);
  992.      DialogBox(hInstApp, szAppName, hwnd, (DLGPROC)fpAbout);
  993.      InvalidateRect(hwnd,NULL,FALSE);
  994.      FreeProcInstance (fpAbout);
  995.      break;
  996.  
  997.       case IDM_FILERELOAD:
  998.      reload_snap();
  999.      break;
  1000.  
  1001.       case IDM_EXIT:
  1002.      PostMessage(hwnd,WM_CLOSE,0,0L);
  1003.      break;
  1004.  
  1005.      
  1006.       case IDM_PAUSE:
  1007.      {
  1008.         NotPaused ^= 1;
  1009.         if(!NotPaused)
  1010.         {
  1011.            // Just force a redraw
  1012.            InvalidateRect (hwndApp, NULL, FALSE);
  1013.  
  1014.            GetWindowText(hwnd, CaptionCopy, 99);
  1015.            SetWindowText(hwnd, "Spectrum Emulator [Paused]" );
  1016.         }
  1017.         else
  1018.            SetWindowText(hwnd, CaptionCopy);
  1019.      }
  1020.      break;
  1021.  
  1022.       case IDM_POKE:
  1023.       {
  1024.      FARPROC lpProcedure;
  1025.      HINSTANCE hInst;
  1026.  
  1027.      hInst=(HINSTANCE)GetWindowWord(hwnd,GWW_HINSTANCE);
  1028.      lpProcedure=MakeProcInstance((FARPROC)DoPoke,hInst);
  1029.      DialogBox(hInst,(LPCSTR)MAKEINTRESOURCE(SP_POKE),
  1030.              hwnd,(DLGPROC)lpProcedure);
  1031.      FreeProcInstance(lpProcedure);
  1032.      InvalidateRect(hwnd,NULL,FALSE);
  1033.      break;
  1034.       }
  1035.  
  1036.       case IDM_SPEED:
  1037.       {
  1038.      FARPROC lpProcedure;
  1039.      HINSTANCE hInst;
  1040.  
  1041.      hInst=(HINSTANCE)GetWindowWord(hwnd,GWW_HINSTANCE);
  1042.      lpProcedure=MakeProcInstance((FARPROC)DoSpeed,hInst);
  1043.      DialogBox(hInst,(LPCSTR)MAKEINTRESOURCE(SP_SPEED),
  1044.              hwnd,(DLGPROC)lpProcedure);
  1045.      FreeProcInstance(lpProcedure);
  1046.      InvalidateRect(hwnd,NULL,FALSE);
  1047.      break;
  1048.       }
  1049.  
  1050.       case IDM_RESET:
  1051.      do_reset();
  1052.      if(NotPaused)
  1053.      {
  1054.         SetWindowText(hwnd, "Spectrum Emulator" );
  1055.      }
  1056.      else
  1057.         strcpy(CaptionCopy, "Spectrum Emulator");
  1058.      break;
  1059.  
  1060.       case IDM_NMI:
  1061.      do_nmi_int();
  1062.      break;
  1063.  
  1064.       case IDM_SOUND:
  1065.      bSoundOn ^= 1;
  1066.      hmenu = GetMenu(hwnd);
  1067.      CheckMenuItem(hmenu, IDM_SOUND, bSoundOn? MF_CHECKED :MF_UNCHECKED);
  1068.      break;
  1069.  
  1070.       case IDM_COLOUR:
  1071.      bFlashOn ^= 1;
  1072.      hmenu = GetMenu(hwnd);
  1073.      CheckMenuItem(hmenu, IDM_COLOUR,
  1074.         bFlashOn? MF_CHECKED : MF_UNCHECKED);
  1075.      break;
  1076.  
  1077.       case IDM_MODEL3:
  1078.      bModel3 ^= 1;
  1079.      hmenu = GetMenu(hwnd);
  1080.      CheckMenuItem(hmenu, IDM_MODEL3,
  1081.         bModel3? MF_CHECKED : MF_UNCHECKED);
  1082.      break;
  1083.  
  1084.       case IDM_SIZE1:
  1085.      Scale = 1;
  1086.      ResizeWindow();
  1087.      break;
  1088.  
  1089.       case IDM_SIZE2:
  1090.      Scale = 2;
  1091.      ResizeWindow();
  1092.      break;
  1093.  
  1094.       case IDM_SIZE3:
  1095.      Scale = 3;
  1096.      ResizeWindow();
  1097.      break;
  1098.  
  1099.       case IDM_SIZE4:
  1100.      Scale = 4;
  1101.      ResizeWindow();
  1102.      break;
  1103.  
  1104.       case IDM_SAVEOPTIONS: 
  1105.      {
  1106.         char szBuf[260];
  1107.  
  1108.         GetWindowsDirectory((LPSTR)szBuf, 259);
  1109.         strcat(szBuf, "\\wspecem.ini");
  1110.  
  1111.         save_sna((LPSTR)szBuf);
  1112.      }
  1113.      break;
  1114.       }
  1115.    return 0L; // returning '0' means we processed this message.
  1116. }
  1117.  
  1118.  
  1119. /*----------------------------------------------------------------------------*\
  1120. |   AppAbout( hDlg, uiMessage, wParam, lParam )                                |
  1121. |                                                                              |
  1122. |   Description:                                                               |
  1123. |       This function handles messages belonging to the "About" dialog box.    |
  1124. |       The only message that it looks for is WM_COMMAND, indicating the use   |
  1125. |       has pressed the "OK" button.  When this happens, it takes down         |
  1126. |       the dialog box.                                                        |
  1127. |                                                                              |
  1128. |   Arguments:                                                                 |
  1129. |       hDlg            window handle of about dialog window                   |
  1130. |       uiMessage       message number                                         |
  1131. |       wParam          message-dependent                                      |
  1132. |       lParam          message-dependent                                      |
  1133. |                                                                              |
  1134. |   Returns:                                                                   |
  1135. |       TRUE if message has been processed, else FALSE                         |
  1136. |                                                                              |
  1137. \*----------------------------------------------------------------------------*/
  1138. BOOL FAR PASCAL AppAbout(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  1139. {
  1140.    int idItem;
  1141.    //HWND hwndCtl;
  1142.    //WORD wNotifyCode;
  1143.  
  1144.    switch (msg) {
  1145.       case WM_INITDIALOG:
  1146.      // Here is where you could move the dialog around, change
  1147.      // some of the text that is going to be displayed, or other
  1148.      // things that you want to have happen right before the
  1149.      // dialog is brought up.
  1150.      return TRUE;
  1151.  
  1152.       case WM_COMMAND:
  1153.      // A 'command' has been recieved by the dialog. Very few are
  1154.      // actually possible in this dialog. Usually just the 'OK' button
  1155. #if defined(WIN32)
  1156.      idItem = LOWORD(wParam);         // WIN32: control or menu item identifier
  1157.      //hwndCtl = (HWND)lParam;          // WIN32: handle of control
  1158.      wNotifyCode = HIWORD(wParam);    // WIN32: notification message
  1159. #else
  1160.      idItem = wParam;                 // WIN16: control or menu item identifier
  1161.      //hwndCtl = (HWND) LOWORD(lParam); // WIN16: handle of control
  1162.      //wNotifyCode = HIWORD(lParam);    // WIN16: notification message
  1163. #endif
  1164.      if (idItem == IDOK) {
  1165.         EndDialog(hwnd,TRUE);
  1166.         }
  1167.      break;
  1168.  
  1169.      }
  1170.     return FALSE;
  1171. }
  1172.  
  1173.  
  1174.  
  1175. /*----------------------------------------------------------------------------*\
  1176. |   AppExit()                                                                  |
  1177. |                                                                              |
  1178. |   Description:                                                               |
  1179. |       app is just about to exit, cleanup                                     |
  1180. |                                                                              |
  1181. \*----------------------------------------------------------------------------*/
  1182. void AppExit()
  1183. {
  1184.    // Clean up after ourselves...
  1185.  
  1186.    if (hdcImage) {
  1187.       // Remove our Device Context that we got from WinG:
  1188.       HBITMAP hbm;
  1189.  
  1190.       // Its not nice to delete a bitmap that is selected into a Device
  1191.       // Context, so lets swap in the original bitmap, which will return
  1192.       // to us our custom bitmap. You -did- remember to save the original
  1193.       // bitmap didn't you?
  1194.       hbm = (HBITMAP)SelectObject(hdcImage, gbmOldMonoBitmap);
  1195.  
  1196.       // Now we can delete the bitmap...
  1197.       DeleteObject(hbm);
  1198.  
  1199.       // ...and the Device Context
  1200.       DeleteDC(hdcImage);
  1201.       }
  1202.  
  1203.       if(hpalApp) {
  1204.      // And finally remove our Palette:
  1205.      DeleteObject(hpalApp);
  1206.      }
  1207.       Close_Z80Emu();
  1208. }
  1209.  
  1210.  
  1211.  
  1212.  
  1213. // Should be at snasave.c, but it needs to much windows specific info
  1214. int save_pcx(HFILE hfp)
  1215. {
  1216.    long i;
  1217.    UCHAR __huge * p;
  1218.    UCHAR byte;
  1219.    UCHAR f_time = 1;
  1220.  
  1221.    putbyte(10, hfp); /* Manufacturer == Paintbrush PCX */
  1222.    putbyte(5, hfp);  /* 3.0 with palette info          */
  1223.    putbyte(1, hfp);  /* .PCX run-length encoding       */
  1224.  
  1225.    putbyte(4, hfp);  /* bits per pixel */
  1226.    put2(0, hfp);     /* COORDS */
  1227.    put2(0, hfp);
  1228.    put2(X_CORD-1, hfp);
  1229.    put2(Y_CORD-1, hfp);
  1230.    put2(X_CORD, hfp); /* Horizontal resolution */
  1231.    put2(Y_CORD, hfp); /* Vertical resolution */
  1232.  
  1233.    /* Save Pallete as RGB, 16 colours */
  1234.    for(i = 0 ; i < 16 ; i++)
  1235.    {
  1236.       putbyte(rgbvals[i][0], hfp);
  1237.       putbyte(rgbvals[i][1], hfp);
  1238.       putbyte(rgbvals[i][2], hfp);
  1239.    }
  1240.    putbyte(0, hfp);
  1241.    putbyte(1, hfp); /* number of colour planes */
  1242.    put2(X_CORD/2, hfp); /* bytes per line */
  1243.    for(i = 0 ; i < 60 ; i++)
  1244.       putbyte(0, hfp);
  1245.  
  1246.    /* Now save image */
  1247.    p = (UCHAR __huge *)image.data.lpIndex;
  1248.    i = ((long)X_CORD * (long)Y_CORD)/2;
  1249.  
  1250.    while(i)
  1251.    {
  1252.       byte = ((*p++)-10 << 4);
  1253.       byte = byte | ((*p++)-10);
  1254.       if(byte >= 0xC0)
  1255.      putbyte(0xC1, hfp);
  1256.       putbyte(byte, hfp);
  1257.       i--;
  1258.    }
  1259.    return 0;
  1260. }
  1261.  
  1262. /* buggy function --- if it's corrected we'll save .BMP too
  1263. int save_dib(HFILE hfp)
  1264. {
  1265.    long i;
  1266.  
  1267.    UCHAR __huge * p;
  1268.    BITMAPFILEHEADER i_block;
  1269.    */
  1270.    // I suspected the problem is between this line
  1271.    /*
  1272.    i_block.bfType = 0x4d42; 
  1273.    i_block.bfSize = (long)X_CORD * (long)Y_CORD+sizeof(BITMAPINFOHEADER)+
  1274.             sizeof(RGBQUAD) * 256 + sizeof(BITMAPFILEHEADER);
  1275.    i_block.bfReserved1 = 0;
  1276.    i_block.bfReserved2 = 0;
  1277.    i_block.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(RGBQUAD)*256
  1278.                + image.bi.biSize;
  1279.     */
  1280.    // and this one. Someone will give it a try?
  1281.  
  1282.    /*p = (UCHAR __huge *)&i_block;
  1283.    i=sizeof(BITMAPFILEHEADER);
  1284.    while(i--)
  1285.       putbyte(*p++, hfp);
  1286.  
  1287.    p = (UCHAR __huge *)&image.bi;
  1288.    i=sizeof(BITMAPINFOHEADER);
  1289.    while(i--)
  1290.       putbyte(*p++, hfp);
  1291.  
  1292.    p = (UCHAR __huge *)image.aColors;
  1293.    i=sizeof(RGBQUAD)*256;
  1294.    while(i --)
  1295.       putbyte(*p++, hfp);
  1296.  
  1297.    p = (UCHAR __huge *)image.data.lpIndex;
  1298.    i = (long)X_CORD * (long)Y_CORD;
  1299.    while(i--)
  1300.       putbyte(*p++, hfp);
  1301.  
  1302.  
  1303.    return 0;
  1304. }
  1305. */
  1306. /* EOF: WSpecem.c */
  1307.