简体   繁体   English

DirectShow-将IGraphBuilder *转换为double(C ++)

[英]DirectShow - convert IGraphBuilder * to double (C++)

I am creating an extension for GameMaker Studio using a DLL. 我正在使用DLL为GameMaker Studio创建扩展。 GameMaker Studio only supports function return types that are either void, char *, or double. GameMaker Studio仅支持void,char *或double的函数返回类型。 As for arguments, only char * and double are supported. 至于参数,仅支持char *和double。 This means I have to convert all other types I need to one of those types. 这意味着我必须将我需要的所有其他类型转换为这些类型之一。

The problem is, I'm not sure if I'm going about it in the best way. 问题是,我不确定是否要以最佳方式进行处理。 When trying to drag the DirectShow owner window by the title bar, very strange behavior occurs. 当试图通过标题栏拖动DirectShow所有者窗口时,会发生非常奇怪的行为。 The embedded video does not move with the parent window; 嵌入式视频不会随父窗口移动; it stays in the same position. 它保持在相同的位置。

This is only an issue when the window is either paused or stopped. 仅当窗口暂停或停止时这才是问题。 When the video is currently playing, the DirectShow window moves with its parent window. 当前正在播放视频时,DirectShow窗口将与其父窗口一起移动。 But I'd like the user to be able to pause and stop the video, so I need this fixed. 但我希望用户能够暂停和停止视频,因此需要修复此问题。 Here is the code for my DLL: 这是我的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);
    }
}

I would provide the GameMaker Studio code that calls the DLL and all that, but I seriously doubt I'll come across a GameMaker Studio user here. 我会提供调用DLL以及所有其他内容的GameMaker Studio代码,但我严重怀疑我是否会在这里遇到GameMaker Studio用户。 This is the best I can do. 这是我能做的最好的。 I don't know if this is what is causing the issue, but I was thinking the way I'm casting the types is why it is acting funky. 我不知道这是否是导致问题的原因,但是我一直在思考转换类型的方式,这就是为什么它表现得很时髦的原因。 To convert IGraphBuilder * to a double as a return value, I casted like so: 要将IGraphBuilder *转换为双精度值作为返回值,我进行了如下转换:

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

I have also tried: 我也尝试过:

return (double)(DWORD)pGraph;

Both give me the same aforementioned issues. 两者都给了我上述相同的问题。

As for arguments, I casted like this: 至于论点,我这样投:

(double)(DWORD)pGraph

How should I be casting the IGraphBuilder * to a double? 我应该如何将IGraphBuilder *转换为double? Or, is that not even my issue here? 或者,这不是我的问题吗?

All advice, correction, and help are appreciated greatly. 非常感谢所有建议,纠正和帮助。

Samuel 塞缪尔

Never cast a pointer to (DWORD) , it will truncate the pointer if you compile the code as 64-bit! 切勿将指针转换为(DWORD) ,如果将代码编译为64位,它将截断该指针! Use a pointer sized integer type like SIZE_T, UINT_PTR or DWORD_PTR if you must. 如果需要,请使用指针大小的整数类型,例如SIZE_T,UINT_PTR或DWORD_PTR。

char* is the best of the types you have available and is guaranteed to be ABI compatible with other pointer types. char*是您可用的最好的类型,并保证与其他指针类型兼容。

double is problematic because its size might not match the size of a pointer and it is passed in a different CPU register in 64-bit Windows programs. double是有问题的,因为它的大小可能与指针的大小不匹配,并且在64位Windows程序中的另一个CPU寄存器中传递它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM