2017-07-17 129 views
0

我正在使用DLL爲GameMaker Studio創建擴展。 GameMaker Studio僅支持void,char *或double函數返回類型。至於參數,只支持char *和double。這意味着我必須將我需要的所有其他類型轉換爲其中一種類型。DirectShow - 將IGraphBuilder *轉換爲雙精度(C++)

問題是,我不確定我是否以最好的方式去解決問題。當試圖通過標題欄拖動DirectShow所有者窗口時,會出現非常奇怪的行爲。嵌入式視頻不隨父窗口移動;它保持在相同的位置。

這只是窗口暫停或停止時的問題。當視頻正在播放時,DirectShow窗口隨其父窗口一起移動。但我希望用戶能夠暫停和停止視頻,所以我需要修復這個問題。這裏是我的DLL的代碼:

#include <windows.h> 
#include <DShow.h> 

#define DLL extern "C" _declspec(dllexport) 
using namespace std; 

wchar_t *convertCharArrayToLPCWSTR(const char* charArray) { 
    wchar_t* wString = new wchar_t[4096]; 
    MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096); 
    return wString; 
} 

DLL double video_init() { 
    if(FAILED(CoInitialize(NULL))){ 
     MessageBox(NULL,L"Failed to initialize COM library.",L"ERROR", MB_ICONERROR | MB_OK); 
     return false; 
    } 

    return true; 
} 

DLL void video_uninit() { 
    CoUninitialize(); 
} 

DLL double video_add(HWND window, char *fname) { 
    IGraphBuilder *pGraph = NULL; 
    HRESULT hr = S_OK; 

    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); 

    hr = pGraph->RenderFile(convertCharArrayToLPCWSTR(fname), NULL); 
    if(FAILED(hr)) return NULL; 

    IVideoWindow *pVidWin = NULL; 
    hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin); 

    hr = pVidWin->put_Owner((OAHWND)window); 
    hr = pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS); 
    pVidWin->Release(); 

    IMediaControl *pControl = NULL; 
    hr = pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl); 
    hr = pControl->Run(); 
    hr = pControl->Pause(); 

    pControl->Release(); 

    return (double)(DWORD)(void *)pGraph; 
} 

DLL void video_start(double video) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IMediaControl *pControl = NULL; 
    HRESULT hr = S_OK; 

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl); 
    hr = pControl->Run(); 
    pControl->Release(); 
} 

DLL void video_stop(double video) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IMediaControl *pControl = NULL; 
    IMediaSeeking *pSeek = NULL; 
    REFERENCE_TIME stoptime = 0; 
    HRESULT hr = S_OK; 

    hr = pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl); 

    OAFilterState fs; 
    hr = pControl->GetState(100,&fs); 

    switch(fs){ 
    case State_Running: 
     hr = pControl->Pause(); 

    case State_Paused: 
     pGraph->QueryInterface(IID_IMediaSeeking,(void**)&pSeek); 
     hr = pSeek->SetPositions(&stoptime,AM_SEEKING_AbsolutePositioning,0,AM_SEEKING_NoPositioning); 
    } 

    pControl->Release(); 
    pSeek->Release(); 
} 

DLL void video_pause(double video) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IMediaControl *pControl = NULL; 
    HRESULT hr = S_OK; 

    pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl); 
    hr = pControl->Pause(); 
    pControl->Release(); 
} 

DLL void video_delete(double video) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    pGraph->Release(); 
} 

DLL void video_set_rectangle(double video,double x,double y,double w,double h) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IVideoWindow *pVidWin = NULL; 
    HRESULT hr = S_OK; 

    hr = pGraph->QueryInterface(IID_IVideoWindow,(void**)&pVidWin); 
    hr = pVidWin->SetWindowPosition((long)x, (long)y, (long)w, (long)h); 
    pVidWin->Release(); 
} 

