zoukankan      html  css  js  c++  java
  • 在MFC中使用纯COM方式来操纵Flash OCX

    1. MFC中的控件(OCX)包装类

    在VC++环境中,使用OCX会变得比较简单和快捷。
    在Dialog中插入ActiveX,如:Shockwave Flash Object。
    在建立了Dialog的类之后,为刚才插入的Flash 控件添加变量,
    MFC会自动帮我们生成两个文件:CShockwaveFlash1.h和CShockwaveFlash1.cpp有了这两个文件,就可以很容易控制Flash了。

    2. 通过MIDL生成TLB文件
    MFC包装类固然简单,但很明显缺乏一些高级的功能,此时就需要采用纯COM的方式了。
    首先使用OLE/COM Object Viewer来找到Shockwave Flash Object,如下图:
    ,点击右键“View Type Information”,在弹出的界面中,点击“save as”将信息保存为 SWF.IDL文件,然后在打开VS提供的工具:“Visual Studio 2008 命令提示”,进入DOS界面,切换到SWF.IDL所在的目录,执行如下命令:
    MIDL SWF.IDL /tlb SWF.tlb,即可生成tlb文件。
    如果生成过程有错,提示“error MIDL2110 : end of file found in string”,可以这样做:将前面打开的界面中(“View Type Information”)的内容拷贝,然后手动新建一个SWF.IDL的文件,将拷贝的内容粘贴入,再次执行MIDL命令。
    接下来在你的VC++项目中:#import "SWF.tlb",编译之,即会在debug或者release
    目录下面生成tlh(头文件,header)和tli文件(实现文件,implementation)。
    注意,在tlh文件的末尾处已经包含了tli文件。
    当然也可以采用下面叙述的方式生成。

    3. 相关概念
    多数情况下,生成的com组件DLL/EXE/OCX已经包含了类型库信息(type information),但当你的com程序足够大,可能需要分离类型库信息,此时考虑生成tlb[/B]文件,单独存放类型库。
    此时使用:#import "XXX.tlb",然后编译之,也会在debug或者release下面产生 XXX.tli和XXX.tlh文件。
    tlh和tli文件实际上是对com接口及其属性方法的封装类,其中tlh[/B]相当于类型申明(头文件),tli相当于定义实现(CPP文件),这里的实现完全是封装方法的实现,而不是com接口方法的实现。
    如下例:
    inline int IShockwaveFlash::GetQuality ( ) {
    int _result = 0;
    HRESULT _hr = get_Quality(&_result);
    if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
    return _result;
    }
    其中get_Quality的真正实现实际上在XXX.ocx或者XXX.dll中。

    4. 开始创建IShockwaveFlash

    为了简单起见,就不使用那么麻烦的方法了,直接这样:
    #import "C:\WINDOWS\system32\Macromed\Flash\FlDbg9f.ocx" \
    raw_interfaces_only, /* Don't add raw_ to method names */ \
    raw_native_types, /* Don't map to DTC smart types */ \
    named_guids, /* Named guids and declspecs */ \
    no_namespace /* Don't wrap with C++ name space */

    如前述会自动在debug目录下面生成tlh和tli文件,不需要在工程属性里面加入lib,也不要include什么,
    很方便。
    接下来,构造、析构:
    CFlashHelper::CFlashHelper(void)
    {
    if(FAILED(CoInitialize(NULL)))
    {
    AfxMessageBox(L"CoInitialize Failed!\r\n");
    return;
    }

    isf=NULL;
    ivo=NULL;
    }
    CFlashHelper::~CFlashHelper(void)
    {
    CoUninitialize();
    }
    其中isf和ivo是成员变量(在.h中声明):
    IShockwaveFlash * isf;
    IViewObject2 * ivo;
    再初始化接口:
    HRESULT CFlashHelper::Init(BSTR fileName)
    {
    HRESULT hr;
    JIF(CoCreateInstance(__uuidof(ShockwaveFlash),
    NULL,CLSCTX_INPROC_SERVER,
    __uuidof(IShockwaveFlash),(void **)&isf));

    JIF(isf->QueryInterface(__uuidof(IViewObject2),(void **)&ivo));

    AtlAxAttachControl(isf,theApp.m_pFlashPlayerDlg->m_hWnd,NULL);

    isf->put_Movie(fileName);

    return S_OK;
    }
    其中JIF是一个宏:
    #define JIF(x) if (FAILED(hr=(x))) \
    {TRACE(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("\n\0"), hr); return hr;}
    这里还要使用一点点ATL,ATL做COM这方面的工作在行些。
    故,要在工程属性中,设置“动态使用ATL”,在这个cpp文件中,包含如下头文件:
    #include <atlbase.h>
    #include <atlcom.h>
    #include <atlctl.h>

    上面的代码中还采用了一种比较简单的方法,即:
    AtlAxAttachControl(isf,theApp.m_pFlashPlayerDlg->m_hWnd,NULL);
    传统的做法是先用CAxWindow创建窗口,然后采用其QueryControl方法得到IUnknown接口,
    再采用其QueryInterface,得到IShockwaveFlash,代码大概如下:
    HRESULT CFlash::Create(LPRECT lpRect) {
    HRESULT hr = S_OK;
    AtlAxWinInit();
    m_pAxWin = new CAxWindow();
    m_hwnd = m_pAxWin->Create(NULL, lpRect, g_szCLSID_ShockwaveFlash, 0);
    if (!m_hwnd)
    {
    return E_FAIL;
    }
    IUnknown *pUk = NULL;
    hr = m_pAxWin->QueryControl(&pUk);
    if (FAILED(hr))
    {
    return hr;
    }
    m_lWidth = lpRect->right-lpRect->left;
    m_lHeight = lpRect->bottom - lpRect->top;
    hr = pUk->QueryInterface(IID_IShockwaveFlash,(void**)&m_pShockwaveFlash);
    pUk->Release();
    return hr;
    }
    但这个工程既然是MFC的工程,就不想使用CAxWindow来创建窗口,所以采用MFC来建立的Dialog,
    然后AtlAxAttachControl(isf,theApp.m_pFlashPlayerDlg->m_hWnd,NULL);就可以了。
    通过上面的方法就得到了IShockwaveFlash和IViewObject2了,接下来怎么做就随你了。

    5. 其他要注意
    如果你同时在使用GDI+,那么可能会要加入如下代码:
    // for GDI+
    #include <comdef.h>
    #ifndef ULONG_PTR
    #define ULONG_PTR unsigned long *
    #include "GdiPlus.h"
    using namespace Gdiplus;
    // end for GDI+
    #endif
    这样编译的时候就会出现如下的错误:
    错误 8 error C2440: “初始化”: 无法从“int”转换为“unsigned long *” c:\program files\microsoft visual studio 9.0\vc\atlmfc\include\atlwin.h 523 LEDEngine
    错误 9 error C2664: “GlobalAlloc”: 不能将参数 2 从“unsigned long *”转换为“SIZE_T” c:\program files\microsoft visual studio 9.0\vc\atlmfc\include\atlwin.h 570 LEDEngine
    其实是因为ULONG_PTR这个数据类型,这个东西在ATL中也有定义,而且在altwin.h中使用了,但是其实在ATL中:
    ULONG_PTR是这样定义的:typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
    在GDI+中式这样定义的:#define ULONG_PTR unsigned long *
    这样就有冲突了,故如要同时使用GDI+和ATL,一定要这样声明:
    // for GDI+
    #include <comdef.h>
    #include "GdiPlus.h"
    using namespace Gdiplus;
    // end for GDI+
    好了,这个话题就说到这里。
  • 相关阅读:
    Expedition---POJ
    LIS的优化算法O(n log n)
    Super Jumping! Jumping! Jumping! ---HDU
    数据库连接判断
    android stuido控件
    sql查询语句
    c# 字符串操作
    windows操作
    C# sql操作
    datagridview
  • 原文地址:https://www.cnblogs.com/xiayong123/p/3717182.html
Copyright © 2011-2022 走看看