2013年3月22日星期五

windows SDK模拟游戏钢琴的实现

最近想做一个模拟钢琴的小软件,想做个既有键盘接口又有鼠标接口的小软件。所涉及到的知识点如下:
  1.有关键盘的知识
  2.有关鼠标的知识
  3.GDI的知识
  4.媒体播放函数的有关知识


  因为这几天也正好在看这些内容,所以理论结合实际是最好的学习方式
 
首先要找钢琴音阶,但是上网找了一圈也没有发现,最后在4399里面找到一个差不多类型的模拟钢琴游戏,而且音色不错,索性用Adobe Audition的录音功能将每个音阶都录下来做一些编辑,自己制作了20来个音阶,用mp3格式保存。
然后用的是mcisendstring函数实现mp3格式音乐的播放。


第一步首先做键盘接口,其实这一步还是比较简单的,在窗口过程里面处理对应的虚拟键码的消息就行了,这里遇到了一个小问题,找不到 <,  和  >.  这两个按键对应的虚拟键码了,找了一下虚拟键码表上面好像也没有写啊?先暂时搁下
成果做出来以后,发现一个比较严重的问题,就是使用mcisendstring这个宏的时候,不能同时打开某个音乐文件,这样比如我的la这个音阶有2秒的话,必须要等到2秒结束以后才能再次播放,这样显然影响了连续的效果,目前也没有什么好的解决方案。


第二步就要涉及到GDI和鼠标接口了,这一部分正在看,等到成品做出来以后在附上源码吧。


