版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
COM組件設計與應用(四)一一簡單調用組件一、 前言同志們、朋友們、各位領導,大家好。VCKBASE不得了,網(wǎng)友眾多文章好。組件設計怎么學?知識庫里悶頭找!摘自楊老師打油集錄在VCKBASE的頂力支持下,在各位網(wǎng)友回帖的鼓勵下,我才能順利完成系列論文的前三回。書到本回,我們終于開始寫代碼啦。寫點啥那?恩,有了!咱們先從如何調用現(xiàn)成的簡單的組件開始吧,同時也順便介紹一些相關的知識。二、 組件的啟動和釋放在第三回中,大家用“小本本”記錄了一個原則:COM組件是運行在分布式環(huán)境中的。于是,如何啟動組件立刻就遇到了嚴重的問題,大家看這段代碼:p=new對象;p->對象函數(shù)();deletep;這樣的代碼再熟悉不過了,在本地進程中運行是不會有問題的。但是你想想,如果這個對象是在“地球另一邊”的計算機上,結果會如何?嘿嘿,C++在設計new的時候,可沒有考慮遠程的實現(xiàn)呀(計算機語言當然不會,也沒必要去設計)。因此啟動組件、調用接口的功能,當然就由COM系統(tǒng)來實現(xiàn)了。圖一組件調用機制由上圖可以看出,當調用組件的時候,其實是依靠代理(運行在本地)和存根(運行在遠端)之間的通訊完成的。具體來說,當客戶程序通過CoCreateInstance()函數(shù)啟動組件,則代理接管該調用,它和存根通訊,存根則它所在的本地(相對于客戶程序來說就是遠程了)執(zhí)行new操作加載對象。對于初學者,你可以不用理它,代理和存根對我們來說是透明的。只要大約知道是怎么一回事就一切OK了。問題又來了,這個遠程的對象什么時候消滅呢?在第二回介紹接口概念的時候,當時我們特意忽略了兩個函數(shù),就是IUnknown::AddRef()和IUnknown::Release(),從函數(shù)名就能猜到了,一個是對內(nèi)部引用記數(shù)器(Ref)加1,一個是釋放(減1),當記數(shù)器減為0的時候,就是釋放的機會啦??雌饋砗軓碗s,沒辦法,因為這是在介紹原理。其實在我們寫程序的時候到比較簡單,請大家遵守幾個原則:1、 啟動組件得到一個接口指針(Interface)后,不要調用AddRef()。因為系統(tǒng)知道你得到了一個指針,所以它已經(jīng)幫你調用了AddRef()函數(shù);2、 通過QueryInterface()得到另一個接口指針后,不要調用AddRef()。因為 和上面的道理一樣;3、 當你把接口指針賦值給(保存到)另一個變量中的時候,請調用AddRef();4、 當不需要再使用接口指針的時候,務必執(zhí)行Release()釋放;5、 當使用智能指針的時候,可以省略指針的維護工作;(注1)三、內(nèi)存分配和釋放自從學習了C語言,老師就教導我們說:對于動態(tài)內(nèi)存的申請和釋放,一定要遵守“誰申請,誰釋放”的原則。在此原則的指導下,不僅是我、不僅是你,就連特級大師都設計了這樣怪怪的函數(shù):函數(shù)說明評論GetWindowText(HWND,LPTSTR,int)取得窗口標題。需要在參數(shù)中給出保存標題所使用的內(nèi)存指針,和這塊內(nèi)存的尺寸。暈!我又不知道窗口標題的長度,居然還要我提供尺寸?!沒辦法,只能估摸著給一個大一些的尺寸吧。sprintf(char*,constchar*,...)格式化一個字符串。這個函數(shù)不用給出緩沖區(qū)的長度啦。恩,雖然不用給出長度了,但你敢給個小尺寸嗎?哼!intCListBox::GetTextLen(int)CListBox::GetText(int,LPTSTR)取得列表窗中子項目的標題。需要調用兩個函數(shù),先取得長度,然后分配內(nèi)存,真煩!再實際取得標題內(nèi)容。說實在的,不但函數(shù)調用者感覺別扭,就連函數(shù)設計者心情也不會爽的,而這一切都是為了滿足所謂“誰申請,誰釋放”的原則。解決這個問題最好的方式就是:函數(shù)內(nèi)部根據(jù)實際需要動態(tài)申請內(nèi)存,而調用者負責釋放。這雖然違背了上述原則,但COM從方便性和效率出發(fā),確實是這么設計的。C語言C++語言Windows平臺COMIMalloc接口BSTR申malloc(請)newGlobalAlloc()CoTaskMemAlloc()Alloc()SysAllocString()重新realloc申()請GlobalReAlloc()CoTaskRealloc()Realloc()SysReAllocString()釋釋free()放deleteGlobalFree()CoTaskMemFree()Free()SysFreeString()以上這些函數(shù)必須要按類型配合使用(比如:new申請的內(nèi)存,則必須用delete釋放)。在COM內(nèi)部,當然你可以隨便使用任何類型的內(nèi)存分配釋放函數(shù),但組件如果需要與客戶進行內(nèi)存的交互,則必須使用上表中的后三類函數(shù)族。1、 BSTR內(nèi)存在上回書中,已經(jīng)有比較豐富的介紹了,不再重復;2、 CoTaskXXX()函數(shù)族,其本質上就是調用C語言的函數(shù)(malloc...);3、 IMalloc接口又是對CoTaskXXX()函數(shù)族的一個包裝。包裝后,同時增強了一些功能,比如:IMalloc::GetSize()可以取得尺寸,使用IMallocSpy可以監(jiān)視內(nèi)存的使用;四、參數(shù)傳遞方向在C語言的函數(shù)聲明中,尤其當參數(shù)為指針的時候,你是看不出它傳遞方向的。比如:voidfun(char*p1,int*p2);請問,p1、p2哪個是入?yún)ⅲ磕膫€是出參?甚或都是入?yún)⒒蚨际浅鰠??由于牽扯到?nèi)存分配和釋放等問題,COM需要明確標注參數(shù)方向。以后我們寫程序,就類似下面的樣子:1.HRESULTAdd([in]longn1,[in]longn2,[out]long*pnSum);//IDL文件(注2)2.STDMETHOD(Add)(/*[in]*/longn1,/*[in]*/longn2,/*[out]*/long*pnSum);//.h文件如果參數(shù)是動態(tài)分配的內(nèi)存指針,那么遵守如下的規(guī)定:方向申請釋放提示人人[in]調用者調用者組件接收指針后,不能重新分配內(nèi)存[out]組件調用者組件返回指針后,調用者“愛咋咋地”(注3)[in,out]調用者調用者組件可以重新分配內(nèi)存五、示例程序示例一、由CLSID得到ProgIDo(程序以word為例子。如果運行不正確,嘿嘿,沒有安裝word吧?)01.::CoInitialize(NULL);02.03.HRESULThr;04.//(000209FF-0000-0000-C000-000000000046)=word.application.905.CLSIDclsid={0x209ff,0,0,{0xc0,0,0,0,0,0,0,0x46}};06.LPOLESTRlpwProgID=NULL;07.08.hr=::ProgIDFromCLSID(clsid,&lpwProgID);09.if(SUCCEEDED(hr))(::MessageBoxW(NULL,lpwProgID,L"ProgID",MB_OK);12.13.IMalloc*pMalloc=NULL;hr=::CoGetMalloc(1,&pMalloc);//取得IMalloc15.if(SUCCEEDED(hr))TOC\o"1-5"\h\z(pMalloc->Free(lpwProgID);//釋放ProgID內(nèi)存pMalloc->Release(); //釋放IMalloc}}21.::CoUninitialize();示例二、如何使用“瀏覽文件夾”選擇對話窗。01.CStringBrowseFolder(HWNDhWnd,LPCTSTRlpTitle)02.(03.//調用SHBrowseForFolder取得目錄(文件夾)名稱04.//參數(shù)hWnd:父窗口句柄05.//參數(shù)lpTitle:窗口標題06.07.charszPath[MAX_PATH]={0};08.BROWSEINFOm_bi;09.m_bi.ulFlags=BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT;m_bi.hwndOwner=hWnd;m_bi.pidlRoot=NULL;m_bi.lpszTitle=lpTitle;m_bi.lpfn=NULL;m_bi.lParam=NULL;m_bi.pszDisplayName=szPath;17.LPITEMIDLISTpidl=::SHBrowseForFolder(&m_bi);19.if(pidl)20.(21.if(!::SHGetPathFromIDList(pidl,szPath))szPath[0]=0;22.23.IMalloc*pMalloc=NULL;24.if(SUCCEEDED(::SHGetMalloc(&pMalloc)))//取得IMalloc分配器接口TOC\o"1-5"\h\z(pMalloc->Free(pidl); //釋放內(nèi)存pMalloc->Release();//釋放接口}}returnszPath;}示例三、在窗口中顯示一幅JPG圖象。01.voidCxxxView::OnDraw(CDC*pDC)02.(03.::CoInitialize(NULL);//COM初始化04.HRESULThr;05.CFilefile;06.07.file.Open("c:\Xaa.jpg",CFile::modeRead|CFile::shareDenyNone);//讀入文件內(nèi)容08.DWORDdwSize=file.GetLength();09.HGLOBALhMem=::GlobalAlloc(GMEM_MOVEABLE,dwSize);LPVOIDlpBuf=::GlobalLock(hMem);file.ReadHuge(lpBuf,dwSize);file.Close();::GlobalUnlock(hMem);14.15.IStream*pStream=NULL;16.IPicture*pPicture=NULL;17.//由HGLOBAL得到IStream,參數(shù)TRUE表示釋放IStream的同時,釋放內(nèi)存hr=::CreateStreamOnHGlobal(hMem,TRUE,&pStream);ASSERT(SUCCEEDED(hr));21.hr=::OleLoadPicture(pStream,dwSize,TRUE,IID_IPicture,(LPVOID*)&pPicture);ASSERT(hr==S_OK);24.25.longnWidth,nHeight;//寬高,MM_HIMETRIC模式,單位是0.01毫米pPicture->get_Width(&nWidth); //寬pPicture->get_Height(&nHeight);//高28.////////原大顯示//////CSizesz(nWidth,nHeight);pDC->HIMETRICtoDP(&sz);//轉換MM_HIMETRIC模式單位為MM_TEXT
像素單位pPicture->Render(pDC->m_hDC,0,0,sz.cx,sz.cy,33.0,nHeight,nWidth,-nHeight,NULL);34.////////按窗口尺寸顯示//////////CRectrect;GetClientRect(&rect);//pPicture->Render(pDC->m_hDC,0,0,rect.Width(),rect.Height(),// 0,nHeight,nWidth,-nHeight,NULL);39.40.if(pPicture)pPicture->Release();//釋放IPicture指針41.if(pStream)pStream->Release();//釋放IStream指針,同時釋放了hMem42.::CoUninitialize();}示例四、在桌面建立快捷方式在閱讀代碼之前,先看一下關于“快捷方式”組件的結構示意圖?!?Q,lUnlmswnCLSID_5hellLinkIShellLink{>CLSID_5hellLink圖二、快捷方式組件的接口結構示意圖從結構圖中可以看出,“快捷方式”組件(CLSID_ShellLink),有3個(其實不止)接口,每個接口完成一組相關功能的函數(shù)。IShellLink接口(IID_IShellLink^供快捷方式的參數(shù)讀寫功能(見圖三),IPersistFile接口(IID_IPersistFile^供快捷方式持續(xù)性文件的讀寫功能。對象的持續(xù)性(注5),是一個非常常用,并且功能強大的接口家族。但今天,我們只要了解其中兩函數(shù),就可以了:IPersistFile::Save()和IPersistFile:Load()。(注6)圖三、快捷方式中的各種屬性01.#include<atlconv.h>02.voidCreateShortcut(LPCTSTRIpszExe,LPCTSTRIpszLnk)03.(04.//建立塊捷方式05.//參數(shù)lpszExe:EXE文件全路徑名06.//參數(shù)lpszLnk:快捷方式文件全路徑名07.08.::CoInitialize(NULL);09.10.IShellLink*psl=NULL;11.IPersistFile*ppf=NULL;12.HRESULThr=::CoCreateInstance(//啟動組件CLSID_ShellLink,//快捷方式CLSIDNULL, // 聚合用(注4)CLSCTX_INPROC_SERVER,//進程內(nèi)(Shell32.dll)服務17.IID_IShellLink,//IShellLink的IID(LPVOID*)&psl); //得到接口指針19.20.if(SUCCEEDED(hr))(psl->SetPath(lpszExe);//全路徑程序名23.//psl->SetArguments();//命令行參數(shù)24.//psl->SetDescription();//備注25.//psl->SetHotkey();//快捷鍵26.//psl->SetIconLocation();//圖標27.//psl->SetShowCmd();//窗口尺寸28.//根據(jù)EXE的文件名,得到目錄名TCHARszWorkPath[MAX_PATH];::lstrcpy(szWorkPath,lpszExe);LPTSTRlp=szWorkPath;while(*lp) lp++;while(''\\''!二*lp) lp--;*lp=0;36.//設置EXE程序的默認工作目錄psl->SetWorkingDirectory(szWorkPath);39.hr=psl->QueryInterface(//查找持續(xù)性文件接口指針41.IID_IPersistFile,//持續(xù)性接口IID42.(LPVOID*)&ppf);//得到接口指針43.44.if(SUCCEEDED(hr))45.(46.USES_CONVERSION;//轉換為UNICODE字符串ppf->Save(T2COLE(lpszLnk),TRUE);//保存}}50.if(ppf)ppf->Release();51.if(psl)psl->Release();52.::CoUninitialize();}55.voidOnXXX()(CreateShortcut(_T("c:\\winnt\\notepad.exe"),//記事本程序。注意,你的系統(tǒng)是否也是這
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 專項幕墻安裝2024協(xié)議范本版
- 組織行為分析與應用
- 專業(yè)舞臺燈光購銷協(xié)議一
- 專業(yè)維修服務協(xié)議樣本2024版B版
- 2025年度場監(jiān)督管理局委托執(zhí)法事項責任書4篇
- 2025年度廠房設備租賃及維護管理合同范本4篇
- 2024版小區(qū)公共服務設施施工協(xié)議樣本一
- 2024版特定企業(yè)融資咨詢與服務協(xié)議版
- 2025年度戶外廣告場地租賃終止協(xié)議書4篇
- 專用肥料國內(nèi)運輸合同標準文本2024版版
- 2024年08月云南省農(nóng)村信用社秋季校園招考750名工作人員筆試歷年參考題庫附帶答案詳解
- 防詐騙安全知識培訓課件
- 心肺復蘇課件2024
- 2024年股東股權繼承轉讓協(xié)議3篇
- 2024-2025學年江蘇省南京市高二上冊期末數(shù)學檢測試卷(含解析)
- 四川省名校2025屆高三第二次模擬考試英語試卷含解析
- 《城鎮(zhèn)燃氣領域重大隱患判定指導手冊》專題培訓
- 湖南財政經(jīng)濟學院專升本管理學真題
- 考研有機化學重點
- 全國身份證前六位、區(qū)號、郵編-編碼大全
- 《GPU體系結構》課件2
評論
0/150
提交評論