#include <windows.h>
#include <stdio.h>
#include <mbstring.h>
#include "kbqt_player.h"

//QTMLMutex g_qtmlMutex;
static const wchar_t g_cszQtWindowClassName[] = L"QuickTime Movie Window";

BOOL KbQtPlayer::s_bInitialized = FALSE;
BOOL KbQtPlayer::s_bQtIsInstalled = FALSE;
wchar_t KbQtPlayer::s_szClassName[128];

static void CheckSize(WPARAM wParam, LPARAM lParam, int nSliderHeight,
                     double RX, double RY)
{
    RECT    *rc;
    double  width,height;
    rc = (RECT *)lParam;

    width  = rc->right - rc->left;
    height = rc->bottom - rc->top;
    int nHeightOffset = GetSystemMetrics(SM_CYCAPTION) + ::GetSystemMetrics(SM_CYFRAME)*2;
    int nWidthOffset = ::GetSystemMetrics(SM_CXFRAME) * 2;
    width -= nWidthOffset;
    height -= nHeightOffset;
    height -= nSliderHeight;
    switch(wParam){
        case WMSZ_TOP:
        case WMSZ_BOTTOM:
            rc->right = rc->left + (int)(height*(RX/RY)) + nWidthOffset;
            break;
        case WMSZ_LEFT:
        case WMSZ_RIGHT:
            rc->bottom = rc->top + (int)(width*(RY/RX)) + nHeightOffset;
            break;
        case WMSZ_TOPLEFT:
            if((width/height)<(RX/RY)){
                rc->left = rc->right - (int)(height*(RX/RY)) - nWidthOffset;
            }else{
                rc->top = rc->bottom - (int)(width*(RY/RX)) - nHeightOffset;
            }
            break;
        case WMSZ_TOPRIGHT:
            if((width/height)<(RX/RY)){
                rc->right = rc->left + (int)(height*(RX/RY)) + nWidthOffset;
            }else{
                rc->top = rc->bottom - (int)(width*(RY/RX)) - nHeightOffset;
            }
            break;
        case WMSZ_BOTTOMLEFT:
            if((width/height)<(RX/RY)){
                rc->left = rc->right - (int)(height*(RX/RY)) - nWidthOffset;
            }else{
                rc->bottom = rc->top + (int)(width*(RY/RX)) + nHeightOffset;
            }
            break;
        case WMSZ_BOTTOMRIGHT:
            if((width/height)<(RX/RY)){
                rc->right = rc->left + (int)(height*(RX/RY)) + nWidthOffset;
            }else{
                rc->bottom = rc->top + (int)(width*(RY/RX)) + nHeightOffset;
            }
            break;
    }
    //rc->bottom += nSliderHeight;
}
///////////////////////////////////////////////////////////////////////////////
static Boolean MCFilter(MovieController mc, short action, void*params, long refCon)
{
    if(action == mcActionControllerSizeChanged) {
        Rect        bounds;
        WindowPtr   w;
        MCGetControllerBoundsRect(mc, &bounds);
        w = GetNativeWindowPort((HWND)refCon);
        SizeWindow((WindowPtr)w, bounds.right, bounds.bottom, TRUE);
        //MacSetPort((GrafPtr)w);//
    }
    return FALSE;
}
static void GetMaxBounds(Rect *maxRect)
{
    RECT deskRect;
    GetWindowRect(GetDesktopWindow(), &deskRect);
    OffsetRect(&deskRect, -deskRect.left, -deskRect.top);
    maxRect->top = (short)deskRect.top;
    maxRect->bottom = (short)deskRect.bottom;
    maxRect->left = (short)deskRect.left;
    maxRect->right = (short)deskRect.right;
}
static void CreateNewMovieController(HWND hwnd, Movie theMovie, MovieController *theMC)
{
    Rect    bounds;
    Rect    maxBounds;
    long    controllerFlags = 0;
    Rect    theMovieRect;
    // 0,0 Movie coordinates
    GetMovieBox(theMovie, &theMovieRect);
    MacOffsetRect(&theMovieRect, -theMovieRect.left, -theMovieRect.top);
    // Attach a movie controller
    *theMC = NewMovieController(theMovie, &theMovieRect, mcTopLeftMovie );
    // Get the controller rect
    MCGetControllerBoundsRect(*theMC, &bounds);
    // Enable editing
    MCEnableEditing(*theMC, FALSE);
    // Tell the controller to attach a movie's CLUT to the window as appropriate.
    MCDoAction(*theMC, mcActionGetFlags, &controllerFlags);
    controllerFlags |= mcFlagsUseWindowPalette;
    controllerFlags |= mcFlagSuppressMovieFrame;
    controllerFlags |= mcFlagSuppressStepButtons;
    controllerFlags |= mcFlagSuppressSpeakerButton;
    //mcFlagSuppressMovieFrame    = 1 << 0,
    //mcFlagSuppressStepButtons   = 1 << 1,
    //mcFlagSuppressSpeakerButton = 1 << 2,
    MCDoAction(*theMC, mcActionSetFlags, (void *)controllerFlags);
    BOOL b = FALSE;
    MCDoAction(*theMC, mcActionSetDragEnabled, (void *)FALSE);
    // Allow the controller to accept keyboard events
    MCDoAction(*theMC, mcActionSetKeysEnabled, (void *)FALSE);
    // Set the controller action filter
    MCSetActionFilterWithRefCon(*theMC, MCFilter, (long)hwnd);
    //MCSetActionFilterWithRefCon(*theMC, MCFilter, (long)0);
    // Set the grow box amound
    GetMaxBounds(&maxBounds);
    MCDoAction(*theMC, mcActionSetGrowBoxBounds, &maxBounds);
    // Size our window
    SizeWindow((WindowPtr)GetNativeWindowPort(hwnd), bounds.right, bounds.bottom, FALSE);
    //MCSetVisible(*theMC, FALSE);
}
// Data held in each child movie window
LRESULT CALLBACK KbQtPlayer::QtMovWindowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    DWORD_PTR dwThis = GetWindowLongPtr(hWnd, GWLP_USERDATA);
    KbQtPlayer *QtPlayer = (KbQtPlayer*)dwThis;
    //QTMLGrabMutex(g_qtmlMutex);
    if(GetNativeWindowPort(hWnd)){
        MSG msg;
        EventRecord macEvent;
        ZeroMemory(&macEvent, sizeof(macEvent));
        LONG thePoints = GetMessagePos();
        msg.hwnd = hWnd;
        msg.message = message;
        msg.wParam = wParam;
        msg.lParam = lParam;
        msg.time = GetMessageTime();
        msg.pt.x = LOWORD(thePoints);
        msg.pt.y = HIWORD(thePoints);
        long ret = WinEventToMacEvent(&msg, &macEvent);  // Convert the message to a QTML event
        // if we have a Movie Controller, pass the QTML event
        MovieController theMC;
        if(QtPlayer)
            theMC = QtPlayer->m_theMC;
        else{
            theMC = 0;
        }

        if(message == WM_LBUTTONDOWN){
            if(theMC){
                int yPos = HIWORD(lParam);
                int xPos = LOWORD(lParam);
                Rect bounds;
                bounds.left = bounds.top = bounds.right = bounds.bottom = 0;
                MCDoAction(theMC, mcActionGetTimeSliderRect, &bounds);
                if(bounds.top <= yPos){
                    if(xPos < bounds.right){
                    //描画領域と右下の（変な領域）のクリックは受けつけない
                        QTMLYieldCPU();
                        MCIsPlayerEvent(theMC,(const EventRecord *)&macEvent);
                    }
                }
            }
        }
        else if(theMC){
            //try{
            QTMLYieldCPU();
            MCIsPlayerEvent(theMC,(const EventRecord *)&macEvent);
            //}
            //catch(...){
            //   _fpreset();
            //}
        }
    }
    switch (message) {
        case WM_CREATE:
            break;
        case WM_DESTROY:
            break;
        case WM_CLOSE:
            ShowWindow(hWnd, SW_HIDE);
            return 0;
            break;
        //case WM_PAINT:
        //    break;
        case WM_SIZING:
        {
            if(!QtPlayer){
                break;
            }
            if(!QtPlayer->m_MediaInfo.dwVideoWidth||
               !QtPlayer->m_MediaInfo.dwVideoHeight){
                break;
            }
            CheckSize(wParam, lParam, QtPlayer->m_nSliderHeight,
                      QtPlayer->m_MediaInfo.dwVideoWidth,  QtPlayer->m_MediaInfo.dwVideoHeight);
            break;
        }
        case WM_SIZE:
        {
            if(!QtPlayer){
                break;
            }
            Rect bounds;
            int nWidth = LOWORD(lParam);
            int nHeight = HIWORD(lParam);
            MCGetControllerBoundsRect(QtPlayer->m_theMC, &bounds);
            bounds.right = bounds.left + nWidth;
            bounds.bottom = bounds.top + nHeight;// + QtPlayer->m_nSliderHeight;
            MCSetControllerBoundsRect(QtPlayer->m_theMC, &bounds);
            break;
        }
        default:
            break;
    }
    //QTMLReturnMutex(g_qtmlMutex);
    return (DefWindowProc(hWnd,message,wParam,lParam));
}
///////////////////////////////////////////////////////////////////////////////
//KbQtPlayer
///////////////////////////////////////////////////////////////////////////////
KbQtPlayer::KbQtPlayer(void)
{
    m_bTopMost = FALSE;
    kpi_InitMediaInfo(&m_MediaInfo);
    m_pFile = NULL;
    m_theMovie = 0;
    m_theMC = 0;
    m_hWnd = 0;
    m_nStatus = KPI_STATUS_STOP;
    m_nTempo = 100;
    m_nVolume = 100;

}
///////////////////////////////////////////////////////////////////////////////
KbQtPlayer::~KbQtPlayer(void)
{
    Stop();
    if(m_theMovie){
        volatile MovieController theMC = m_theMC;
        m_theMC = NULL;
        MCRemoveAMovie(theMC, m_theMovie);
        DisposeMovieController(theMC);
        DisposeMovie(m_theMovie);
        m_theMovie = 0;
        DestroyPortAssociation((CGrafPtr)GetNativeWindowPort(m_hWnd));
        DestroyWindow(m_hWnd);
    }
    if(m_pFile){
        m_pFile->Release();
    }
}
///////////////////////////////////////////////////////////////////////////////
BOOL __fastcall KbQtPlayer::Open(IKpiFile *pFile, IKpiFolder *pFolder)
{
    InitQt();
    if(!s_bQtIsInstalled){
        return false;
    }
    const char *cszFileNameA = NULL;
    if(!pFile->GetRealFileA(&cszFileNameA)){
        return false;
    }
    TimeRecord tr;
    FSSpec fileSpec;
    OSErr err;
    short movieRefNum=0, movieResId=0;
    Movie  theMovie=0;
    MovieController theMC=0;
    HWND hWnd=NULL;
    wchar_t szCaption[MAX_PATH];
    pFile->GetFileName(szCaption, sizeof(szCaption));
    hWnd = CreateWindowEx(0,//WS_EX_APPWINDOW,
                          s_szClassName,
                          szCaption,
                          WS_OVERLAPPEDWINDOW,
                            //WS_SYSMENU|WS_MINIMIZEBOX|
                          //WS_OVERLAPPED|WS_CLIPCHILDREN,
                          0,0,//s_nPrevPosX, s_nPrevPosY,
                          0, 0,
                          NULL,//ghWnd,
                          NULL,
                          GetModuleHandle(NULL),
                          NULL) ;
    ShowWindow(hWnd, SW_HIDE);
    UpdateWindow(hWnd);
    // Create the movie window
    CreatePortAssociation(hWnd, 0, 0L);
    //MacSetPort(GetHWNDPort(hWnd));
    SetGWorld((CGrafPtr)GetNativeWindowPort((void *)hWnd), NULL);

    //c2pstr((char*)cszFileName);
    //FSMakeFSSpec(0,0L,(const unsigned char*)cszFileName, &fileSpec);
    ZeroMemory(&fileSpec, sizeof(fileSpec));
    //fileSpec.vRefNum = 0;
    //fileSpec.parID = 0;
    _mbsncpy_s(&fileSpec.name[1], _countof(fileSpec.name)-1, (unsigned char*)cszFileNameA, _TRUNCATE);
    fileSpec.name[0] = strlen((const char*)&fileSpec.name[1]);
    err = OpenMovieFile(&fileSpec, &movieRefNum, fsRdPerm);
    if(!err){
        movieResId = 0;
        err = NewMovieFromFile(&theMovie, movieRefNum, &movieResId, NULL,newMovieActive,NULL);
        CloseMovieFile(movieRefNum);
    }

    if (err) goto bail;
    // Open up the movie file...
    // Fill in a FSSpec.  Currently the vRefNum and parID are not used under Windows.
    // Note the name must be a full pathname P-string!
    // Offset the movie box to (0,0)
    CreateNewMovieController(hWnd, theMovie, &theMC);
    m_theMovie = theMovie;
    m_theMC = theMC;
    m_hWnd = hWnd;
    DWORD dwLength = GetMovieDuration(theMovie);
    GetMovieTime(theMovie, &tr);
    if(tr.scale != 0){
        m_MediaInfo.qwLength = (UINT64)dwLength*1000*10000/tr.scale;
    }
    else{
        m_MediaInfo.qwLength = 0;
    }
    SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)this);
    StopMovie(theMovie);
    Rect rcMovie;
    Rect rcSlider;
    // 0,0 Movie coordinates
    GetMovieBox(theMovie, &rcMovie);
    m_MediaInfo.dwVideoWidth = rcMovie.right-rcMovie.left;
    m_MediaInfo.dwVideoHeight= rcMovie.bottom-rcMovie.top;;
    m_MediaInfo.dwCount = 1;
    m_MediaInfo.dwNumber = 1;
    m_MediaInfo.dwFormatType = KPI_MEDIAINFO::FORMAT_PLAYER;
    m_pFile = pFile;
    pFile->AddRef();
    MCDoAction(m_theMC, mcActionGetTimeSliderRect, &rcSlider);
    m_nSliderHeight = rcSlider.bottom - rcSlider.top;
    return TRUE;