昨天晚上做梦的时候突然想到怎么实现可以几乎同时按一个键发出声音了,话说梦真是个神奇的东西啊。
既然不能同时打开同一个音乐文件,那么我在每次打开前关闭这个音乐文件不就实现这个效果了吗?想到了确实觉得挺简单的,但是昨天怎么就没想到呢?呵呵,下面先附上我键盘接口的代码:


  1. /*------------------------------------------------------------ 
  2.    a piano program 
  3.   ------------------------------------------------------------*/  
  4.   
  5. #include <windows.h>  
  6. #include <mmsystem.h>  
  7.   
  8. #pragma comment(lib, "WINMM.LIB")  
  9.   
  10. LRESULT CALLBACK WndProc (HWNDUINTWPARAMLPARAM) ;  
  11.   
  12. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,  
  13.                     PSTR szCmdLine, int iCmdShow)  
  14. {  
  15.      static TCHAR szAppName[] = TEXT ("HelloWin") ;  
  16.      HWND         hwnd ;  
  17.      MSG          msg ;  
  18.      WNDCLASS     wndclass ;  
  19.        
  20.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;  
  21.      wndclass.lpfnWndProc   = WndProc ;  
  22.      wndclass.cbClsExtra    = 0 ;  
  23.      wndclass.cbWndExtra    = 0 ;  
  24.      wndclass.hInstance     = hInstance ;  
  25.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;  
  26.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;  
  27.      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;  
  28.      wndclass.lpszMenuName  = NULL ;  
  29.      wndclass.lpszClassName = szAppName ;  
  30.   
  31.      if (!RegisterClass (&wndclass))  
  32.      {  
  33.           MessageBox (NULL, TEXT ("This program requires Windows NT!"),  
  34.                       szAppName, MB_ICONERROR) ;  
  35.           return 0 ;  
  36.      }  
  37.        
  38.      hwnd = CreateWindow (szAppName,                  // window class name  
  39.                           TEXT ("The Hello Program"), // window caption  
  40.                           WS_OVERLAPPEDWINDOW,        // window style  
  41.                           CW_USEDEFAULT,              // initial x position  
  42.                           CW_USEDEFAULT,              // initial y position  
  43.                           CW_USEDEFAULT,              // initial x size  
  44.                           CW_USEDEFAULT,              // initial y size  
  45.                           NULL,                       // parent window handle  
  46.                           NULL,                       // window menu handle  
  47.                           hInstance,                  // program instance handle  
  48.                           NULL) ;                     // creation parameters  
  49.        
  50.      ShowWindow (hwnd, iCmdShow) ;  
  51.      UpdateWindow (hwnd) ;  
  52.        
  53.      while (GetMessage (&msg, NULL, 0, 0))  
  54.      {  
  55.           TranslateMessage (&msg) ;  
  56.           DispatchMessage (&msg) ;  
  57.      }  
  58.      return msg.wParam ;  
  59. }  
  60.   
  61. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  62. {  
  63.       
  64.      HDC         hdc;  
  65.      PAINTSTRUCT ps ;  
  66.      RECT        rect;  
  67.       
  68.      switch (message)  
  69.      {  
  70.      case WM_CREATE:  
  71.             
  72.           return 0 ;  
  73.       
  74.      case WM_PAINT:  
  75.           
  76.           hdc = BeginPaint (hwnd, &ps);    
  77.           GetClientRect (hwnd, &rect);  
  78.           DrawText (hdc, TEXT ("an intersting piano game^_^  just use keyboard" ), -1, &rect,  
  79.                     DT_SINGLELINE | DT_CENTER | DT_VCENTER);  
  80.             
  81.           EndPaint (hwnd, &ps) ;  
  82.           return 0 ;  
  83.      case WM_KEYDOWN:  
  84.          switch(wParam)  
  85.          {  
  86.          case 0x31:  
  87.              mciSendString(TEXT("close c://1.mp3"), NULL, 0, NULL);  
  88.              mciSendString(TEXT("play c://1.mp3"), NULL, 0, NULL);       //0-9键盘接口  
  89.              break;  
  90.          case 0x32:  
  91.              mciSendString(TEXT("close c://2.mp3"), NULL, 0, NULL);  
  92.              mciSendString(TEXT("play c://2.mp3"), NULL, 0, NULL);  
  93.              break;  
  94.          case 0x33:  
  95.              mciSendString(TEXT("close c://3.mp3"), NULL, 0, NULL);  
  96.             mciSendString(TEXT("play c://3.mp3"), NULL, 0, NULL);  
  97.              break;  
  98.          case 0x34:  
  99.              mciSendString(TEXT("close c://4.mp3"), NULL, 0, NULL);  
  100.              mciSendString(TEXT("play c://4.mp3"), NULL, 0, NULL);  
  101.              break;  
  102.          case 0x35:  
  103.              mciSendString(TEXT("close c://5.mp3"), NULL, 0, NULL);  
  104.              mciSendString(TEXT("play c://5.mp3"), NULL, 0, NULL);  
  105.              break;  
  106.          case 0x36:  
  107.              mciSendString(TEXT("close c://6.mp3"), NULL, 0, NULL);  
  108.              mciSendString(TEXT("play c://6.mp3"), NULL, 0, NULL);  
  109.              break;  
  110.          case 0x37:  
  111.              mciSendString(TEXT("close c://7.mp3"), NULL, 0, NULL);  
  112.              mciSendString(TEXT("play c://7.mp3"), NULL, 0, NULL);  
  113.              break;  
  114.          case 0x38:  
  115.              mciSendString(TEXT("close c://8.mp3"), NULL, 0, NULL);  
  116.              mciSendString(TEXT("play c://8.mp3"), NULL, 0, NULL);  
  117.              break;  
  118.          case 0x39:  
  119.              mciSendString(TEXT("close c://9.mp3"), NULL, 0, NULL);  
  120.              mciSendString(TEXT("play c://9.mp3"), NULL, 0, NULL);  
  121.              break;  
  122.          case 0x30:  
  123.              mciSendString(TEXT("close c://10.mp3"), NULL, 0, NULL);  
  124.              mciSendString(TEXT("play c://10.mp3"), NULL, 0, NULL);  
  125.              break;  
  126.   
  127.          case 65:                                                                                                //字母键盘接口  
  128.              mciSendString(TEXT("close c://1.mp3"), NULL, 0, NULL);  
  129.              mciSendString(TEXT("play c://1.mp3"), NULL, 0, NULL);  
  130.              break;  
  131.          case 90:  
  132.              mciSendString(TEXT("close c://2.mp3"), NULL, 0, NULL);  
  133.              mciSendString(TEXT("play c://2.mp3"), NULL, 0, NULL);  
  134.              break;  
  135.          case 83:  
  136.              mciSendString(TEXT("close c://3.mp3"), NULL, 0, NULL);  
  137.              mciSendString(TEXT("play c://3.mp3"), NULL, 0, NULL);  
  138.              break;  
  139.          case 88:  
  140.              mciSendString(TEXT("close c://4.mp3"), NULL, 0, NULL);  
  141.              mciSendString(TEXT("play c://4.mp3"), NULL, 0, NULL);  
  142.              break;  
  143.          case 68:  
  144.              mciSendString(TEXT("close c://5.mp3"), NULL, 0, NULL);  
  145.              mciSendString(TEXT("play c://5.mp3"), NULL, 0, NULL);  
  146.              break;  
  147.          case 67:  
  148.              mciSendString(TEXT("close c://6.mp3"), NULL, 0, NULL);  
  149.              mciSendString(TEXT("play c://6.mp3"), NULL, 0, NULL);  
  150.              break;  
  151.          case 70:  
  152.              mciSendString(TEXT("close c://7.mp3"), NULL, 0, NULL);  
  153.              mciSendString(TEXT("play c://7.mp3"), NULL, 0, NULL);  
  154.              break;  
  155.          case 86:  
  156.              mciSendString(TEXT("close c://8.mp3"), NULL, 0, NULL);  
  157.              mciSendString(TEXT("play c://8.mp3"), NULL, 0, NULL);  
  158.              break;  
  159.          case 71:  
  160.              mciSendString(TEXT("close c://9.mp3"), NULL, 0, NULL);  
  161.              mciSendString(TEXT("play c://9.mp3"), NULL, 0, NULL);  
  162.              break;  
  163.          case 66:  
  164.              mciSendString(TEXT("close c://10.mp3"), NULL, 0, NULL);  
  165.              mciSendString(TEXT("play c://10.mp3"), NULL, 0, NULL);  
  166.              break;  
  167.          case 72:  
  168.              mciSendString(TEXT("close c://11.mp3"), NULL, 0, NULL);  
  169.              mciSendString(TEXT("play c://11.mp3"), NULL, 0, NULL);  
  170.              break;  
  171.          case 78:  
  172.              mciSendString(TEXT("close c://12.mp3"), NULL, 0, NULL);  
  173.              mciSendString(TEXT("play c://12.mp3"), NULL, 0, NULL);  
  174.              break;  
  175.          case 74:  
  176.              mciSendString(TEXT("close c://13.mp3"), NULL, 0, NULL);  
  177.              mciSendString(TEXT("play c://13.mp3"), NULL, 0, NULL);  
  178.              break;  
  179.          case 77:  
  180.              mciSendString(TEXT("close c://14.mp3"), NULL, 0, NULL);  
  181.              mciSendString(TEXT("play c://14.mp3"), NULL, 0, NULL);  
  182.              break;  
  183.          case 75:  
  184.              mciSendString(TEXT("close c://15.mp3"), NULL, 0, NULL);  
  185.              mciSendString(TEXT("play c://15.mp3"), NULL, 0, NULL);  
  186.              break;  
  187.          case VK_OEM_8:  
  188.              mciSendString(TEXT("close c://16.mp3"), NULL, 0, NULL);  
  189.              mciSendString(TEXT("play c://16.mp3"), NULL, 0, NULL);  
  190.              break;  
  191.          case 76:  
  192.              mciSendString(TEXT("close c://17.mp3"), NULL, 0, NULL);  
  193.              mciSendString(TEXT("play c://17.mp3"), NULL, 0, NULL);  
  194.              break;  
  195.          }  
  196.          return 0;  
  197.      case WM_DESTROY:  
  198.           PostQuitMessage (0) ;  
  199.           return 0 ;  
  200.      }  
  201.      return DefWindowProc (hwnd, message, wParam, lParam) ;  
  202. }  

