VC++ 项目中使用 FLEX

1, http://hi.baidu.com/qinpc/blog/item/58253df3f9a04654352acc36.html

复杂的界面有多层窗口组成,当windows在窗口改变大小的时候是先重画父窗口,然后重画子窗口,子父窗口重画的过程一般无法在一个刷新周期内完成,所以会呈现闪烁。我们知道父窗口上被子窗口挡住的部分其实没必要重画的。

 

解决方法:给窗口加个风格 WS_CLIPCHILDREN ,这样父窗口上被子窗口挡住的部分就不会重画了。如果同级窗口之间有重叠,那么需要再加上 WS_CLIPSIBLINGS 风格

 

我赶紧到项目中把Flash对话框的窗口风格加上WS_CLIPCHILDREN,编译后运行,成功了!感谢作者,让我终于睡了一个安稳觉。
四、DEBUG状态是总是报Assertion失败。
这个问题困扰了我一整天。我的系统上安装了Flex SDK,因此,注册的Flash控件是调试版。不知什么原因,在每次关闭对话框之后,系统总是报cmdtarget.cpp文件中的控件引用值不为1错误,从而造成断言失败。
我以为是代码的问题,重建了一个项目,什么代码都没写。运行,关闭,断言错误。因为之前的VC出现了一个奇怪的问题:打开对话框命令总是出现非法操作。反复重装VC都不能解决,最后在网上看到可能是安装的visio 2003冲突,卸载visio 2003后问题解决。我开始怀疑是不是我之前的折腾把系统搞乱掉了。我又重装了一次VC,再次编译运行,问题再次出现。我都快疯了。
在没疯之前,我决定到同事的电脑上试一下。生成的程序运行没有问题。把我生成的代码拷贝过去运行,没有问题。我突然意识到,是不是Flash控件的问题。卸载重装后,问题解决。我的天!
(待续。。。)

