home *** CD-ROM | disk | FTP | other *** search
/ Game Audio Programming / GameAudioProgramming.iso / Extras / Sensaura / SDK1.0 / data1.cab / Example_Files / ZoomFX / mainwnd.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-13  |  17.7 KB  |  743 lines

  1. /*
  2.     Company:            Sensaura Ltd
  3.     Copyright:          (C) 2000
  4.  
  5.     File Name:            mainwnd.cpp
  6.     File Description:    Source file for implementation of MainWnd class
  7.     Author:                Adam Philp
  8.     Last Update:        04-JAN-00
  9.  
  10.     Target Compiler:    Microsoft Visual C++ Version 5.0
  11. */
  12.  
  13. ///////////////////////    Included files ////////////////////////////////////////////////////////////
  14.  
  15. #include <windows.h>
  16. #include <stddef.h>
  17. #include <string.h>
  18.  
  19. #include "mainwnd.h"
  20. #include "applicat.h"
  21. #include "aboutbox.h"
  22. #include "buffrdlg.h"
  23. #include "lstnrdlg.h"
  24. #include "directx.h"
  25. #include "debug.h"
  26. #include "resource.h"
  27.  
  28. ///////////////////////    Definitions ///////////////////////////////////////////////////////////////
  29.  
  30. #define TIMERPERIOD        500                // 1/2 second
  31.  
  32. ///////////////////////    Local type definitions ////////////////////////////////////////////////////
  33.  
  34. typedef LRESULT (CALLBACK *ThunkProc)(HWND, UINT, WPARAM, LPARAM);
  35.  
  36. #pragma pack(1)
  37.  
  38. struct InstanceThunk 
  39. {
  40.   BYTE        Call;
  41.   int        Offset;
  42.   ThunkProc    Proc;
  43.   MainWnd*    MainWnd;
  44.   BYTE        Code[6];
  45. };
  46. #pragma pack()
  47.  
  48. ///////////////////////    Constants /////////////////////////////////////////////////////////////////
  49.  
  50. static const int CodeOffset = offsetof(InstanceThunk, Code)-offsetof(InstanceThunk, Proc);
  51.  
  52. ///////////////////////    Local variables ///////////////////////////////////////////////////////////
  53.  
  54. MainWnd* g_ThunkWindow = NULL;
  55.  
  56. ///////////////////////    Local functions ///////////////////////////////////////////////////////////
  57.  
  58. /*
  59.     The following functions handle setting the pThunk for our window object to enable us to use a
  60.     C++ class to handle Windows messages
  61. */
  62.  
  63. WNDPROC CreateInstanceThunk(MainWnd* w, ThunkProc thunkProc)
  64. {
  65.   InstanceThunk* pThunk;
  66.   
  67.   pThunk = new InstanceThunk;
  68.  
  69.   pThunk->Call = 0xE8u;        // CALL rel32
  70.   pThunk->Offset = CodeOffset; // relative displacement to Code[5]
  71.   pThunk->Proc = thunkProc;
  72.   pThunk->MainWnd = w;
  73.  
  74.   // POP ECX
  75.   //
  76.   // pop return address of call into ecx (address of member "Proc")
  77.   //
  78.   pThunk->Code[0] = 0x59u;
  79.  
  80.   // MOV EAX,[ECX+4]
  81.   //
  82.   // load "MainWnd" into ebx
  83.   //
  84.   pThunk->Code[1] = 0x8Bu;     // MOV r32,r/m32
  85.   pThunk->Code[2] = 0x41u;     // eax,disp8[ECX]
  86.   pThunk->Code[3] = 0x04u;     // +4
  87.  
  88.   // JMP [ECX]
  89.   //
  90.   // jump to window function provided
  91.   //
  92.   pThunk->Code[4] = 0xFFu;     // JMP r/m32
  93.   pThunk->Code[5] = 0x21u;     // [ECX]
  94.  
  95.   return (WNDPROC)pThunk;
  96. }
  97.  
  98. void FreeInstanceThunk(WNDPROC proc)
  99. {
  100.   delete (InstanceThunk*)proc;
  101. }
  102.  
  103. void SetWindowToThunk(MainWnd* w)
  104. {
  105.     g_ThunkWindow = w;
  106. }
  107.  
  108. MainWnd* GetWindowToThunk()
  109. {
  110.     return g_ThunkWindow;
  111. }
  112.  
  113. LRESULT    CALLBACK InitWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  114. {
  115.     WNDPROC pThunk;
  116.  
  117.     if(!g_ThunkWindow)
  118.         return DefWindowProc(hwnd, message, wParam, lParam);
  119.     g_ThunkWindow->m_hWnd = hwnd;
  120.     g_ThunkWindow->SetDefaultProc((WNDPROC)GetProcAddress((HINSTANCE)GetModuleHandle("USER32"), 
  121.                                                           "DefWindowProcA"));
  122.     pThunk = g_ThunkWindow->GetThunk();
  123.     g_ThunkWindow = NULL;
  124.  
  125.     SetWindowLong(hwnd, GWL_WNDPROC, (long)pThunk);
  126.     return (*(WNDPROC)(pThunk))(hwnd, message, wParam, lParam);
  127. }
  128.  
  129. /////////////////////// MainWnd class implementation ///////////////////////////////////////////////
  130.  
  131. MainWnd::MainWnd(LPCSTR pCaption, Application* pApp)
  132. {
  133.     m_pApp = pApp;
  134.     m_hWnd = NULL;
  135.     m_DefaultProc = NULL;
  136.     m_Thunk = CreateInstanceThunk(this, StdWndProc);
  137.  
  138.     m_xNextPos = 0;
  139.     m_yNextPos = 0;
  140.  
  141.     m_pDirectSound = NULL;
  142.     m_pPrimary = NULL;
  143.     m_pListener = NULL;
  144.  
  145.     m_bCanDoZoomFX = false;
  146.     m_bZoomFX = false;
  147.  
  148.     m_dwTimer = 0;
  149.     m_hbmZoomFX = NULL;
  150.     memset(&m_dsCaps, 0, sizeof(m_dsCaps));
  151.     m_dsCaps.dwSize = sizeof(m_dsCaps);
  152.  
  153.     m_pListenerDlg = NULL;
  154.     m_pBufferDlgs = NULL;
  155.  
  156. }
  157.  
  158. MainWnd::~MainWnd()
  159. {
  160.     if(m_hWnd)
  161.         DestroyWindow();                // Destroy MS-MainWnd
  162.     
  163.     FreeInstanceThunk(m_Thunk);
  164. }
  165.  
  166. /////////////////////// MainWnd public member functions ///////////////////////////////////////////
  167.  
  168. int MainWnd::GetClassName(LPSTR className, int maxCount) const
  169. {
  170.     return ::GetClassName(m_hWnd, className, maxCount);
  171. }
  172.  
  173. LPSTR MainWnd::GetClassName() const
  174. {
  175.     return "MainWnd";
  176. }
  177.  
  178. LPCSTR MainWnd::GetCaption() const 
  179.     return m_pApp->GetName(); 
  180. }
  181.  
  182. void MainWnd::GetWindowClass(WNDCLASS& wc) const
  183. {
  184.     wc.cbClsExtra = 0;
  185.     wc.cbWndExtra = 0;
  186.     wc.hInstance = m_pApp->GetInstance();
  187.     wc.hIcon = LoadIcon(m_pApp->GetInstance(), MAKEINTRESOURCE(IDI_SENSAURA));
  188.     wc.hCursor = ::LoadCursor(0, IDC_ARROW);
  189.     wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  190.     wc.lpszMenuName = MAKEINTRESOURCE(IDM_MAINMENU);
  191.     wc.lpszClassName = GetClassName();
  192.     wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
  193.     wc.lpfnWndProc = InitWndProc;
  194. }
  195.  
  196. bool MainWnd::Create()
  197. {
  198.     BITMAP                    bm;
  199.     LPDIRECTSOUNDBUFFER        pBuffer;
  200.     LPDIRECTSOUND3DBUFFER    p3dBuffer;
  201.     LPKSPROPERTYSET            pKsPropertySet;
  202.     unsigned long            ulSupport;
  203.     WAVEFORMATEX            wfx;
  204.     DSBUFFERDESC            dsbd;
  205.  
  206.     TRY_DS(DirectSoundCreate(NULL, &m_pDirectSound, NULL))
  207.  
  208.     m_hbmZoomFX = LoadBitmap(m_pApp->GetInstance(), MAKEINTRESOURCE(IDB_ZOOMFX));
  209.     if(m_hbmZoomFX == NULL)
  210.         return false;
  211.     GetObject(m_hbmZoomFX, sizeof(bm), &bm);
  212.  
  213.     if(Register()) 
  214.     {
  215.         SetWindowToThunk(this);
  216.  
  217.         m_hWnd = CreateWindowEx(0, GetClassName(), GetCaption(),
  218.                                 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_BORDER|WS_MINIMIZEBOX,
  219.                                 CW_USEDEFAULT, CW_USEDEFAULT, 
  220.                                 bm.bmWidth+2*GetSystemMetrics(SM_CXBORDER), 
  221.                                 bm.bmHeight+2*GetSystemMetrics(SM_CYBORDER)+GetSystemMetrics(SM_CYMENU)+GetSystemMetrics(SM_CYCAPTION),      
  222.                                 NULL, NULL, m_pApp->GetInstance(), NULL);
  223.     }
  224.     if(GetWindowToThunk() == this)
  225.         SetWindowToThunk(NULL);
  226.  
  227.     if(m_hWnd == NULL)
  228.         return false;
  229.  
  230.     TRY_DS(m_pDirectSound->SetCooperativeLevel(m_hWnd, DSSCL_NORMAL))
  231.  
  232.     dsbd.dwSize = sizeof(DSBUFFERDESC);    // Set primary buffer properties
  233.     dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER|DSBCAPS_CTRL3D;        
  234.     dsbd.dwBufferBytes = 0;                  
  235.     dsbd.dwReserved = 0;                
  236.     dsbd.lpwfxFormat = NULL;
  237.  
  238.     TRY_DS(m_pDirectSound->CreateSoundBuffer(&dsbd, &m_pPrimary, NULL))
  239.     if(m_pPrimary->QueryInterface(IID_IDirectSound3DListener, (void**)&m_pListener) != S_OK)
  240.         return false;
  241.  
  242.     wfx.wFormatTag = WAVE_FORMAT_PCM;    // Create a temp secondary buffer
  243.     wfx.nChannels = 1;
  244.     wfx.nSamplesPerSec = 11025;
  245.     wfx.nAvgBytesPerSec = 11025;
  246.     wfx.nBlockAlign = 1; 
  247.     wfx.wBitsPerSample = 8; 
  248.     wfx.cbSize = 0; 
  249.  
  250.     dsbd.dwSize = sizeof(DSBUFFERDESC);    // First, set up the DirectSound buffer description
  251.     dsbd.dwFlags = DSBCAPS_CTRL3D|DSBCAPS_LOCHARDWARE;
  252.     dsbd.dwBufferBytes = 256;
  253.     dsbd.dwReserved = 0;
  254.     dsbd.lpwfxFormat = &wfx;
  255.                 
  256.     TRY_DS(m_pDirectSound->CreateSoundBuffer(&dsbd, &pBuffer, NULL))
  257.     if(pBuffer->QueryInterface(IID_IDirectSound3DBuffer, (void**)&p3dBuffer) != S_OK)
  258.     {
  259.         pBuffer->Release();
  260.         return false;
  261.     }
  262.     if(pBuffer->QueryInterface(IID_IKsPropertySet, (void**)&pKsPropertySet))
  263.     {
  264.         p3dBuffer->Release();
  265.         pBuffer->Release();
  266.         return false;
  267.     }
  268.     m_bCanDoZoomFX = false;
  269.     if(pKsPropertySet->QuerySupport(DSPROPSETID_ZOOMFX_BufferProperties, DSPROPERTY_ZOOMFXBUFFER_ALL, &ulSupport) == S_OK)
  270.     {
  271.         if(ulSupport == (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET))
  272.         {
  273.             m_bCanDoZoomFX = true;        // Set status flag    
  274.             m_bZoomFX = true;            // ZoomFX on by default
  275.         }
  276.     }
  277.     pKsPropertySet->Release();
  278.     p3dBuffer->Release();
  279.     pBuffer->Release();
  280.  
  281.     if(!m_bCanDoZoomFX)                    // Allow the program to continue if ZoomFX not present
  282.         MessageBox("ZoomFX extensions are not supported", GetCaption(), MB_OK|MB_ICONEXCLAMATION);
  283.  
  284.     if((m_dwTimer = SetTimer(m_hWnd, 1, TIMERPERIOD, NULL)) == 0)
  285.     {                                    // Quit the app if we can't get a timer
  286.         MessageBox("Cannot allocate timer, aborting", GetCaption(), MB_OK|MB_ICONSTOP);
  287.         return false;
  288.     }
  289.     return true;
  290.  
  291. DS_ERROR:
  292.     return false;
  293.  
  294. }
  295.  
  296. bool MainWnd::ShowWindow(int nCmdShow)
  297. {
  298.     if(m_hWnd)
  299.         return ::ShowWindow(m_hWnd, nCmdShow) ? true : false;
  300.     return false;
  301. }
  302.  
  303. void MainWnd::Paint(HDC hdc, RECT& rect, bool bErase)
  304. {
  305.     RECT        rcClient;
  306.     TCHAR        szText[128];
  307.     SIZE        sizeExtent;
  308.     COLORREF    clrOld;
  309.  
  310.     GetClientRect(m_hWnd, &rcClient);
  311.     SetBkMode(hdc, TRANSPARENT);
  312.     clrOld = GetTextColor(hdc);
  313.     SetTextColor(hdc, RGB(0, 128, 64));
  314.  
  315.     wsprintf(szText, "Free HW Mem: %luKb", m_dsCaps.dwFreeHwMemBytes / 1024);
  316.     GetTextExtentPoint32(hdc, szText, lstrlen(szText), &sizeExtent);
  317.     DrawText(hdc, szText, -1, &rcClient, DT_TOP | DT_LEFT);
  318.  
  319.     wsprintf(szText, "Free HW Mixing Buffers: %lu", m_dsCaps.dwFreeHwMixingStaticBuffers);
  320.     rcClient.top += sizeExtent.cy;
  321.     DrawText(hdc, szText, -1, &rcClient, DT_TOP | DT_LEFT);
  322.  
  323.     wsprintf(szText, "Free HW 3D Buffers: %lu", m_dsCaps.dwFreeHw3DStaticBuffers);
  324.     rcClient.top += sizeExtent.cy;
  325.     DrawText(hdc, szText, -1, &rcClient, DT_TOP | DT_LEFT);
  326.  
  327.     wsprintf(szText, "ZoomFX extensions: %s", !m_bCanDoZoomFX ? "NOT PRESENT" : m_bZoomFX ? "ON" : "OFF");
  328.     rcClient.top += sizeExtent.cy;
  329.     DrawText(hdc, szText, -1, &rcClient, DT_TOP | DT_LEFT);
  330.  
  331.     SetTextColor(hdc, clrOld);
  332. }
  333.  
  334. LRESULT MainWnd::EvCommand(UINT id, HWND hwndCtl, UINT notifyCode)
  335. {
  336.     BufferList* pBuffer;
  337.  
  338.     switch(id)
  339.     {
  340.     case CM_FILE_OPEN:
  341.         OpenFile(NULL);
  342.         break;
  343.  
  344.     case CM_FILE_EXIT: 
  345.         SendMessage(WM_CLOSE);
  346.         break;
  347.  
  348.     case CM_BUFFERS_MINIMIZEALL:
  349.         pBuffer = m_pBufferDlgs;
  350.         while(pBuffer)
  351.         {
  352.             ::ShowWindow(pBuffer->pDlg->m_hWnd, SW_MINIMIZE);
  353.             pBuffer = pBuffer->pNext;
  354.         }
  355.         break;
  356.  
  357.     case CM_BUFFERS_RESTOREALL:
  358.         pBuffer = m_pBufferDlgs;
  359.         while(pBuffer)
  360.         {
  361.             ::SendMessage(pBuffer->pDlg->m_hWnd, WM_SYSCOMMAND, SC_RESTORE, 0L);
  362.             pBuffer = pBuffer->pNext;
  363.         }
  364.         break;
  365.  
  366.     case CM_BUFFERS_CASCADE:
  367.         pBuffer = m_pBufferDlgs;
  368.         if(pBuffer)
  369.             ResetCascade();
  370.  
  371.         while(pBuffer)
  372.         {
  373.             CascadeWindow(pBuffer->pDlg->m_hWnd);
  374.             pBuffer = pBuffer->pNext;
  375.         }
  376.         break;
  377.  
  378.     case CM_BUFFERS_CLOSEALL:
  379.         while(m_pBufferDlgs)
  380.         {
  381.             pBuffer = m_pBufferDlgs->pNext;
  382.             ::SendMessage(m_pBufferDlgs->pDlg->m_hWnd, WM_COMMAND, MAKELONG(IDCANCEL, 0), 0L);
  383.             m_pBufferDlgs = pBuffer;
  384.         }
  385.         EnableMenuItem(GetMenu(m_hWnd), 1, MF_BYPOSITION|MF_GRAYED);
  386.         DrawMenuBar(m_hWnd);
  387.         break;
  388.  
  389.     case CM_HELP_ABOUT:
  390.         AboutBox(m_hWnd, m_pApp->GetInstance());
  391.         break;
  392.     }
  393.     return 0;
  394. }
  395.  
  396. void MainWnd::DestroyChild(HWND hwndChild)
  397. {
  398.     BufferList* pBuffer = m_pBufferDlgs;
  399.     BufferList* pPrev = NULL;
  400.     
  401.     while(pBuffer)
  402.     {
  403.         if(pBuffer->pDlg->m_hWnd == hwndChild)    // Here it is
  404.         {
  405.             if(pBuffer == m_pBufferDlgs)
  406.                 m_pBufferDlgs = m_pBufferDlgs->pNext;
  407.             if(pPrev)
  408.                 pPrev->pNext = pBuffer->pNext;
  409.             delete pBuffer->pDlg;
  410.             delete pBuffer;                // Not our job to destroy the actual object
  411.  
  412.             pBuffer = NULL;
  413.             pBuffer = NULL;
  414.         }
  415.         else                            // On to the next entry
  416.         {
  417.             pPrev = pBuffer;
  418.             pBuffer = pBuffer->pNext;
  419.         }
  420.     }
  421. }
  422.  
  423. void MainWnd::Invalidate(bool bErase)
  424. {
  425.     if(m_hWnd)
  426.     {
  427.         RECT rc;
  428.         GetClientRect(m_hWnd, &rc);
  429.         InvalidateRect(m_hWnd, &rc, bErase ? TRUE : FALSE);
  430.     }
  431. }
  432.  
  433. int    MainWnd::MessageBox(LPCSTR message, LPCSTR pCaption, UINT uStyle) const
  434. {
  435.     return ::MessageBox(m_hWnd, message, pCaption, uStyle);
  436. }
  437.  
  438. void MainWnd::ResetCascade()
  439. {
  440.     POINT   ptParent;
  441.  
  442.     ptParent.x = ptParent.y = 0;
  443.     ClientToScreen(m_hWnd, &ptParent);
  444.     m_xNextPos = ptParent.x;
  445.     m_yNextPos = ptParent.y;
  446. }
  447.  
  448. void MainWnd::CascadeWindow(HWND hWnd)
  449. {
  450.     RECT    rc;
  451.     int        nStep;
  452.  
  453.     // Don't move minimized windows
  454.     if(IsIconic(hWnd))
  455.         return;
  456.  
  457.     GetWindowRect(hWnd, &rc);
  458.  
  459.     if(m_xNextPos+(rc.right-rc.left) > GetSystemMetrics(SM_CXSCREEN))
  460.         ResetCascade();
  461.     else if(m_yNextPos+(rc.bottom-rc.top) > GetSystemMetrics(SM_CYSCREEN))
  462.         ResetCascade();
  463.  
  464.     SetWindowPos(hWnd, NULL, m_xNextPos, m_yNextPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  465.     // Move diagonally by the height of the title bar
  466.     nStep = GetSystemMetrics(SM_CYCAPTION);
  467.     m_xNextPos += nStep;
  468.     m_yNextPos += nStep;
  469. }
  470.  
  471. /////////////////////// MainWnd protected member functions /////////////////////////////////////////
  472.  
  473. bool MainWnd::Register()
  474. {
  475.     WNDCLASS wc;
  476.  
  477.     if(!GetClassInfo(m_pApp->GetInstance(), GetClassName(), &wc)) 
  478.     {
  479.         GetWindowClass(wc);
  480.         return ::RegisterClass(&wc) ? true : false;
  481.     }
  482.     return true;
  483. }
  484.  
  485. bool MainWnd::OpenFile(LPTSTR lpszPath)
  486. {
  487.     TCHAR            szFileName[MAX_PATH];
  488.     LPTSTR            lpszFileName;
  489.     int                nFileIndex;
  490.     BufferListEntry    pBuffer;
  491.  
  492.     PTRACE("MainWnd::OpenFile(%s)", lpszPath);
  493.  
  494.     if(m_dsCaps.dwFreeHw3DStaticBuffers <= 0)
  495.     {
  496.         MessageBox("No more 3D buffers available for ZoomFX", GetCaption(), MB_ICONSTOP|MB_OK);
  497.         return false;
  498.     }
  499.  
  500.     if(lpszPath != NULL)
  501.     {
  502.         lpszFileName = strrchr(lpszPath, '\\');
  503.         if(lpszFileName == NULL)
  504.             nFileIndex = 0;
  505.         else
  506.             nFileIndex =  lpszFileName-lpszPath+sizeof(TCHAR);
  507.         lstrcpy(szFileName, lpszPath);
  508.     }
  509.     else
  510.     {
  511.         if(!OpenFileDialog(szFileName, &nFileIndex))
  512.             return false;
  513.     }
  514.     if(m_pListenerDlg == NULL)            // This is the first buffer
  515.     {
  516.         ResetCascade();
  517.  
  518.         m_pListenerDlg = new ListenerDlg;
  519.         if(m_pListenerDlg == NULL)
  520.         {
  521.             MessageBox("Cannot create listener dialog object", GetCaption(), MB_ICONSTOP|MB_OK);
  522.             return false;
  523.         }
  524.         if(!m_pListenerDlg->Create(m_pApp, m_pListener))
  525.             return false;
  526.     }
  527.     pBuffer = new BufferList;
  528.     if(pBuffer == NULL)
  529.     {
  530.         MessageBox("No memory for buffer", GetCaption(), MB_ICONSTOP|MB_OK);
  531.         return false;
  532.     }
  533.     pBuffer->pDlg = new BufferDlg;
  534.     if(pBuffer->pDlg == NULL)
  535.     {
  536.         MessageBox("No memory for dialog", GetCaption(), MB_ICONSTOP|MB_OK);
  537.         return false;
  538.     }
  539.     if(!pBuffer->pDlg->Create(m_pApp, szFileName, m_pDirectSound))
  540.     {
  541.         MessageBox("Unable to create buffer", GetCaption(), MB_ICONSTOP|MB_OK);
  542.         return false;
  543.     }
  544.  
  545.     pBuffer->pNext = m_pBufferDlgs;
  546.     m_pBufferDlgs = pBuffer;
  547.  
  548.     EnableMenuItem(GetMenu(m_hWnd), 1, MF_BYPOSITION);
  549.     DrawMenuBar(m_hWnd);
  550.  
  551.     return true;
  552. }
  553.  
  554. bool MainWnd::OpenFileDialog(LPTSTR pszFileName, int* pnFileName)
  555. {
  556.     bool            fReturn;
  557.     OPENFILENAME    ofn;
  558.  
  559.     pszFileName[0]          = 0;
  560.     ofn.lStructSize         = sizeof(ofn);
  561.     ofn.hwndOwner           = m_hWnd;
  562.     ofn.hInstance           = m_pApp->GetInstance();
  563.     ofn.lpstrFilter         = "Wave Files\0*.wav\0All Files\0*.*\0\0";
  564.     ofn.lpstrCustomFilter   = NULL;
  565.     ofn.nMaxCustFilter      = 0;
  566.     ofn.nFilterIndex        = 1;
  567.     ofn.lpstrFile           = pszFileName;
  568.     ofn.nMaxFile            = MAX_PATH;
  569.     ofn.lpstrFileTitle      = NULL;
  570.     ofn.nMaxFileTitle       = 0;
  571.     ofn.lpstrInitialDir     = /*grs.szInitialDir*/NULL;
  572.     ofn.lpstrTitle          = "File Open";
  573.     ofn.Flags               = OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_HIDEREADONLY;
  574.     ofn.nFileOffset         = 0;
  575.     ofn.nFileExtension      = 0;
  576.     ofn.lpstrDefExt         = "wav";
  577.     ofn.lCustData           = 0;
  578.     ofn.lpfnHook            = NULL;
  579.     ofn.lpTemplateName      = NULL;
  580.  
  581.     fReturn = GetOpenFileName(&ofn) ? true : false;
  582.  
  583.     return fReturn;
  584. }
  585.  
  586. void MainWnd::DestroyWindow(int)
  587. {
  588.     if(m_pListenerDlg)
  589.     {
  590.         delete m_pListenerDlg;
  591.         m_pListenerDlg = NULL;
  592.     }
  593.     if(m_dwTimer)
  594.     {
  595.         KillTimer(m_hWnd, m_dwTimer);
  596.         m_dwTimer = 0;
  597.     }
  598.  
  599.     if(m_hWnd)
  600.         ::DestroyWindow(m_hWnd);
  601.  
  602.     RELEASE(m_pListener)
  603.     RELEASE(m_pPrimary)
  604.     RELEASE(m_pDirectSound)
  605.  
  606.     if(m_hbmZoomFX)
  607.     {
  608.         DeleteObject(m_hbmZoomFX);
  609.         m_hbmZoomFX = NULL;
  610.     }
  611. }
  612.  
  613. void MainWnd::CloseWindow(int ret)
  614. {
  615.     DestroyWindow(ret);
  616. }
  617.  
  618. LRESULT MainWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  619. {
  620.     switch(message) 
  621.     {
  622.     case WM_COMMAND:
  623.         return EvCommand((UINT)LOWORD (wParam), (HWND)LOWORD (lParam), (UINT) HIWORD(wParam));
  624.     
  625.     case WM_PAINT:
  626.         EvPaint();
  627.         return 0;
  628.  
  629.     case WM_DESTROY:
  630.         EvDestroy();
  631.         break;
  632.  
  633.     case WM_CLOSE:
  634.         EvClose();
  635.         return 0;
  636.  
  637.     case WM_INITMENU:
  638.         return EvInitMenu((HMENU)wParam);
  639.  
  640.     case WM_ERASEBKGND:
  641.         return EvEraseBkgnd((HDC)wParam);
  642.  
  643.     case WM_TIMER:
  644.         return EvTimer(wParam);
  645. }
  646.     return DefWindowProc(m_hWnd, message, wParam, lParam);
  647. }
  648.  
  649. void MainWnd::EvPaint()
  650. {
  651.     PAINTSTRUCT    ps;
  652.     
  653.     BeginPaint(m_hWnd, &ps);
  654.     Paint(ps.hdc, ps.rcPaint, ps.fErase ? true : false);
  655.     EndPaint(m_hWnd, &ps);
  656. }
  657.  
  658. void MainWnd::EvClose()
  659. {
  660.     CloseWindow();
  661. }
  662.  
  663. void MainWnd::EvDestroy()
  664. {
  665.     if(m_pApp)
  666.         if(m_pApp->GetMainWindow() == this)
  667.             PostQuitMessage(0);
  668.  
  669.     m_hWnd = NULL;
  670. }
  671.  
  672. LRESULT    MainWnd::EvInitMenu(HMENU hMenu)
  673. {
  674.     if(hMenu == GetMenu(m_hWnd))
  675.     {
  676.         EnableMenuItem(hMenu, CM_FILE_OPEN, MF_BYCOMMAND|(m_dsCaps.dwFreeHw3DStaticBuffers == 0 ? MF_GRAYED : 0));
  677.         DrawMenuBar(m_hWnd);
  678.     }
  679.     return 0;
  680. }
  681.  
  682. LRESULT MainWnd::EvEraseBkgnd(HDC hdc)
  683. {
  684.     HDC        hdcMem;
  685.     HGDIOBJ hbmOld;
  686.  
  687.     hdcMem = CreateCompatibleDC(hdc);
  688.     if(hdcMem == NULL)
  689.         return 0;
  690.  
  691.     hbmOld = SelectObject(hdcMem, m_hbmZoomFX);
  692.     BitBlt(hdc, 0, 0, 256, 256, hdcMem, 0, 0, SRCCOPY);
  693.  
  694.     SelectObject(hdcMem, hbmOld);
  695.     DeleteDC(hdcMem);
  696.  
  697.     return 1;
  698. }
  699.  
  700. LRESULT MainWnd::EvTimer(WORD)
  701. {
  702.     DSCAPS dsCaps;
  703.     BufferList* pBuffer;
  704.  
  705.     dsCaps.dwSize = sizeof(dsCaps);
  706.     m_pDirectSound->GetCaps(&dsCaps);
  707.     if(memcmp(&dsCaps, &m_dsCaps, sizeof(m_dsCaps)))
  708.     {
  709.         memcpy(&m_dsCaps, &dsCaps, sizeof(m_dsCaps));
  710.         Invalidate(true);
  711.     }
  712.  
  713.     pBuffer = m_pBufferDlgs;
  714.     while(pBuffer)
  715.     {
  716.         pBuffer->pDlg->Update();
  717.         pBuffer = pBuffer->pNext;
  718.     }
  719.     return 0;
  720. }
  721. /////////////////////// MainWnd private member functions ///////////////////////////////////////////
  722.  
  723. void MainWnd::InstallWindowProc()
  724. {
  725.     DWORD processId;
  726.  
  727.     if(m_hWnd) 
  728.     {
  729.         GetWindowThreadProcessId(m_hWnd, &processId);
  730.         if(processId == GetCurrentProcessId()) 
  731.             m_DefaultProc = (WNDPROC)SetWindowLong(m_hWnd, GWL_WNDPROC, (long)GetThunk());
  732.     }
  733. }
  734.  
  735. LRESULT    CALLBACK MainWnd::StdWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  736. {
  737.     MainWnd* w;
  738.  
  739.     _asm mov w, eax
  740.     return w->WindowProc(message, wParam, lParam);
  741. }
  742.