中间有很多东西都是重复的,只是简单地完成了一个音乐播放的功能,而且也没有加上资源,加上GDI等东西。
这几天偶尔在书上看到了类似的一个程序,集合了菜单,资源等很多功能,是用MIDI来控制音乐播放的,所以有很多选项可以选择,下面附上代码:
  1. /*--------------------------------------- 
  2.    KBMIDI.C -- Keyboard MIDI Player  
  3.                (c) Charles Petzold, 1998 
  4.   ---------------------------------------*/  
  5.   
  6. #include <windows.h>  
  7.   
  8. // Defines for Menu IDs  
  9. // --------------------  
  10.   
  11. #define IDM_OPEN    0x100  
  12. #define IDM_CLOSE   0x101  
  13. #define IDM_DEVICE  0x200  
  14. #define IDM_CHANNEL 0x300  
  15. #define IDM_VOICE   0x400  
  16.   
  17. LRESULT CALLBACK WndProc (HWNDUINTWPARAMLPARAM);  
  18.   
  19. TCHAR    szAppName [] = TEXT ("KBMidi") ;  
  20. HMIDIOUT hMidiOut ;  
  21. int      iDevice = MIDIMAPPER, iChannel = 0, iVoice = 0, iVelocity = 64 ;  
  22. int      cxCaps, cyChar, xOffset, yOffset ;  
  23.   
  24.      // Structures and data for showing families and instruments on menu  
  25.      // ----------------------------------------------------------------  
  26.   
  27. typedef struct  
  28. {  
  29.      TCHAR * szInst ;  
  30.      int    iVoice ;  
  31. }  
  32. INSTRUMENT ;  
  33.   
  34. typedef struct  
  35. {  
  36.      TCHAR      * szFam ;  
  37.      INSTRUMENT   inst [8] ;  
  38. }  
  39. FAMILY ;  
  40.   
  41. FAMILY fam [16] = {   
  42.        
  43.      TEXT ("Piano"),  
  44.   
  45.           TEXT ("Acoustic Grand Piano"),        0,  
  46.           TEXT ("Bright Acoustic Piano"),       1,  
  47.           TEXT ("Electric Grand Piano"),        2,  
  48.           TEXT ("Honky-tonk Piano"),            3,  
  49.           TEXT ("Rhodes Piano"),                4,  
  50.           TEXT ("Chorused Piano"),              5,  
  51.           TEXT ("Harpsichord"),                 6,  
  52.           TEXT ("Clavinet"),                    7,  
  53.   
  54.      TEXT ("Chromatic Percussion"),  
  55.   
  56.           TEXT ("Celesta"),                     8,  
  57.           TEXT ("Glockenspiel"),                9,  
  58.           TEXT ("Music Box"),                   10,  
  59.           TEXT ("Vibraphone"),                  11,  
  60.           TEXT ("Marimba"),                     12,  
  61.           TEXT ("Xylophone"),                   13,  
  62.           TEXT ("Tubular Bells"),               14,  
  63.           TEXT ("Dulcimer"),                    15,  
  64.   
  65.      TEXT ("Organ"),  
  66.   
  67.           TEXT ("Hammond Organ"),               16,  
  68.           TEXT ("Percussive Organ"),            17,  
  69.           TEXT ("Rock Organ"),                  18,  
  70.           TEXT ("Church Organ"),                19,  
  71.           TEXT ("Reed Organ"),                  20,  
  72.           TEXT ("Accordian"),                   21,  
  73.           TEXT ("Harmonica"),                   22,  
  74.           TEXT ("Tango Accordian"),             23,  
  75.   
  76.      TEXT ("Guitar"),  
  77.   
  78.           TEXT ("Acoustic Guitar (nylon)"),     24,  
  79.           TEXT ("Acoustic Guitar (steel)"),     25,  
  80.           TEXT ("Electric Guitar (jazz)"),      26,  
  81.           TEXT ("Electric Guitar (clean)"),     27,  
  82.           TEXT ("Electric Guitar (muted)"),     28,  
  83.           TEXT ("Overdriven Guitar"),           29,  
  84.           TEXT ("Distortion Guitar"),           30,  
  85.           TEXT ("Guitar Harmonics"),            31,  
  86.   
  87.      TEXT ("Bass"),  
  88.   
  89.           TEXT ("Acoustic Bass"),               32,  
  90.           TEXT ("Electric Bass (finger)"),      33,  
  91.           TEXT ("Electric Bass (pick)"),        34,  
  92.           TEXT ("Fretless Bass"),               35,  
  93.           TEXT ("Slap Bass 1"),                 36,  
  94.           TEXT ("Slap Bass 2"),                 37,  
  95.           TEXT ("Synth Bass 1"),                38,  
  96.           TEXT ("Synth Bass 2"),                39,  
  97.   
  98.      TEXT ("Strings"),  
  99.   
  100.           TEXT ("Violin"),                      40,  
  101.           TEXT ("Viola"),                       41,  
  102.           TEXT ("Cello"),                       42,  
  103.           TEXT ("Contrabass"),                  43,  
  104.           TEXT ("Tremolo Strings"),             44,  
  105.           TEXT ("Pizzicato Strings"),           45,  
  106.           TEXT ("Orchestral Harp"),             46,  
  107.           TEXT ("Timpani"),                     47,  
  108.   
  109.      TEXT ("Ensemble"),  
  110.   
  111.           TEXT ("String Ensemble 1"),           48,  
  112.           TEXT ("String Ensemble 2"),           49,  
  113.           TEXT ("Synth Strings 1"),             50,  
  114.           TEXT ("Synth Strings 2"),             51,  
  115.           TEXT ("Choir Aahs"),                  52,  
  116.           TEXT ("Voice Oohs"),                  53,  
  117.           TEXT ("Synth Voice"),                 54,  
  118.           TEXT ("Orchestra Hit"),               55,  
  119.   
  120.      TEXT ("Brass"),  
  121.   
  122.           TEXT ("Trumpet"),                     56,  
  123.           TEXT ("Trombone"),                    57,  
  124.           TEXT ("Tuba"),                        58,  
  125.           TEXT ("Muted Trumpet"),               59,  
  126.           TEXT ("French Horn"),                 60,  
  127.           TEXT ("Brass Section"),               61,  
  128.           TEXT ("Synth Brass 1"),               62,  
  129.           TEXT ("Synth Brass 2"),               63,  
  130.   
  131.      TEXT ("Reed"),  
  132.   
  133.           TEXT ("Soprano Sax"),                 64,  
  134.           TEXT ("Alto Sax"),                    65,  
  135.           TEXT ("Tenor Sax"),                   66,  
  136.           TEXT ("Baritone Sax"),                67,  
  137.           TEXT ("Oboe"),                        68,  
  138.           TEXT ("English Horn"),                69,  
  139.           TEXT ("Bassoon"),                     70,  
  140.           TEXT ("Clarinet"),                    71,  
  141.   
  142.      TEXT ("Pipe"),  
  143.   
  144.           TEXT ("Piccolo"),                     72,  
  145.           TEXT ("Flute"),                       73,  
  146.           TEXT ("Recorder"),                    74,  
  147.           TEXT ("Pan Flute"),                   75,  
  148.           TEXT ("Bottle Blow"),                 76,  
  149.           TEXT ("Shakuhachi"),                  77,  
  150.           TEXT ("Whistle"),                     78,  
  151.           TEXT ("Ocarina"),                     79,  
  152.   
  153.      TEXT ("Synth Lead"),  
  154.   
  155.           TEXT ("Lead 1 (square)"),             80,  
  156.           TEXT ("Lead 2 (sawtooth)"),           81,  
  157.           TEXT ("Lead 3 (caliope lead)"),       82,  
  158.           TEXT ("Lead 4 (chiff lead)"),         83,  
  159.           TEXT ("Lead 5 (charang)"),            84,  
  160.           TEXT ("Lead 6 (voice)"),              85,  
  161.           TEXT ("Lead 7 (fifths)"),             86,  
  162.           TEXT ("Lead 8 (brass + lead)"),       87,  
  163.   
  164.      TEXT ("Synth Pad"),  
  165.   
  166.           TEXT ("Pad 1 (new age)"),             88,  
  167.           TEXT ("Pad 2 (warm)"),                89,  
  168.           TEXT ("Pad 3 (polysynth)"),           90,  
  169.           TEXT ("Pad 4 (choir)"),               91,  
  170.           TEXT ("Pad 5 (bowed)"),               92,  
  171.           TEXT ("Pad 6 (metallic)"),            93,  
  172.           TEXT ("Pad 7 (halo)"),                94,  
  173.           TEXT ("Pad 8 (sweep)"),               95,  
  174.   
  175.      TEXT ("Synth Effects"),  
  176.   
  177.           TEXT ("FX 1 (rain)"),                 96,  
  178.           TEXT ("FX 2 (soundtrack)"),           97,  
  179.           TEXT ("FX 3 (crystal)"),              98,  
  180.           TEXT ("FX 4 (atmosphere)"),           99,  
  181.           TEXT ("FX 5 (brightness)"),           100,  
  182.           TEXT ("FX 6 (goblins)"),              101,  
  183.           TEXT ("FX 7 (echoes)"),               102,  
  184.           TEXT ("FX 8 (sci-fi)"),               103,  
  185.   
  186.      TEXT ("Ethnic"),  
  187.   
  188.           TEXT ("Sitar"),                       104,  
  189.           TEXT ("Banjo"),                       105,  
  190.           TEXT ("Shamisen"),                    106,  
  191.           TEXT ("Koto"),                        107,  
  192.           TEXT ("Kalimba"),                     108,  
  193.           TEXT ("Bagpipe"),                     109,  
  194.           TEXT ("Fiddle"),                      110,  
  195.           TEXT ("Shanai"),                      111,  
  196.   
  197.      TEXT ("Percussive"),  
  198.   
  199.           TEXT ("Tinkle Bell"),                 112,  
  200.           TEXT ("Agogo"),                       113,  
  201.           TEXT ("Steel Drums"),                 114,  
  202.           TEXT ("Woodblock"),                   115,  
  203.           TEXT ("Taiko Drum"),                  116,  
  204.           TEXT ("Melodic Tom"),                 117,  
  205.           TEXT ("Synth Drum"),                  118,  
  206.           TEXT ("Reverse Cymbal"),              119,  
  207.   
  208.      TEXT ("Sound Effects"),  
  209.   
  210.           TEXT ("Guitar Fret Noise"),           120,  
  211.           TEXT ("Breath Noise"),                121,  
  212.           TEXT ("Seashore"),                    122,  
  213.           TEXT ("Bird Tweet"),                  123,  
  214.           TEXT ("Telephone Ring"),              124,  
  215.           TEXT ("Helicopter"),                  125,  
  216.           TEXT ("Applause"),                    126,  
  217.           TEXT ("Gunshot"),                     127 } ;  
  218.   
  219.      // Data for translating scan codes to octaves and notes  
  220.      // ----------------------------------------------------  
  221.   
  222. #define NUMSCANS    (sizeof key / sizeof key[0])  
  223.   
  224. struct  
  225. {  
  226.      int     iOctave ;  
  227.      int     iNote ;  
  228.      int     yPos ;  
  229.      int     xPos ;  
  230.      TCHAR * szKey ;  
  231. }  
  232. key [] =  
  233. {  
  234.                                          // Scan  Char  Oct  Note  
  235.                                          // ----  ----  ---  ----  
  236.          -1, -1, -1, -1, NULL,           //   0   None  
  237.          -1, -1, -1, -1, NULL,           //   1   Esc  
  238.          -1, -1,  0,  0, TEXT (""),      //   2     1  
  239.           5,  1,  0,  2, TEXT ("C#"),    //   3     2    5    C#  
  240.           5,  3,  0,  4, TEXT ("D#"),    //   4     3    5    D#  
  241.          -1, -1,  0,  6, TEXT (""),      //   5     4  
  242.           5,  6,  0,  8, TEXT ("F#"),    //   6     5    5    F#  
  243.           5,  8,  0, 10, TEXT ("G#"),    //   7     6    5    G#  
  244.           5, 10,  0, 12, TEXT ("A#"),    //   8     7    5    A#  
  245.          -1, -1,  0, 14, TEXT (""),      //   9     8  
  246.           6,  1,  0, 16, TEXT ("C#"),    //  10     9    6    C#  
  247.           6,  3,  0, 18, TEXT ("D#"),    //  11     0    6    D#  
  248.          -1, -1,  0, 20, TEXT (""),      //  12     -  
  249.           6,  6,  0, 22, TEXT ("F#"),    //  13     =    6    F#  
  250.          -1, -1, -1, -1, NULL,           //  14    Back  
  251.             
  252.          -1, -1, -1, -1, NULL,           //  15    Tab  
  253.           5,  0,  1,  1, TEXT ("C"),     //  16     q    5    C  
  254.           5,  2,  1,  3, TEXT ("D"),     //  17     w    5    D  
  255.           5,  4,  1,  5, TEXT ("E"),     //  18     e    5    E  
  256.           5,  5,  1,  7, TEXT ("F"),     //  19     r    5    F  
  257.           5,  7,  1,  9, TEXT ("G"),     //  20     t    5    G  
  258.           5,  9,  1, 11, TEXT ("A"),     //  21     y    5    A  
  259.           5, 11,  1, 13, TEXT ("B"),     //  22     u    5    B  
  260.           6,  0,  1, 15, TEXT ("C"),     //  23     i    6    C  
  261.           6,  2,  1, 17, TEXT ("D"),     //  24     o    6    D  
  262.           6,  4,  1, 19, TEXT ("E"),     //  25     p    6    E  
  263.           6,  5,  1, 21, TEXT ("F"),     //  26     [    6    F  
  264.           6,  7,  1, 23, TEXT ("G"),     //  27     ]    6    G  
  265.          -1, -1, -1, -1, NULL,           //  28    Ent  
  266.             
  267.          -1, -1, -1, -1, NULL,           //  29    Ctrl  
  268.           3,  8,  2,  2, TEXT ("G#"),    //  30     a    3    G#  
  269.           3, 10,  2,  4, TEXT ("A#"),    //  31     s    3    A#  
  270.          -1, -1,  2,  6, TEXT (""),      //  32     d  
  271.           4,  1,  2,  8, TEXT ("C#"),    //  33     f    4    C#  
  272.           4,  3,  2, 10, TEXT ("D#"),    //  34     g    4    D#  
  273.          -1, -1,  2, 12, TEXT (""),      //  35     h  
  274.           4,  6,  2, 14, TEXT ("F#"),    //  36     j    4    F#  
  275.           4,  8,  2, 16, TEXT ("G#"),    //  37     k    4    G#  
  276.           4, 10,  2, 18, TEXT ("A#"),    //  38     l    4    A#  
  277.          -1, -1,  2, 20, TEXT (""),      //  39     ;  
  278.           5,  1,  2, 22, TEXT ("C#"),    //  40     '    5    C#  
  279.          -1, -1, -1, -1, NULL,           //  41     `  
  280.             
  281.          -1, -1, -1, -1, NULL,           //  42    Shift  
  282.          -1, -1, -1, -1, NULL,           //  43     \  (not line continuation)  
  283.           3,  9,  3,  3, TEXT ("A"),     //  44     z    3    A  
  284.           3, 11,  3,  5, TEXT ("B"),     //  45     x    3    B  
  285.           4,  0,  3,  7, TEXT ("C"),     //  46     c    4    C  
  286.           4,  2,  3,  9, TEXT ("D"),     //  47     v    4    D  
  287.           4,  4,  3, 11, TEXT ("E"),     //  48     b    4    E  
  288.           4,  5,  3, 13, TEXT ("F"),     //  49     n    4    F  
  289.           4,  7,  3, 15, TEXT ("G"),     //  50     m    4    G  
  290.           4,  9,  3, 17, TEXT ("A"),     //  51     ,    4    A  
  291.           4, 11,  3, 19, TEXT ("B"),     //  52     .    4    B  
  292.           5,  0,  3, 21, TEXT ("C")      //  53     /    5    C  
  293. } ;  
  294.   
  295. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,  
  296.                     PSTR szCmdLine, int iCmdShow)  
  297. {  
  298.      MSG      msg;  
  299.      HWND     hwnd ;  
  300.      WNDCLASS wndclass ;  
  301.        
  302.      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;  
  303.      wndclass.lpfnWndProc   = WndProc ;  
  304.      wndclass.cbClsExtra    = 0 ;  
  305.      wndclass.cbWndExtra    = 0 ;  
  306.      wndclass.hInstance     = hInstance ;  
  307.      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;  
  308.      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;  
  309.      wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;  
  310.      wndclass.lpszMenuName  = NULL ;  
  311.      wndclass.lpszClassName = szAppName ;  
  312.        
  313.      if (!RegisterClass (&wndclass))  
  314.      {  
  315.           MessageBox (NULL, TEXT ("This program requires Windows NT!"),  
  316.                       szAppName, MB_ICONERROR) ;  
  317.           return 0 ;  
  318.      }  
  319.        
  320.      hwnd = CreateWindow (szAppName, TEXT ("Keyboard MIDI Player"),  
  321.                           WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,  
  322.                           CW_USEDEFAULT, CW_USEDEFAULT,  
  323.                           CW_USEDEFAULT, CW_USEDEFAULT,  
  324.                           NULL, NULL, hInstance, NULL) ;  
  325.   
  326.      if (!hwnd)  
  327.           return 0 ;  
  328.        
  329.      ShowWindow (hwnd, iCmdShow) ;  
  330.      UpdateWindow (hwnd);   
  331.        
  332.      while (GetMessage (&msg, NULL, 0, 0))  
  333.      {  
  334.           TranslateMessage (&msg) ;  
  335.           DispatchMessage (&msg) ;  
  336.      }  
  337.      return msg.wParam ;  
  338. }  
  339.   
  340. // Create the program's menu (called from WndProc, WM_CREATE)  
  341. // ----------------------------------------------------------  
  342.   
  343. HMENU CreateTheMenu (int iNumDevs)  
  344. {  
  345.      TCHAR       szBuffer [32] ;  
  346.      HMENU       hMenu, hMenuPopup, hMenuSubPopup ;  
  347.      int         i, iFam, iIns ;  
  348.      MIDIOUTCAPS moc ;  
  349.        
  350.      hMenu = CreateMenu () ;  
  351.        
  352.           // Create "On/Off" popup menu  
  353.        
  354.      hMenuPopup = CreateMenu () ;  
  355.        
  356.      AppendMenu (hMenuPopup, MF_STRING, IDM_OPEN, TEXT ("&Open")) ;   
  357.      AppendMenu (hMenuPopup, MF_STRING | MF_CHECKED, IDM_CLOSE,   
  358.                              TEXT ("&Closed")) ;  
  359.        
  360.      AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,   
  361.                         TEXT ("&Status")) ;  
  362.        
  363.           // Create "Device" popup menu  
  364.        
  365.      hMenuPopup = CreateMenu () ;  
  366.        
  367.           // Put MIDI Mapper on menu if it's installed  
  368.        
  369.      if (!midiOutGetDevCaps (MIDIMAPPER, &moc, sizeof (moc)))  
  370.           AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + (int) MIDIMAPPER,  
  371.                          moc.szPname) ;  
  372.      else  
  373.           iDevice = 0 ;  
  374.        
  375.           // Add the rest of the MIDI devices  
  376.        
  377.      for (i = 0 ; i < iNumDevs ; i++)  
  378.      {  
  379.           midiOutGetDevCaps (i, &moc, sizeof (moc)) ;  
  380.           AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + i, moc.szPname) ;  
  381.      }  
  382.        
  383.      CheckMenuItem (hMenuPopup, 0, MF_BYPOSITION | MF_CHECKED) ;  
  384.      AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,   
  385.                         TEXT ("&Device")) ;  
  386.        
  387.           // Create "Channel" popup menu  
  388.        
  389.      hMenuPopup = CreateMenu () ;  
  390.        
  391.      for (i = 0 ; i < 16 ; i++)  
  392.      {  
  393.           wsprintf (szBuffer, TEXT ("%d"), i + 1) ;  
  394.           AppendMenu (hMenuPopup, MF_STRING | (i ? MF_UNCHECKED : MF_CHECKED),  
  395.                                   IDM_CHANNEL + i, szBuffer) ;  
  396.      }  
  397.        
  398.      AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,   
  399.                         TEXT ("&Channel")) ;  
  400.        
  401.           // Create "Voice" popup menu  
  402.        
  403.      hMenuPopup = CreateMenu () ;  
  404.        
  405.      for (iFam = 0 ; iFam < 16 ; iFam++)  
  406.      {  
  407.           hMenuSubPopup = CreateMenu () ;  
  408.             
  409.           for (iIns = 0 ; iIns < 8 ; iIns++)  
  410.           {  
  411.                wsprintf (szBuffer, TEXT ("&%d.\t%s"), iIns + 1,  
  412.                                    fam[iFam].inst[iIns].szInst) ;  
  413.                AppendMenu (hMenuSubPopup,  
  414.                            MF_STRING | (fam[iFam].inst[iIns].iVoice ?  
  415.                                              MF_UNCHECKED : MF_CHECKED),  
  416.                            fam[iFam].inst[iIns].iVoice + IDM_VOICE,  
  417.                            szBuffer) ;  
  418.           }  
  419.             
  420.           wsprintf (szBuffer, TEXT ("&%c.\t%s"), 'A' + iFam,  
  421.                               fam[iFam].szFam) ;  
  422.           AppendMenu (hMenuPopup, MF_STRING | MF_POPUP, (UINT) hMenuSubPopup,  
  423.                                   szBuffer) ;  
  424.      }  
  425.      AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup,   
  426.                         TEXT ("&Voice")) ;  
  427.      return hMenu ;  
  428. }  
  429.   
  430. // Routines for simplifying MIDI output  
  431. // ------------------------------------  
  432.   
  433. DWORD MidiOutMessage (HMIDIOUT hMidi, int iStatus, int iChannel,  
  434.                       int iData1,  int iData2)  
  435. {  
  436.      DWORD dwMessage ;  
  437.        
  438.      dwMessage = iStatus | iChannel | (iData1 << 8) | (iData2 << 16) ;  
  439.        
  440.      return midiOutShortMsg (hMidi, dwMessage) ;  
  441. }  
  442.   
  443. DWORD MidiNoteOff (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel)  
  444. {  
  445.      return MidiOutMessage (hMidi, 0x080, iChannel, 12 * iOct + iNote, iVel) ;  
  446. }  
  447.   
  448. DWORD MidiNoteOn (HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel)  
  449. {  
  450.      return MidiOutMessage (hMidi, 0x090, iChannel, 12 * iOct + iNote, iVel) ;  
  451. }  
  452.   
  453. DWORD MidiSetPatch (HMIDIOUT hMidi, int iChannel, int iVoice)  
  454. {  
  455.      return MidiOutMessage (hMidi, 0x0C0, iChannel, iVoice, 0) ;  
  456. }  
  457.   
  458. DWORD MidiPitchBend (HMIDIOUT hMidi, int iChannel, int iBend)  
  459. {  
  460.      return MidiOutMessage (hMidi, 0x0E0, iChannel, iBend & 0x7F, iBend >> 7) ;  
  461. }  
  462.   
  463. // Draw a single key on window  
  464. // ---------------------------  
  465.   
  466. VOID DrawKey (HDC hdc, int iScanCode, BOOL fInvert)  
  467. {  
  468.      RECT rc ;  
  469.        
  470.      rc.left   = 3 * cxCaps * key[iScanCode].xPos / 2 + xOffset ;  
  471.      rc.top    = 3 * cyChar * key[iScanCode].yPos / 2 + yOffset ;  
  472.      rc.right  = rc.left + 3 * cxCaps ;  
  473.      rc.bottom = rc.top  + 3 * cyChar / 2 ;  
  474.        
  475.      SetTextColor (hdc, fInvert ? 0x00FFFFFFul : 0x00000000ul) ;  
  476.      SetBkColor   (hdc, fInvert ? 0x00000000ul : 0x00FFFFFFul) ;  
  477.        
  478.      FillRect (hdc, &rc, GetStockObject (fInvert ? BLACK_BRUSH : WHITE_BRUSH)) ;  
  479.        
  480.      DrawText (hdc, key[iScanCode].szKey, -1, &rc,  
  481.                     DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;  
  482.        
  483.      FrameRect (hdc, &rc, GetStockObject (BLACK_BRUSH)) ;  
  484. }  
  485.   
  486. // Process a Key Up or Key Down message  
  487. // ------------------------------------  
  488.   
  489. VOID ProcessKey (HDC hdc, UINT message, LPARAM lParam)  
  490. {  
  491.      int iScanCode, iOctave, iNote ;  
  492.        
  493.      iScanCode = 0x0FF & HIWORD (lParam) ;  
  494.        
  495.      if (iScanCode >= NUMSCANS)                       // No scan codes over 53  
  496.           return ;  
  497.        
  498.      if ((iOctave = key[iScanCode].iOctave) == -1)    // Non-music key  
  499.           return ;  
  500.        
  501.      if (GetKeyState (VK_SHIFT) < 0)  
  502.           iOctave += 0x20000000 & lParam ? 2 : 1 ;  
  503.        
  504.      if (GetKeyState (VK_CONTROL) < 0)  
  505.           iOctave -= 0x20000000 & lParam ? 2 : 1 ;  
  506.        
  507.      iNote = key[iScanCode].iNote ;  
  508.        
  509.      if (message == WM_KEYUP)                           // For key up  
  510.      {  
  511.           MidiNoteOff (hMidiOut, iChannel, iOctave, iNote, 0) ;   // Note off  
  512.           DrawKey (hdc, iScanCode, FALSE) ;  
  513.           return ;  
  514.      }  
  515.        
  516.      if (0x40000000 & lParam)                          // ignore typematics  
  517.           return ;  
  518.        
  519.      MidiNoteOn (hMidiOut, iChannel, iOctave, iNote, iVelocity) ; // Note on  
  520.      DrawKey (hdc, iScanCode, TRUE) ;                 // Draw the inverted key  
  521. }  
  522.   
  523. // Window Procedure  
  524. // ----------------  
  525.   
  526. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
  527. {  
  528.      static BOOL bOpened = FALSE ;  
  529.      HDC         hdc ;  
  530.      HMENU       hMenu ;  
  531.      int         i, iNumDevs, iPitchBend, cxClient, cyClient ;  
  532.      MIDIOUTCAPS moc ;  
  533.      PAINTSTRUCT ps ;  
  534.      SIZE        size ;  
  535.      TCHAR       szBuffer [16] ;  
  536.        
  537.      switch (message)  
  538.      {  
  539.      case WM_CREATE:  
  540.                // Get size of capital letters in system font  
  541.             
  542.           hdc = GetDC (hwnd) ;  
  543.             
  544.           GetTextExtentPoint (hdc, TEXT ("M"), 1, &size) ;  
  545.           cxCaps = size.cx ;  
  546.           cyChar = size.cy ;  
  547.             
  548.           ReleaseDC (hwnd, hdc) ;  
  549.             
  550.                // Initialize "Volume" scroll bar  
  551.             
  552.           SetScrollRange (hwnd, SB_HORZ, 1, 127, FALSE) ;  
  553.           SetScrollPos   (hwnd, SB_HORZ, iVelocity, TRUE) ;  
  554.             
  555.                // Initialize "Pitch Bend" scroll bar  
  556.             
  557.           SetScrollRange (hwnd, SB_VERT, 0, 16383, FALSE) ;  
  558.           SetScrollPos   (hwnd, SB_VERT, 8192, TRUE) ;  
  559.             
  560.                // Get number of MIDI output devices and set up menu  
  561.             
  562.           if (0 == (iNumDevs = midiOutGetNumDevs ()))  
  563.           {  
  564.                MessageBeep (MB_ICONSTOP) ;  
  565.                MessageBox (hwnd, TEXT ("No MIDI output devices!"),  
  566.                                  szAppName, MB_OK | MB_ICONSTOP) ;  
  567.                return -1 ;  
  568.           }  
  569.           SetMenu (hwnd, CreateTheMenu (iNumDevs)) ;  
  570.           return 0 ;  
  571.             
  572.      case WM_SIZE:  
  573.           cxClient = LOWORD (lParam) ;  
  574.           cyClient = HIWORD (lParam) ;  
  575.             
  576.           xOffset = (cxClient - 25 * 3 * cxCaps / 2) / 2 ;  
  577.           yOffset = (cyClient - 11 * cyChar) / 2 + 5 * cyChar ;  
  578.           return 0 ;  
  579.             
  580.      case WM_COMMAND:  
  581.           hMenu = GetMenu (hwnd) ;  
  582.             
  583.               // "Open" menu command  
  584.             
  585.           if (LOWORD (wParam) == IDM_OPEN && !bOpened)  
  586.           {  
  587.                if (midiOutOpen (&hMidiOut, iDevice, 0, 0, 0))  
  588.                {  
  589.                     MessageBeep (MB_ICONEXCLAMATION) ;  
  590.                     MessageBox (hwnd, TEXT ("Cannot open MIDI device"),  
  591.                                 szAppName, MB_OK | MB_ICONEXCLAMATION) ;  
  592.                }  
  593.                else  
  594.                {  
  595.                     CheckMenuItem (hMenu, IDM_OPEN,  MF_CHECKED) ;  
  596.                     CheckMenuItem (hMenu, IDM_CLOSE, MF_UNCHECKED) ;  
  597.                       
  598.                     MidiSetPatch (hMidiOut, iChannel, iVoice) ;  
  599.                     bOpened = TRUE ;  
  600.                }  
  601.           }  
  602.             
  603.                // "Close" menu command  
  604.             
  605.           else if (LOWORD (wParam) == IDM_CLOSE && bOpened)  
  606.           {  
  607.                CheckMenuItem (hMenu, IDM_OPEN,  MF_UNCHECKED) ;  
  608.                CheckMenuItem (hMenu, IDM_CLOSE, MF_CHECKED) ;  
  609.                  
  610.                     // Turn all keys off and close device  
  611.                  
  612.                for (i = 0 ; i < 16 ; i++)  
  613.                     MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ;  
  614.                  
  615.                midiOutClose (hMidiOut) ;  
  616.                bOpened = FALSE ;  
  617.           }  
  618.             
  619.                // Change MIDI "Device" menu command  
  620.             
  621.           else if (LOWORD (wParam) >= IDM_DEVICE - 1 &&   
  622.                    LOWORD (wParam) <  IDM_CHANNEL)  
  623.           {  
  624.                CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_UNCHECKED) ;  
  625.                iDevice = LOWORD (wParam) - IDM_DEVICE ;  
  626.                CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_CHECKED) ;  
  627.                  
  628.                     // Close and reopen MIDI device  
  629.                  
  630.                if (bOpened)  
  631.                {  
  632.                     SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ;  
  633.                     SendMessage (hwnd, WM_COMMAND, IDM_OPEN,  0L) ;  
  634.                }  
  635.           }  
  636.             
  637.                // Change MIDI "Channel" menu command  
  638.             
  639.           else if (LOWORD (wParam) >= IDM_CHANNEL &&   
  640.                    LOWORD (wParam) <  IDM_VOICE)  
  641.           {  
  642.                CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_UNCHECKED);  
  643.                iChannel = LOWORD (wParam) - IDM_CHANNEL ;  
  644.                CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_CHECKED) ;  
  645.                  
  646.                if (bOpened)  
  647.                     MidiSetPatch (hMidiOut, iChannel, iVoice) ;  
  648.           }  
  649.             
  650.                // Change MIDI "Voice" menu command  
  651.             
  652.           else if (LOWORD (wParam) >= IDM_VOICE)  
  653.           {  
  654.                CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_UNCHECKED) ;  
  655.                iVoice = LOWORD (wParam) - IDM_VOICE ;  
  656.                CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_CHECKED) ;  
  657.                  
  658.                if (bOpened)  
  659.                     MidiSetPatch (hMidiOut, iChannel, iVoice) ;  
  660.           }  
  661.             
  662.           InvalidateRect (hwnd, NULL, TRUE) ;  
  663.           return 0 ;  
  664.             
  665.           // Process a Key Up or Key Down message  
  666.             
  667.      case WM_KEYUP:  
  668.      case WM_KEYDOWN:  
  669.           hdc = GetDC (hwnd) ;  
  670.             
  671.           if (bOpened)  
  672.                ProcessKey (hdc, message, lParam) ;  
  673.             
  674.           ReleaseDC (hwnd, hdc) ;  
  675.           return 0 ;  
  676.             
  677.           // For Escape, turn off all notes and repaint  
  678.             
  679.      case WM_CHAR:  
  680.           if (bOpened && wParam == 27)  
  681.           {  
  682.                for (i = 0 ; i < 16 ; i++)  
  683.                     MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ;  
  684.                  
  685.                InvalidateRect (hwnd, NULL, TRUE) ;  
  686.           }  
  687.           return 0 ;  
  688.             
  689.           // Horizontal scroll: Velocity  
  690.             
  691.      case WM_HSCROLL:  
  692.           switch (LOWORD (wParam))  
  693.           {  
  694.           case SB_LINEUP:         iVelocity -= 1 ;  break ;  
  695.           case SB_LINEDOWN:       iVelocity += 1 ;  break ;  
  696.           case SB_PAGEUP:         iVelocity -= 8 ;  break ;  
  697.           case SB_PAGEDOWN:       iVelocity += 8 ;  break ;  
  698.           case SB_THUMBPOSITION:  iVelocity = HIWORD (wParam) ;  break ;  
  699.           default:                return 0 ;  
  700.           }  
  701.           iVelocity = max (1, min (iVelocity, 127)) ;  
  702.           SetScrollPos (hwnd, SB_HORZ, iVelocity, TRUE) ;  
  703.           return 0 ;  
  704.             
  705.           // Vertical scroll:  Pitch Bend  
  706.        
  707.      case WM_VSCROLL:  
  708.           switch (LOWORD (wParam))  
  709.           {  
  710.           case SB_THUMBTRACK:    iPitchBend = 16383 - HIWORD (wParam) ;  break ;  
  711.           case SB_THUMBPOSITION: iPitchBend = 8191 ;                     break ;  
  712.           default:               return 0 ;  
  713.           }  
  714.           iPitchBend = max (0, min (iPitchBend, 16383)) ;  
  715.           SetScrollPos (hwnd, SB_VERT, 16383 - iPitchBend, TRUE) ;  
  716.             
  717.           if (bOpened)  
  718.                MidiPitchBend (hMidiOut, iChannel, iPitchBend) ;  
  719.           return 0 ;  
  720.        
  721.      case WM_PAINT:  
  722.           hdc = BeginPaint (hwnd, &ps) ;  
  723.             
  724.           for (i = 0 ; i < NUMSCANS ; i++)  
  725.                if (key[i].xPos != -1)  
  726.                     DrawKey (hdc, i, FALSE) ;  
  727.                  
  728.           midiOutGetDevCaps (iDevice, &moc, sizeof (MIDIOUTCAPS)) ;  
  729.           wsprintf (szBuffer, TEXT ("Channel %i"), iChannel + 1) ;  
  730.        
  731.           TextOut (hdc, cxCaps, 1 * cyChar,   
  732.                         bOpened ? TEXT ("Open") : TEXT ("Closed"),  
  733.                         bOpened ? 4 : 6) ;  
  734.           TextOut (hdc, cxCaps, 2 * cyChar, moc.szPname,  
  735.                         lstrlen (moc.szPname)) ;  
  736.           TextOut (hdc, cxCaps, 3 * cyChar, szBuffer, lstrlen (szBuffer)) ;  
  737.           TextOut (hdc, cxCaps, 4 * cyChar,  
  738.                         fam[iVoice / 8].inst[iVoice % 8].szInst,  
  739.                lstrlen (fam[iVoice / 8].inst[iVoice % 8].szInst)) ;  
  740.        
  741.           EndPaint (hwnd, &ps) ;  
  742.           return 0 ;  
  743.                  
  744.      case WM_DESTROY :  
  745.           SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ;  
  746.           PostQuitMessage (0) ;  
  747.           return 0 ;  
  748.      }  
  749.      return DefWindowProc (hwnd, message, wParam, lParam) ;  
  750. }  

程序虽然有点长,自己现在也没有学得很好,所以还不能完全看懂。希望以后能写一下关于这个程序的解释

没有评论:

发表评论