同大多数的ActiveX控件一样,VC为Flash实现了一个CWnd的包装:CShockwaveFlash,该类实现了Flash ActiveX控件的所有功能。在AS3问世之前,Flash同宿主之间的通讯只有FSCommand一种方式,而且是异步的,更没有返回值可言。因为项目中需要VC为Flash提供大量的数据库查询,返回结果通过XML进行传递。因此,FSCommand无疑是不方便的。
AS3推出的外部API调用方式:ExternalInterface,极大的简化了编程方式。ExternaleInterface是同步的调用,并可以返回调用结果。需要说明的是,同步调用是以牺牲性能为代价的,因为这涉及到大量的CPU周期占用)。我曾经在Flex项目中,利用ExternalInterface实现了IFrame在Flash的嵌入调用,从而达到在Flash中显示HTML的问题。
CShockwaveFlash为ExternalInterface提供了一个事件接收器(event sink):FlashCall。FlashCall事件只有一个参数:request,而且我们会发现,在Flash中通过ExternalInterface的调用,是通过XML的方式进行封装,然后传递到request中的。为了获得调用的方法名和参数,你必须解析request封装的XML包。
不过奇怪的是,处理FlashCall事件的是一个void方法。要返回数据,你需要调用SetReturnValue方法。返回的数据也必须是XML格式,且必须符合Flash的规范。如果要返回XML结果集,把XML封装到<string></string>中,然后在Flash中通过new XML(str)的方式动态生成。
二、屏蔽Flash的右键菜单
这是个恼人的问题,我不希望用户在软件界面中弹出Flash右键菜单。在VC中,虽然Flash控件提供了SetMenu方法,通过传入FALSE屏蔽大部分的菜单项,但遗憾的是,“关于”和“设置”菜单无法去掉。
为了实现这个功能,我查阅了大量的资料。按照一般的想法,右键菜单的生成应该经过某种消息处理的流程。我先是重载了CShockwaveFlash类的WndProc方法,并在其中跟踪消息流,结果造成IDE死机。我做出了一个错误的决定,我认为这个消息一定可以在其它地方截获,于是我又费了很大的周折,特意实现了自己的CControlSite类,结果依然让人失望。
后来下载了一个Delphi下的TShockwaveFlashEx组件,才发现该组件是通过截获组件的WM_RBUTTONDOWN消息实现的菜单屏蔽。这就是说,让用户的右键消息干脆不传到Flash控件中去。简单而直接的方法。
VC中实现起来更简单些。直接从CShockwaveFlash派生自己的类(不建议直接修改CShowwaveFlash类),然后捕获WM_RBUTTONDOWN消息,直接在消息处理函数中注释掉父类的方法调用。然后修改Flash对象的类型为你的派生类即可。
甚至可以更简单些。直接在对话框中响应WM_MOUSEACTIVATE消息,然后在处理函数中判断message参数的值,如果是WM_RBUTTONDOWN,则返回MA_ACTIVATEANDEAT(激活控件,吃掉消息。http://msdn2.microsoft.com/en-us/library/ms645612.aspx)。
三、调整窗口大小时防止Flash控件闪烁
在Dialog的WM_SIZE响应中,把Flash控件布满整个窗口。可是这个简单的实现却造成了Flash界面的频繁闪烁。在Delphi的TShockwaveFlashEx组件中,作者是通过覆盖组件的CreateWnd方法实现的,在对话框Resize事件中,调用这个重载的CreateWnd方法。
可是,在VC中如何实现呢?为此,我在google上苦苦搜索了好几天。关于ActiveX控件闪烁的问题,网上有很多的解决方案。很多方案都是建议同时重载控件和对话框擦除背景事件,然后写一些代码防止控件重绘自身。也有一些方法是通过GDI的思路,在内存中通过bitblt的方式避免闪烁。看到最后很伤心,怎么会这么麻烦呢。
Ely Greenfield's Flex Ajax Bridge is a beautiful piece of work. It impressed me so much that I translated the javascript part of it to C++. Just like FABridge for javascript, the Flex C++ bridge allows you to do most of the things you can do with actionscript via C++. Of course, the syntax is not as pretty as it would be in javascript but it does let you develop C++ applications with a Flex UI.

What?

Nothing explains it like code. Take a look at the following C++ snippet1:

//addeventlistener to call a cpp function
oRootObj.Call("getbutton1").Call("addEventListener", "click", SampleCallback); 

//where SampleCallback is:
void SampleCallback(CASObject& obj, CFlexBridge* pBridge)
{
    CASObject oRootObj;
    pBridge->Root(oRootObj);
    oRootObj.Call("getpanel1").Call("settitle", "Title from CPP"); 
} 

//c++ way of saying Alert.show("StaticClassCalled")
pBridge->ClassRef("mx.controls.Alert").Call("show", "StaticClassCalled");

//create a datagrid and add it to the flex app
CASObject oDGrid = pBridge->Create("mx.controls.DataGrid");
oRootObj.Call("addChild", oDGrid);

Flex C++ Bridge is a C++ library that lets you communicate with Flex in a manner more suited for the normal C++ programmer, i.e, you can communicate to flex from c++ by writing code like shown above.

Once you put the Flex Ajax bridge into a Flex application, it is exposed to scripting in the browser. You can use a slightly modified version of the same FABridge.as2 (or even the same one) on the actionscript side and the flex application is exposed to the Flex C++ Bridge.

Flex is for the web, AIR is for the desktop. What is this for?

This is for C++ applications that need an awesome UI but do not want to re-write their existing c++ code and libraries to actionscript / javascript. It's a normal desktop application, you can interact with all your favorite C++ libraries and APIs and still have all the rich expressiveness that flex can deliver.

You could do all this before as well, but the bridge makes it really easy to use Flex from C++. A lot of the reasons for FABridge applies to this as well, but this is outside the browser realm so those reasons have to be filtered to suit that particular fact.

Where can I get it from?

The project is licensed under MPL 1.1 and both the C++ and actionscript source code is available at code.google.com.

It's open source, so feel free to participate and contribute to it.

Sample Applications

Note: The source (both flex and cpp) is available for all the examples.

AdvancedDataGrid that supports Excel formulae computation:

Computing Excel formulae in ADG.

Here, each individual cells in the ADG are editable. You can type in any Excel formula into it and hit the "Compute" button. The application invokes Excel using COM, computes the results and populates the result into the ADG.

Scan images right into flexbook:

Scan images using TWAIN into Flexbook.

When the Scan button is clicked, a TWAIN dialog pops up letting you use your scanner to scan images directly into the pages of the flexbook component.

Sample app showing two flash player instances each with a flex application:

Multiple flash player instances.

The bridge supports multiple flash player instances. It can talk to each instance in a different manner. If you look at the screenshot, both the instances are loading the same swf file. But the C++ code for one instance adds a datagrid and removes an element shown in the pie chart.

How does it work?

The flash player ActiveX control is added to a MFC dialog. Now the content in the flash player can talk to the C++ application via ExternalInterface. ExternalInterface.call("fnname") will dispatch a FlashCall message on the C++ side which will have the arguments passed to call() in XML. This XML has to be parsed to understand what the message was from the actionscript side.

All this complexity is hidden by the bridge. The bridge talks with the actionscript side of Ely's FABridge and facilitates calling and referencing to actionscript objects, classes and methods.

There are multiple worker threads waiting to process incoming or outgoing flash requests so that the main MFC thread does not block. The bridge can even support multiple flash player instances each with it's own bridge back to the C++ application.

Also, Actionscript exceptions are serialized and thrown on the C++ side.

C++ Syntax Rules

To start off, you need the root object which is the main application object of your flex application. Now you can access the public methods and properties of your application.

Getters and setters are treated differently: A property "width" will be translated to "getwidth" for retrieving the value and "setwidth" for setting the value. Ely's FABridge had camel casing here, but that has been removed so that constants like MOUSE_DOWN don't confuse the bridge.

The "Call" method shown in the snippets above take a string as the first argument that is the name of the method or property (suitably modified using above defined rules) and the arguments for it. Common types like string, int, reference to an AS object, custom anonymous AS object etc are converted internally to an ASObject thanks to copy constructors and operator overloads.

For more examples of the syntax, take a look at the Worker() method in ASWorkSample.cpp.

FABridge did not originally have support for accessing methods and variables of static classes. This was added by Devin Garner and I have incorporated his code into FABridge.as along with some of my changes.

Fine Print

Currently, it supports only Windows since it embeds the internet explorer flash ActiveX control in a MFC dialog.

But it's an open source project and I hope I'll get contributors to help me make it more platform agnostic.

I'd love to know what you guys think about this and how it's being used.

CategoryFlexCPPBridge Comment(s)

 


[1] Now, this is a better way to communicate rather than saying m_Shockwave.CallFunction("asfnname") where asfnname has to be exposed by using ExternalInterface.addCallback on the actionscript side.
[2] Minor changes to support passing of primitives from me and additional support for accessing static classes, variables and methods thanks to Devin Garner)

 

