我正在使用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(¤tPos);
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 *爲雙?或者,這不是我的問題嗎?
所有的建議,更正和幫助,都會很讚賞。
塞繆爾
我會嘗試使用'char *'來代替(從一個指針類型到另一個),並使用'reinterpret_cast'而不是C風格的強制轉換。 –
@PhilBrubaker聽起來真是個好主意。謝謝!當我得到結果時,我會嘗試並更新我的問題。 :) –
@PhilBrubaker不幸的是我發現我不能這麼做,因爲在使用char *參數時,GameMaker Studio將參數限制爲3,我真的需要video_set_rectangle,它使用5個參數。 –