简体   繁体   中英

DirectShow - convert IGraphBuilder * to double (C++)

I am creating an extension for GameMaker Studio using a DLL. GameMaker Studio only supports function return types that are either void, char *, or double. As for arguments, only char * and double are supported. 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. 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. 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:

#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. 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:

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? 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! Use a pointer sized integer type like SIZE_T, UINT_PTR or DWORD_PTR if you must.

char* is the best of the types you have available and is guaranteed to be ABI compatible with other pointer types.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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