作者:齊云
前言: FLASH是一種功能強(qiáng)大的矢量動(dòng)畫(huà),可以制作出各種華麗的電影效果,應(yīng)用非常廣泛!這也給予我們一個(gè)啟迪:如果在VC程序中能夠播放FLASH動(dòng)畫(huà),將為程序增色不少,而且許多原本不易實(shí)現(xiàn)的功能,現(xiàn)在都可以輕松實(shí)現(xiàn)! 像金山詞霸的安裝程序主控界面就利用了FLASH,效果相當(dāng)好。本文中筆者將制作一個(gè)完整的多媒體軟件,將一些關(guān)鍵性技術(shù)介紹給大家,并提供全部代碼供大家參考。
本文使用到的關(guān)鍵性技術(shù): (1)利用VB制作MS AGENT播放模塊。 (2)將該播放模塊、FLASH動(dòng)畫(huà)文件SWF與其它必要資源打包到程序中,并在運(yùn)行時(shí)自動(dòng)釋放。 (3)通過(guò)VC和VB的通信實(shí)現(xiàn)多個(gè)不同模塊的順序執(zhí)行。 (4)FLASH的播放,并實(shí)現(xiàn)避免右鍵菜單的彈出。
下面介紹具體的實(shí)現(xiàn): (1)利用VB制作MS AGENT播放模塊。 這里先插入MS AGENT模塊。然后在Form_Load里進(jìn)行Agent控件的初始化; Private Sub Form_Load() Agent1.Characters.Load ("dot") 下面就可進(jìn)行動(dòng)畫(huà)操作了. Agent1.Characters.Character("dot").Show 我們可用如下語(yǔ)句執(zhí)行一些動(dòng)作 Agent1.Characters.Character("dot").Play "Congratulate" Agent1.Characters.Character("dot").Speak "你好!" Agent1.Characters.Character("dot").moveto x,y ‘x,y 位屏幕坐標(biāo)。 ......
由于我們用的是dot.acs,我們不能假定別人的機(jī)子上有這個(gè)文件。所以我將這個(gè)文件復(fù)制到winnt(windows)\msagent\chars目錄下, 用于復(fù)制的VC代碼如下: char *a = new char [255]; char *b = new char [255]; GetCurrentDirectory(255,a); CString *str = new CString(a); CString *sou = new CString; //////////////////////////////////////// (*sou)=*str+CString("\\DOT.ACS"); GetWindowsDirectory (b,255); CString *des =new CString(b) ; (*des)+=CString ("\\msagent\\chars"); CreateDirectory (des->GetBuffer (10),NULL); *des+=CString ("\\DOT.ACS"); //AfxMessageBox (*des); //AfxMessageBox (*sou); CopyFile (sou->GetBuffer (10),des->GetBuffer (10),false); //這個(gè)是為了避免在Load中用全路徑。
(2)實(shí)現(xiàn)了文件打包,將過(guò)多的模塊整合到一起,避免文件的繁雜 首先我們將各個(gè)模塊作為資源加入資源中。定義整數(shù)標(biāo)識(shí)和類(lèi)型。這些資源文件打包將在程序運(yùn)行的時(shí)候解出。 以下是從資源釋放到文件的函數(shù): int res2file(LPCTSTR lpName,LPCTSTR lpType,LPCTSTR filename) { //輸入:lpName 為資源名,可用MAKEINTRESOURCE()宏將整型變?yōu)樽址? //LpType 為串類(lèi)型名 //Filename 為釋放出的文件名。 //輸出:成功1,失敗0 HRSRC myres = FindResource (NULL,lpName,lpType); HGLOBAL gl = LoadResource (NULL,myres); LPVOID lp = LockResource(gl);//返回指向資源內(nèi)存的地址的指針。 // CREATE_ALWAYS為不管文件存不存在都產(chǎn)生新文件。 HANDLE fp = CreateFile(filename ,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
if (!fp) return false; DWORD a; //sizeofResource 得到資源文件的大小 if(!WriteFile (fp,lp,SizeofResource(NULL,myres),&a,NULL)) return false; CloseHandle(fp); FreeResource(gl); return true; } 以下是調(diào)用的方法: res2file (MAKEINTRESOURCE(IDR_ZF),"swf","zf.swf"); res2file (MAKEINTRESOURCE(IDR_ZG),"swf","zg.swf"); res2file (MAKEINTRESOURCE(IDR_DOT),"acs","DOT.ACS"); res2file (MAKEINTRESOURCE(IDR_SHARE),"dll","share.dll"); res2file (MAKEINTRESOURCE(IDR_TALK),"dll","talk.dll"); res2file (MAKEINTRESOURCE(IDR_SWFLASH),"ocx","swflash.ocx");
(3)通過(guò)VC和VB的通信實(shí)現(xiàn)多個(gè)不同模塊的順序執(zhí)行 在程序中我們需要調(diào)用VB模塊并等待它執(zhí)行完畢再繼續(xù)我們的VC程序,這就涉及到VC與VB之間的通訊問(wèn)題,在這里我使用事件來(lái)解決這個(gè)問(wèn)題,請(qǐng)看如下代碼: CreateEvent(NULL,false,false,"lsbeven"); 然后,調(diào)用ms agent 動(dòng)畫(huà) PROCESS_INFORMATION pi; STARTUPINFO si={0}; si.cb=sizeof(si); char *a =new char [255]; GetCurrentDirectory (255,a); CString *str=new CString(a); //AfxMessageBox (*des); //AfxMessageBox (*sou); *str+=CString("\\talk.e\0"); BOOL fRet=CreateProcess(NULL, str->GetBuffer (5), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 最后,用WaitForSingleObject (heven,40000)等待事件被觸發(fā)。(40s超時(shí))
接下來(lái)的問(wèn)題便是如何在VB中完成執(zhí)行后觸發(fā)這個(gè)事件。由于在vb中使用API很復(fù)雜,為了提供簡(jiǎn)單起見(jiàn)我用vc做了share.dll實(shí)現(xiàn)setvalue,然后在VB中進(jìn)行調(diào)用來(lái)激活事件。 在setvalue中調(diào)用如下兩個(gè)函數(shù)來(lái)激活事件。
OpenEvent(DWORD dwAccess,//存取方式 BOOL bInheritHandle,//是否能被繼承 LPCTSTR lpName)//名字 SetEvent (HANDLE hEvent); Vb中用變量鎖方法實(shí)現(xiàn)在未出來(lái)提示“點(diǎn)我呀!”前對(duì)左鍵點(diǎn)擊的無(wú)效,在顯示完提示后,當(dāng)用戶(hù)點(diǎn)擊就調(diào)用setvalue來(lái)激活事件。 Agent1_Click(ByVal CharacterID As String, ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Integer, ByVal y As Integer) If b ==ture Then setvalue Endif
(4)FLASH的播放,并實(shí)現(xiàn)避免右鍵菜單的彈出 1. 控鍵注冊(cè): HMODULE hmod=LoadLibrary ("swflash.ocx"); FARPROC p=GetProcAddress (hmod,"DllRegisterServer"); (*p)();
2.在工程中插入 flash 控件。由于在不規(guī)則窗口中在進(jìn)行flash控件的支持會(huì)使程序過(guò)于不清晰。于是另開(kāi)獨(dú)立的窗口來(lái)顯示flash。 void TransparentWnd::OnTimer(UINT nIDEvent) { switch (nIDEvent) { case 1: { KillTimer (nIDEvent); DoChange(MAKEINTRESOURCE(IDB_MAIN2)); //創(chuàng)建視,作為默認(rèn)視 if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(260, 30,630, 370), this, AFX_IDW_PANE_FIRST, NULL)) TRACE0("Failed to create view window\n"); CenterWindow (); ShowWindow (SW_SHOW); } break; default: break; } }
BOOL TransparentWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { if(m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;//如果是command消息則視類(lèi)先處理。 return CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); }
void TransparentWnd::OnSetFocus(CWnd* pOldWnd) { //如果有視類(lèi)則視類(lèi)獲得焦點(diǎn)。 if(m_wndView.m_hWnd !=NULL) m_wndView.SetFocus(); }
下面在CchildView中定義
CShockwaveFlash myflash;
///改變窗口特征 BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) { if (!CWnd::PreCreateWindow(cs)) return FALSE; cs.dwExStyle |= WS_EX_CLIENTEDGE; cs.style &= ~WS_BORDER; cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW), HBRUSH(COLOR_WINDOWTEXT), NULL); return TRUE; }
BOOL CChildView::OnEraseBkgnd(CDC* pDC) { return TRUE;//不讓window自動(dòng)刷屏 }
//下面進(jìn)入控制部分 int CChildView ::OnCreate (LPCREATESTRUCT lpCreateStruct) { if(CWnd::OnCreate(lpCreateStruct)==-1) return -1; myflash.Create(NULL,WS_CHILD|WS_VISIBLE,CRect(0,0,0,0), this, 1024); SetTimer (1,0,NULL); SetTimer (2,12000,NULL); CRect m_rect; GetClientRect (&m_rect ); myflash.MoveWindow (&m_rect);//使flash 控件占滿(mǎn)整個(gè)視區(qū)域 return 0; }
char *a = new char [512]; GetCurrentDirectory (100,a); CString *s=new CString(a); myflash.LoadMovie (0,*s+CString("\\zf.swf"));//這里一定要為全路徑 myflash.Play();//播放FLASH動(dòng)畫(huà) (5)兩個(gè)高級(jí)話(huà)題 5.1 在VC中用COM接口對(duì)ms agent 進(jìn)行操作 #include "stdafx.h" #include <ole2.h> #include <AgtSvr.h> #include <AgtSvr_i.c> #include <tchar.h>
const LPWSTR kpwszCharacter =L"dot.acs"; int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { IAgent *pAgent; if (FAILED(OleInitialize(NULL))) return -1; HRESULT hRes=CoCreateInstance (CLSID_AgentServer, NULL, CLSCTX_LOCAL_SERVER, IID_IAgent, (LPVOID*)&pAgent); //下面的代碼調(diào)用IAgent::Load()方法來(lái)裝入一個(gè)動(dòng)畫(huà)人物的數(shù)據(jù) //由于Agent服務(wù)器在自己的內(nèi)存空間中運(yùn)行,所以傳送的字符串變量需要用SysAllocString()來(lái)分配內(nèi)存
VARIANTARG vPath; VariantInit(&vPath);
//初始化OLE變量 vPath.vt = VT_BSTR;
//指明變量類(lèi)型為Unicode的字符串 vPath.bstrVal=SysAllocString(lpCharacter);
//lpCharacter 為動(dòng)畫(huà)人物數(shù)據(jù)的存放路徑
long __RPC_FAR lCharID,lRequestID; hRes=pAgent->Load(vPath,&lCharID,&lRequestID);//裝入數(shù)據(jù)人物ID在lCharID中返回
IDispatch *pdCharacter; hRes=pAgent->GetCharacter(lCharID,&pdCharacter); //獲取 lCharID的IDispatch接口指針調(diào)用IDispatch::QueryInterface()方法
//可以得到IAgentCharacter的接口指針: IAgentCharacter *pCharacter; hRes=pdCharacter->QueryInterface(IID_IAgentCharacter, (LPVOID*)&pCharacter);
pdCharacter->Release();
//釋放IDispath 通過(guò)IAgentCharacter接口就可以調(diào)用動(dòng)畫(huà)人物支持的各種方法了:
hRes = pCharacter->Show(FALSE,&lRequestID); //顯示動(dòng)畫(huà)人物 hRes = pCharacter->MoveTo(320,240,100,&lRequestID);//移動(dòng)動(dòng)畫(huà)人物到屏幕中央 BSTR bszSpeak = SysAllocString(L"Hello World!");//分配字符串 hRes = pCharacter->Speak(bszSpeak,NULL,&lRequestID);//讓動(dòng)畫(huà)人物說(shuō)話(huà)
SysFreeString(bszSpeak);//釋放字符串所占內(nèi)存
// 程序在退出之前需要把創(chuàng)建的Agent對(duì)象釋放:
if(pCharacter){ pCharacter->Release();//釋放IAgentCharacter接口 pAgent->Unload(lCharID); //卸載動(dòng)畫(huà)人物數(shù)據(jù) } pAgent->Release(); //釋放Agent對(duì)象 VariantClear(&vPath); //清除OLE變量 }
下載MS AGENT演示源代碼(VC)11.1K
5.2 同步問(wèn)題還可用信號(hào)燈來(lái)實(shí)現(xiàn) 在vc 中進(jìn)行啟動(dòng)時(shí)第一步就創(chuàng)建信號(hào)量,值為0。在啟動(dòng)vb創(chuàng)建的程序,然后vc中進(jìn)行p操作. vb創(chuàng)建的程序中 在退出時(shí)使用v操作。實(shí)現(xiàn)同步。 P (s): S - - If s<0 Then 掛起當(dāng)前進(jìn)程 對(duì)應(yīng):win32 API :WaitForSingleObject
V(s): S++ If s<=0 Then 在s的等待隊(duì)列中喚醒一進(jìn)程 對(duì)應(yīng):win32 API :ReleaseSemaphore
(6)后記 本程序?qū)懹?月份,當(dāng)時(shí)是一個(gè)朋友的生日,它是作為一個(gè)禮物送給她的。開(kāi)始的時(shí)候,只提供了簡(jiǎn)單的窗口界面后來(lái),在看了幾位高手的佳作后,將它改進(jìn)了一下。并希望和大家一起討論,將它更加完美。
|