DLL double video_is_playing(double video) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IMediaControl *pControl = NULL; 
    IMediaPosition *pPos = NULL; 
    HRESULT hr = S_OK; 

    hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); 

    OAFilterState fs; 
    hr = pControl->GetState(100, &fs); 

    switch (fs){ 
    case State_Running: 

     pGraph->QueryInterface(IID_IMediaPosition, (void**)&pPos); 

     REFTIME currentPos; 
     hr = pPos->get_CurrentPosition(&currentPos); 

     REFTIME duration; 
     hr = pPos->get_Duration(&duration); 

     if (currentPos < duration) { 

      return true; 
     } 
     else { 

      video_stop(video); 
      return false; 
     } 

    case State_Paused: 
     return false; 

    case State_Stopped: 
     return false; 
    } 

    pControl->Release(); 
    pPos->Release(); 

    return false; 
} 

DLL double video_is_cursor_hidden(double video) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IVideoWindow *pVidWin = NULL; 
    HRESULT hr = S_OK; 

    hr = pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVidWin); 

    long hidden; 
    hr = pVidWin->IsCursorHidden(&hidden); 

    if (hidden == OATRUE) { 
     return true; 
    } else { 
     return false; 
    } 

    pVidWin->Release(); 
} 

DLL void video_hide_cursor(double video, double hide) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IVideoWindow *pVidWin = NULL; 
    HRESULT hr = S_OK; 

    hr = pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVidWin); 

    if (hide == (double)true) { 
     hr = pVidWin->HideCursor(OATRUE); 
    } 
    else { 
     hr = pVidWin->HideCursor(OAFALSE); 
    } 

    pVidWin->Release(); 
} 

DLL void video_set_foreground(double video, double focus) { 
    IGraphBuilder *pGraph = (IGraphBuilder *)(DWORD)video; 
    IVideoWindow *pVidWin = NULL; 
    HRESULT hr = S_OK; 

    hr = pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVidWin); 

    if (focus == (double)true) { 
     hr = pVidWin->SetWindowForeground(OATRUE); 
    } 
    else { 
     hr = pVidWin->SetWindowForeground(OAFALSE); 
    } 

    pVidWin->Release(); 
} 

DLL void video_update(HWND window) { 

    if (!(GetWindowLong(window, GWL_STYLE) & WS_CLIPCHILDREN)) { 
     SetWindowLong(window, GWL_STYLE, 
      GetWindowLong(window, GWL_STYLE) | WS_CLIPCHILDREN); 
    } 
} 

我將提供調用該DLL和所有的GameMaker Studio代碼,但我嚴重懷疑我會遇到一個GameMaker Studio用戶在這裏。這是我能做的最好的。我不知道這是什麼原因造成了這個問題,但是我想我正在投射這些類型的原因是它爲什麼會表現得很時髦。爲了IGraphBuilder *轉換爲雙作爲返回值,我鑄像這樣:

return (double)(DWORD)(void *)pGraph; 

我也試過:

return (double)(DWORD)pGraph; 

兩個給我同樣的上述問題。

至於論據,我鑄造這樣的:

(double)(DWORD)pGraph 

我應該如何鑄造IGraphBuilder *爲雙?或者,這不是我的問題嗎?

所有的建議,更正和幫助,都會很讚賞。

塞繆爾

+0

我會嘗試使用'char *'來代替(從一個指針類型到另一個),並使用'reinterpret_cast'而不是C風格的強制轉換。 –

+0

@PhilBrubaker聽起來真是個好主意。謝謝!當我得到結果時,我會嘗試並更新我的問題。 :) –

+0

@PhilBrubaker不幸的是我發現我不能這麼做,因爲在使用char *參數時,GameMaker Studio將參數限制爲3,我真的需要video_set_rectangle,它使用5個參數。 –

回答

2

決不蒙上了指針(DWORD),它將截斷指針,如果你編譯代碼爲64位!如果必須,請使用指針大小的整數類型,如SIZE_T,UINT_PTR或DWORD_PTR。

char*是您可用的最佳類型,並保證與其他指針類型ABI兼容。

double是有問題的,因爲它的大小可能與指針的大小不匹配,並且它傳遞到64位Windows程序的不同CPU寄存器中。

+0

你可以給我一個代碼片段,以便在IGraphBuilder *和char *之間轉換嗎?我試過reinterpret_cast,我認爲我做錯了,因爲它使我的程序崩潰。 –

+0

somefunction((char *)pMyBuilder);但另一方必須將其視爲IGraphBuilder *顯然! – Anders

+0

我已經試過了,它在應用程序窗口打開時立即崩潰 –