3.

Flex与Win32通信实例之ExternalInterface

关键字: flex win32 vc++ vc externalinterface
项目中要实现Flex打开文件夹选择框(Flex做为桌面程序的UI),没办法,如果不用AIR只能在下面加一层Container了。网上搜来搜去差不多都是讲FSCommand怎样与VC++交互,可是FSCommand不能及时返回值呀。经过一番摸索,终于调通了ExternalInterface在VC++中的处理流程,看代码。
 
Cpp代码
void CMyBicapDlg::OnFlashCallShockwaveflash1(LPCTSTR request)  

    // TODO: Add your control notification handler code here 
    // "<invoke name='%s' returntype='xml'><arguments><string>%s</string></arguments></invoke>" 
     
    // parse request 
    TiXmlDocument request_xml; 
    request_xml.Parse(request); 
    const char* request_name = request_xml.RootElement()->Attribute("name"); 
     
    if (strcmp(request_name,"savedVideosDirectory") == 0 || strcmp(request_name,"bufferDirectory") == 0 || strcmp(request_name,"preferredExportDirectory") == 0) 
    { 
        // choose path 
        CoInitialize(NULL); 
        BROWSEINFO bi; 
        bi.hwndOwner = this->GetSafeHwnd(); 
        bi.pidlRoot = NULL; 
        bi.pszDisplayName = NULL; 
        bi.lpszTitle = NULL; 
        bi.ulFlags = BIF_BROWSEFORCOMPUTER|BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT; 
        bi.lpfn = NULL; 
        LPCITEMIDLIST pidl = SHBrowseForFolder(&bi); 
        if(pidl != NULL) 
        { 
            TCHAR tpath[MAX_PATH] = _T(""); 
            BOOL bresult = SHGetPathFromIDList(pidl, tpath); 
            if (bresult) 
            { 
                std::string re_value = "<string>"; 
                re_value = re_value+tpath+"</string>"; 
                m_FlashPlayer.SetReturnValue(re_value.c_str()); 
            } 
        } 
 
        CoUninitialize(); 
    } 
     

 
首先,需要在项目中嵌入Flash player插件,网上有很多例子。另外Flex也要写好代码,这里略掉。
添加一个ExternalInterface的事件处理函数,对于Flash player来讲就是FlashCall事件(跟FSCommand不同的),这里的事件处理函数是void CMyBicapDlg::OnFlashCallShockwaveflash1(LPCTSTR request)。没有返回值(下面会讲到),参数是一个XML格式的字符串。格式是"<invoke name='%s' returntype='xml'><arguments><string>%s</string></arguments></invoke>",去查查帮助就知道了。
处理request:标准C++没有处理XML的库,我去下载了tinyxml,小巧好用。下面就是按照个人需要处理request了,我这里是,打开一个文件夹选择对话框然后选择一个路径。
返回值。事件处理函数是没有返回值的,但是flash player提供了一个方法:m_FlashPlayer.SetReturnValue(re_value.c_str());,专门传递返回值,格式是<string>%s</string>(也可以是别的AS结构,具体看帮助)。
需要提醒的是,在处理期间要block掉Flex,ExternalInterface.call是有返回值的,如果不阻塞Flex,可能返回就是NULL,呵呵,不知道深层原因。另外,反过来调用格式也是一样的。
调试环境:win xp, VC++6.0, Flex builder 2.0

posted on 2010-12-08 08:55  cy163  阅读(...)  评论(...编辑  收藏

导航