COM 組件設(shè)計(jì)與應(yīng)用_第1頁(yè)
COM 組件設(shè)計(jì)與應(yīng)用_第2頁(yè)
COM 組件設(shè)計(jì)與應(yīng)用_第3頁(yè)
COM 組件設(shè)計(jì)與應(yīng)用_第4頁(yè)
COM 組件設(shè)計(jì)與應(yīng)用_第5頁(yè)
已閱讀5頁(yè),還剩7頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

COM組件設(shè)計(jì)與應(yīng)用(四)一一簡(jiǎn)單調(diào)用組件一、 前言同志們、朋友們、各位領(lǐng)導(dǎo),大家好。VCKBASE不得了,網(wǎng)友眾多文章好。組件設(shè)計(jì)怎么學(xué)?知識(shí)庫(kù)里悶頭找!摘自楊老師打油集錄在VCKBASE的頂力支持下,在各位網(wǎng)友回帖的鼓勵(lì)下,我才能順利完成系列論文的前三回。書(shū)到本回,我們終于開(kāi)始寫(xiě)代碼啦。寫(xiě)點(diǎn)啥那?恩,有了!咱們先從如何調(diào)用現(xiàn)成的簡(jiǎn)單的組件開(kāi)始吧,同時(shí)也順便介紹一些相關(guān)的知識(shí)。二、 組件的啟動(dòng)和釋放在第三回中,大家用“小本本”記錄了一個(gè)原則:COM組件是運(yùn)行在分布式環(huán)境中的。于是,如何啟動(dòng)組件立刻就遇到了嚴(yán)重的問(wèn)題,大家看這段代碼:p=new對(duì)象;p->對(duì)象函數(shù)();deletep;這樣的代碼再熟悉不過(guò)了,在本地進(jìn)程中運(yùn)行是不會(huì)有問(wèn)題的。但是你想想,如果這個(gè)對(duì)象是在“地球另一邊”的計(jì)算機(jī)上,結(jié)果會(huì)如何?嘿嘿,C++在設(shè)計(jì)new的時(shí)候,可沒(méi)有考慮遠(yuǎn)程的實(shí)現(xiàn)呀(計(jì)算機(jī)語(yǔ)言當(dāng)然不會(huì),也沒(méi)必要去設(shè)計(jì))。因此啟動(dòng)組件、調(diào)用接口的功能,當(dāng)然就由COM系統(tǒng)來(lái)實(shí)現(xiàn)了。圖一組件調(diào)用機(jī)制由上圖可以看出,當(dāng)調(diào)用組件的時(shí)候,其實(shí)是依靠代理(運(yùn)行在本地)和存根(運(yùn)行在遠(yuǎn)端)之間的通訊完成的。具體來(lái)說(shuō),當(dāng)客戶(hù)程序通過(guò)CoCreateInstance()函數(shù)啟動(dòng)組件,則代理接管該調(diào)用,它和存根通訊,存根則它所在的本地(相對(duì)于客戶(hù)程序來(lái)說(shuō)就是遠(yuǎn)程了)執(zhí)行new操作加載對(duì)象。對(duì)于初學(xué)者,你可以不用理它,代理和存根對(duì)我們來(lái)說(shuō)是透明的。只要大約知道是怎么一回事就一切OK了。問(wèn)題又來(lái)了,這個(gè)遠(yuǎn)程的對(duì)象什么時(shí)候消滅呢?在第二回介紹接口概念的時(shí)候,當(dāng)時(shí)我們特意忽略了兩個(gè)函數(shù),就是IUnknown::AddRef()和IUnknown::Release(),從函數(shù)名就能猜到了,一個(gè)是對(duì)內(nèi)部引用記數(shù)器(Ref)加1,一個(gè)是釋放(減1),當(dāng)記數(shù)器減為0的時(shí)候,就是釋放的機(jī)會(huì)啦??雌饋?lái)很復(fù)雜,沒(méi)辦法,因?yàn)檫@是在介紹原理。其實(shí)在我們寫(xiě)程序的時(shí)候到比較簡(jiǎn)單,請(qǐng)大家遵守幾個(gè)原則:1、 啟動(dòng)組件得到一個(gè)接口指針(Interface)后,不要調(diào)用AddRef()。因?yàn)橄到y(tǒng)知道你得到了一個(gè)指針,所以它已經(jīng)幫你調(diào)用了AddRef()函數(shù);2、 通過(guò)QueryInterface()得到另一個(gè)接口指針后,不要調(diào)用AddRef()。因?yàn)?和上面的道理一樣;3、 當(dāng)你把接口指針賦值給(保存到)另一個(gè)變量中的時(shí)候,請(qǐng)調(diào)用AddRef();4、 當(dāng)不需要再使用接口指針的時(shí)候,務(wù)必執(zhí)行Release()釋放;5、 當(dāng)使用智能指針的時(shí)候,可以省略指針的維護(hù)工作;(注1)三、內(nèi)存分配和釋放自從學(xué)習(xí)了C語(yǔ)言,老師就教導(dǎo)我們說(shuō):對(duì)于動(dòng)態(tài)內(nèi)存的申請(qǐng)和釋放,一定要遵守“誰(shuí)申請(qǐng),誰(shuí)釋放”的原則。在此原則的指導(dǎo)下,不僅是我、不僅是你,就連特級(jí)大師都設(shè)計(jì)了這樣怪怪的函數(shù):函數(shù)說(shuō)明評(píng)論GetWindowText(HWND,LPTSTR,int)取得窗口標(biāo)題。需要在參數(shù)中給出保存標(biāo)題所使用的內(nèi)存指針,和這塊內(nèi)存的尺寸。暈!我又不知道窗口標(biāo)題的長(zhǎng)度,居然還要我提供尺寸?!沒(méi)辦法,只能估摸著給一個(gè)大一些的尺寸吧。sprintf(char*,constchar*,...)格式化一個(gè)字符串。這個(gè)函數(shù)不用給出緩沖區(qū)的長(zhǎng)度啦。恩,雖然不用給出長(zhǎng)度了,但你敢給個(gè)小尺寸嗎?哼!intCListBox::GetTextLen(int)CListBox::GetText(int,LPTSTR)取得列表窗中子項(xiàng)目的標(biāo)題。需要調(diào)用兩個(gè)函數(shù),先取得長(zhǎng)度,然后分配內(nèi)存,真煩!再實(shí)際取得標(biāo)題內(nèi)容。說(shuō)實(shí)在的,不但函數(shù)調(diào)用者感覺(jué)別扭,就連函數(shù)設(shè)計(jì)者心情也不會(huì)爽的,而這一切都是為了滿足所謂“誰(shuí)申請(qǐng),誰(shuí)釋放”的原則。解決這個(gè)問(wèn)題最好的方式就是:函數(shù)內(nèi)部根據(jù)實(shí)際需要?jiǎng)討B(tài)申請(qǐng)內(nèi)存,而調(diào)用者負(fù)責(zé)釋放。這雖然違背了上述原則,但COM從方便性和效率出發(fā),確實(shí)是這么設(shè)計(jì)的。C語(yǔ)言C++語(yǔ)言Windows平臺(tái)COMIMalloc接口BSTR申malloc(請(qǐng))newGlobalAlloc()CoTaskMemAlloc()Alloc()SysAllocString()重新realloc申()請(qǐng)GlobalReAlloc()CoTaskRealloc()Realloc()SysReAllocString()釋釋free()放deleteGlobalFree()CoTaskMemFree()Free()SysFreeString()以上這些函數(shù)必須要按類(lèi)型配合使用(比如:new申請(qǐng)的內(nèi)存,則必須用delete釋放)。在COM內(nèi)部,當(dāng)然你可以隨便使用任何類(lèi)型的內(nèi)存分配釋放函數(shù),但組件如果需要與客戶(hù)進(jìn)行內(nèi)存的交互,則必須使用上表中的后三類(lèi)函數(shù)族。1、 BSTR內(nèi)存在上回書(shū)中,已經(jīng)有比較豐富的介紹了,不再重復(fù);2、 CoTaskXXX()函數(shù)族,其本質(zhì)上就是調(diào)用C語(yǔ)言的函數(shù)(malloc...);3、 IMalloc接口又是對(duì)CoTaskXXX()函數(shù)族的一個(gè)包裝。包裝后,同時(shí)增強(qiáng)了一些功能,比如:IMalloc::GetSize()可以取得尺寸,使用IMallocSpy可以監(jiān)視內(nèi)存的使用;四、參數(shù)傳遞方向在C語(yǔ)言的函數(shù)聲明中,尤其當(dāng)參數(shù)為指針的時(shí)候,你是看不出它傳遞方向的。比如:voidfun(char*p1,int*p2);請(qǐng)問(wèn),p1、p2哪個(gè)是入?yún)??哪個(gè)是出參?甚或都是入?yún)⒒蚨际浅鰠ⅲ坑捎跔砍兜絻?nèi)存分配和釋放等問(wèn)題,COM需要明確標(biāo)注參數(shù)方向。以后我們寫(xiě)程序,就類(lèi)似下面的樣子:1.HRESULTAdd([in]longn1,[in]longn2,[out]long*pnSum);//IDL文件(注2)2.STDMETHOD(Add)(/*[in]*/longn1,/*[in]*/longn2,/*[out]*/long*pnSum);//.h文件如果參數(shù)是動(dòng)態(tài)分配的內(nèi)存指針,那么遵守如下的規(guī)定:方向申請(qǐng)釋放提示人人[in]調(diào)用者調(diào)用者組件接收指針后,不能重新分配內(nèi)存[out]組件調(diào)用者組件返回指針后,調(diào)用者“愛(ài)咋咋地”(注3)[in,out]調(diào)用者調(diào)用者組件可以重新分配內(nèi)存五、示例程序示例一、由CLSID得到ProgIDo(程序以word為例子。如果運(yùn)行不正確,嘿嘿,沒(méi)有安裝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();示例二、如何使用“瀏覽文件夾”選擇對(duì)話窗。01.CStringBrowseFolder(HWNDhWnd,LPCTSTRlpTitle)02.(03.//調(diào)用SHBrowseForFolder取得目錄(文件夾)名稱(chēng)04.//參數(shù)hWnd:父窗口句柄05.//參數(shù)lpTitle:窗口標(biāo)題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的同時(shí),釋放內(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);//轉(zhuǎn)換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指針,同時(shí)釋放了hMem42.::CoUninitialize();}示例四、在桌面建立快捷方式在閱讀代碼之前,先看一下關(guān)于“快捷方式”組件的結(jié)構(gòu)示意圖。■.Q,lUnlmswnCLSID_5hellLinkIShellLink{>CLSID_5hellLink圖二、快捷方式組件的接口結(jié)構(gòu)示意圖從結(jié)構(gòu)圖中可以看出,“快捷方式”組件(CLSID_ShellLink),有3個(gè)(其實(shí)不止)接口,每個(gè)接口完成一組相關(guān)功能的函數(shù)。IShellLink接口(IID_IShellLink^供快捷方式的參數(shù)讀寫(xiě)功能(見(jiàn)圖三),IPersistFile接口(IID_IPersistFile^供快捷方式持續(xù)性文件的讀寫(xiě)功能。對(duì)象的持續(xù)性(注5),是一個(gè)非常常用,并且功能強(qiáng)大的接口家族。但今天,我們只要了解其中兩函數(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(//啟動(dòng)組件CLSID_ShellLink,//快捷方式CLSIDNULL, // 聚合用(注4)CLSCTX_INPROC_SERVER,//進(jìn)程內(nèi)(Shell32.dll)服務(wù)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();//圖標(biāo)27.//psl->SetShowCmd();//窗口尺寸28.//根據(jù)EXE的文件名,得到目錄名TCHARszWorkPath[MAX_PATH];::lstrcpy(szWorkPath,lpszExe);LPTSTRlp=szWorkPath;while(*lp) lp++;while(''\\''!二*lp) lp--;*lp=0;36.//設(shè)置EXE程序的默認(rèn)工作目錄psl->SetWorkingDirectory(szWorkPath);39.hr=psl->QueryInterface(//查找持續(xù)性文件接口指針41.IID_IPersistFile,//持續(xù)性接口IID42.(LPVOID*)&ppf);//得到接口指針43.44.if(SUCCEEDED(hr))45.(46.USES_CONVERSION;//轉(zhuǎn)換為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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論