bail:
    if(theMovie) DisposeMovie(theMovie);
    if(theMC) DisposeMovieController(theMC);
    if(hWnd){
        DestroyPortAssociation((CGrafPtr)GetNativeWindowPort(hWnd));
        DestroyWindow(hWnd);
    }
    return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbQtPlayer::Select(DWORD dwNumber,
                                 const KPI_MEDIAINFO **ppMediaInfo,
                                 IKpiTagInfo *pTagInfo,
                                 DWORD dwTagGetFlags)
{
    if(ppMediaInfo){
        *ppMediaInfo = NULL;
    }
    if(dwNumber > m_MediaInfo.dwCount){
        return 0;
    }
    if(!ppMediaInfo){
        return 1;
    }
    *ppMediaInfo = &m_MediaInfo;
    return 1;
}
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbQtPlayer::GetPosition(void)
{
    if(m_nStatus == KPI_STATUS_STOP){
        return 0;
    }
    int ret = 0;
    //QTMLGrabMutex(g_qtmlMutex);
    if(m_theMovie){
        TimeRecord tr;
        ZeroMemory(&tr, sizeof(tr));
        ret = GetMovieTime(m_theMovie, &tr);
        if(tr.scale != 0){
            ret = ret*1000/tr.scale;
        }
    }
    //QTMLReturnMutex(g_qtmlMutex);
    return ret;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KbQtPlayer::Play(DWORD dwStartPos, BOOL bVisible)
{
    if(m_theMovie){
        //HWND hWndActive = GetActiveWindow();
        StopMovie(m_theMovie);
        if(dwStartPos == 0){
            GoToBeginningOfMovie(m_theMovie);
        }
        else{
            TimeRecord tr;
            ZeroMemory(&tr, sizeof(tr));
            tr.value.lo = dwStartPos;
            tr.value.hi = 0;
            GetMovieTime(m_theMovie, &tr);
            if(tr.scale != 0){
                double d = dwStartPos*tr.scale/1000.0;
                dwStartPos = (DWORD)d;
                if((int)dwStartPos < 0)
                    dwStartPos = 0;
            }
            else{
                dwStartPos = 0;
            }
            SetMovieTimeValue(m_theMovie, dwStartPos);
        }
        int nCmdShow;
        if(bVisible)
            nCmdShow = SW_SHOWNOACTIVATE;
        else
            nCmdShow = SW_HIDE;
        if(m_MediaInfo.dwVideoWidth == 0 ||
           m_MediaInfo.dwVideoHeight == 0){
            nCmdShow = SW_HIDE;
        }
        ShowWindow(m_hWnd, nCmdShow);
        m_nStatus = KPI_STATUS_PLAYING;
        SetTempo(m_nTempo);
    }
    return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KbQtPlayer::Pause(void)
{
    if(m_theMovie){
        StopMovie(m_theMovie);
        m_nStatus = KPI_STATUS_PAUSE;
    }
    return true;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI KbQtPlayer::Restart(void)
{
    if(m_hWnd){
        Play(GetPosition(), IsWindowVisible(m_hWnd));
    }
    return true;
}
///////////////////////////////////////////////////////////////////////////////
void WINAPI KbQtPlayer::Stop(void)
{
    if(m_theMovie){
        StopMovie(m_theMovie);
    }
    m_nStatus = KPI_STATUS_STOP;
}
///////////////////////////////////////////////////////////////////////////////
DWORD WINAPI KbQtPlayer::GetStatus(void)
{
    //QTMLGrabMutex(g_qtmlMutex);
    if(m_theMovie){
        if(IsMovieDone(m_theMovie)){
            m_nStatus = KPI_STATUS_STOP;
        }
    }
    //QTMLReturnMutex(g_qtmlMutex);
    return m_nStatus;
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbQtPlayer::SetTempo(int Tempo)
{
    if(m_theMovie && m_nStatus == KPI_STATUS_PLAYING){
        int rate;
        rate = 65536*Tempo/100;
        SetMovieRate(m_theMovie, rate);
    }
    m_nTempo = Tempo;
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbQtPlayer::SetVolume(int Vol)
{
    if(0 <= Vol && Vol <= 100){
        m_nVolume = Vol;
        Vol = 256*Vol/100;
        if(m_theMovie){
            //return;
            SetMovieVolume(m_theMovie, Vol);
        }
    }
}
///////////////////////////////////////////////////////////////////////////////
void WINAPI KbQtPlayer::SetVisible(BOOL bVisible)
{
    int nStatus = GetStatus();
    if(!bVisible || nStatus == KPI_STATUS_PLAYING || nStatus == KPI_STATUS_PAUSE){
        if(m_hWnd){
            int nCmd;
            if(bVisible){
                nCmd = SW_SHOWNOACTIVATE;
            }
            else{
                nCmd = SW_HIDE;
            }
            ShowWindow(m_hWnd, nCmd);
        }
    }
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbQtPlayer::SetTopMost(BOOL bTopMost)
{
    m_bTopMost = bTopMost;
    if(m_hWnd){
        HWND f;
        if(bTopMost){
            f = HWND_TOPMOST;
        }
        else{
            f= HWND_NOTOPMOST;
        }
        ::SetWindowPos(m_hWnd, f, 0, 0,0,0,SWP_NOMOVE|SWP_NOSIZE);
        //::SetForegroundWindow(m_hWnd);
    }
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbQtPlayer::GetWindowPosition(int *pLeft,  int *pTop,
                                           int *pVideoWidth, int *pVideoHeight)
{
    if(m_hWnd){
        WINDOWPLACEMENT wp;//最大化していないときのウィンドウサイズ
        wp.length = sizeof(WINDOWPLACEMENT);
        GetWindowPlacement(m_hWnd, &wp);
        RECT rect;
        // デスクトップ作業領域を取得
        SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);
        OffsetRect(&wp.rcNormalPosition, rect.left, rect.top);
        *pLeft = wp.rcNormalPosition.left;
        *pTop =  wp.rcNormalPosition.top;
        *pVideoWidth = wp.rcNormalPosition.right - wp.rcNormalPosition.left - GetSystemMetrics(SM_CXFRAME) * 2;
        *pVideoHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top - (GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME) * 2);
    }
    else{
        *pLeft = 0;
        *pTop = 0;
        *pVideoWidth = 0;
        *pVideoHeight = 0;
    }
}
///////////////////////////////////////////////////////////////////////////////
void  WINAPI KbQtPlayer::SetWindowPosition(int nLeft, int nTop,
                                           int nWidth, int nHeight)
{
    if(!m_theMC || !m_hWnd){
        return;
    }
    if(m_MediaInfo.dwVideoWidth && m_MediaInfo.dwVideoHeight){
        int nHeightOffset = ::GetSystemMetrics(SM_CYCAPTION) + 
                            ::GetSystemMetrics(SM_CYFRAME)*2 +
                            m_nSliderHeight;
        int nWidthOffset = ::GetSystemMetrics(SM_CXFRAME)*2;
        nHeight += nHeightOffset;
        nWidth += nWidthOffset;
    }
    SetWindowPos(m_hWnd, HWND_TOP, nLeft, nTop, nWidth, nHeight, 0);
}
///////////////////////////////////////////////////////////////////////////////
void KbQtPlayer::InitQt(void)
{
    if(!s_bInitialized){
        s_bInitialized = 1;
        //QuickTime6 の環境で DirectDraw を明示的に無効にすると
        //正常動作しなくなる（落ちる）データがある
        //N:\Movie\FF\commercial2.mov など
#if 0
enum {
    kInitializeQTMLNoSoundFlag  = (1L << 0),                    /* flag for requesting no sound when calling InitializeQTML*/
    kInitializeQTMLUseGDIFlag   = (1L << 1),                    /* flag for requesting GDI when calling InitializeQTML*/
    kInitializeQTMLDisableDirectSound = (1L << 2),              /* disables QTML's use of DirectSound*/
    kInitializeQTMLUseExclusiveFullScreenModeFlag = (1L << 3),  /* later than QTML 3.0: qtml starts up in exclusive full screen mode*/
    kInitializeQTMLDisableDDClippers = (1L << 4)                /* flag for requesting QTML not to use DirectDraw clipper objects; QTML 5.0 and later*/
};
#endif
        int flag = //kInitializeQTMLUseGDIFlag | // DirectDraw 無効
                   //kInitializeQTMLDisableDirectSound |// DirectSound 無効
                   //kInitializeQTMLDisableDDClippers|
                   0;
        OSErr err = InitializeQTML(flag);// Initialize QuickTime Media Layer
        EnterMovies();// Initialize QuickTime
        LARGE_INTEGER counter = {0};
        QueryPerformanceCounter(&counter);
        _snwprintf_s(s_szClassName, sizeof(s_szClassName) / sizeof(s_szClassName[0]),
                     _TRUNCATE, L"%s%08x:%016llx",
                     g_cszQtWindowClassName, GetCurrentThreadId(), counter.QuadPart);
        WNDCLASSEX  wc;
        wc.cbSize       = sizeof(wc);
        wc.style        = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc  = QtMovWindowProc;
        wc.cbClsExtra   = 0;
        wc.cbWndExtra   = 0;
        wc.hInstance    = GetModuleHandle(NULL);
        wc.hIcon        = ::LoadIcon(NULL, IDI_WINLOGO);
        wc.hCursor      = ::LoadCursor(NULL, IDC_ARROW);
        wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
        wc.lpszMenuName = NULL;
        wc.lpszClassName= s_szClassName;
        wc.hIconSm      = NULL;//::LoadIcon(NULL, IDI_WINLOGO);
        RegisterClassEx(&wc);
        s_bQtIsInstalled = (err == noErr);
    }
}
///////////////////////////////////////////////////////////////////////////////
void KbQtPlayer::DeinitQt(void)
{
    if(s_bInitialized){
        // Deinitialize QuickTime Media Layer
        ExitMovies();
        TerminateQTML();
        UnregisterClassW(s_szClassName, GetModuleHandle(NULL));
        s_bInitialized = FALSE;
        s_bQtIsInstalled = FALSE;
        s_szClassName[0] = 0;
    }
}
///////////////////////////////////////////////////////////////////////////////
