Flash 矢量動畫效果華麗、應用廣泛。若能在 VC++ 程式中播放 Flash、結合 MS Agent 語音角色,將大幅豐富介面表現。本文實作一個完整多媒體軟體,涵蓋四大關鍵技術:VB 製作 MS Agent 模組、資源打包釋放、VC/VB 跨程序同步、Flash 播放與右鍵選單屏蔽。
插入 MS Agent 控制項,Form_Load 初始化:
Agent1.Characters.Load "dot"
Agent1.Characters("dot").Show
Agent1.Characters("dot").Play "Congratulate"
Agent1.Characters("dot").Speak "你好!"
Agent1.Characters("dot").MoveTo x, y
角色檔 dot.acs 需部署至 Windows\msagent\chars,VC++ 端複製代碼:
CString src = currentDir + "\\DOT.ACS";
CString des = winDir + "\\msagent\\chars\\DOT.ACS";
CreateDirectory(des.Left(des.ReverseFind('\\')), NULL);
CopyFile(src, des, FALSE);
將 SWF、ACS、DLL、OCX 等以自訂資源類型(如 "swf", "acs", "dll", "ocx")加入專案資源,執行時釋放:
int Res2File(LPCTSTR lpName, LPCTSTR lpType, LPCTSTR filename) {
HRSRC hRes = FindResource(NULL, lpName, lpType);
HGLOBAL hGlob = LoadResource(NULL, hRes);
LPVOID pData = LockResource(hGlob);
HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
DWORD dwWritten;
WriteFile(hFile, pData, SizeofResource(NULL, hRes), &dwWritten, NULL);
CloseHandle(hFile); FreeResource(hGlob); return TRUE;
}
// 呼叫範例
Res2File(MAKEINTRESOURCE(IDR_ZF), "swf", "zf.swf");
Res2File(MAKEINTRESOURCE(IDR_DOT), "acs", "DOT.ACS");
Res2File(MAKEINTRESOURCE(IDR_SWFLASH), "ocx", "swflash.ocx");
VC++ 啟動 VB 程式並等待完成:
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "lsbeven"); // 自動重置、非訊號狀態
PROCESS_INFORMATION pi; STARTUPINFO si = {sizeof(si)};
CString cmd = currentDir + "\\talk.exe";
CreateProcess(NULL, cmd.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
WaitForSingleObject(hEvent, 40000); // 等待 40 秒超時
VB 端完成互動後觸發事件:
Private Sub Agent1_Click(...)
If bReady Then SetValue ' 呼叫 VC++ DLL 觸發事件
End Sub
VC++ share.dll 導出 SetValue:
HANDLE hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, "lsbeven");
SetEvent(hEvent); // 通知 VC++ 繼續執行
替代方案:信號量 (CreateSemaphore/ReleaseSemaphore) 同樣適用。
動態載入註冊 swflash.ocx:
HMODULE hMod = LoadLibrary("swflash.ocx");
FARPROC pFn = GetProcAddress(hMod, "DllRegisterServer");
pFn();
獨立視窗播放 Flash(避免不規則視窗渲染問題):
class CChildView : public CWnd {
CShockwaveFlash m_flash;
int OnCreate(LPCREATESTRUCT lpCS) {
m_flash.Create(NULL, WS_CHILD|WS_VISIBLE, CRect(0,0,0,0), this, 1024);
SetTimer(1, 0, NULL); // 立即載入
SetTimer(2, 12000, NULL); // 12 秒後切換
CRect rc; GetClientRect(&rc); m_flash.MoveWindow(&rc);
return 0;
}
void OnTimer(UINT nID) {
if (nID == 1) {
KillTimer(1);
CString path = currentDir + "\\zf.swf";
m_flash.LoadMovie(0, path); // 必須完整路徑
m_flash.Play();
}
}
};
屏蔽右鍵選單:Flash ActiveX 本身無直接屬性,需透過視窗子類化攔截 WM_RBUTTONDOWN/WM_CONTEXTMENU 或使用 AllowScriptAccess 參數限制。
無需 VB 中介,直接呼叫 IAgent 介面:
IAgent* pAgent; CoCreateInstance(CLSID_AgentServer, ..., IID_IAgent, (void**)&pAgent);
VARIANT vPath; vPath.vt = VT_BSTR; vPath.bstrVal = SysAllocString(L"dot.acs");
long lCharID, lReqID; pAgent->Load(vPath, &lCharID, &lReqID);
IDispatch* pDisp; pAgent->GetCharacter(lCharID, &pDisp);
IAgentCharacter* pChar; pDisp->QueryInterface(IID_IAgentCharacter, (void**)&pChar);
pChar->Show(FALSE, &lReqID);
pChar->MoveTo(320, 240, 100, &lReqID);
BSTR bstr = SysAllocString(L"Hello World!"); pChar->Speak(bstr, NULL, &lReqID);
SysFreeString(bstr); pChar->Release(); pAgent->Unload(lCharID); pAgent->Release();
程式最初作為生日禮物開發,後參考高手作品改良。歡迎同好交流,共同完善。