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