日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【转载】COM 组件设计与应用(四)——简单调用组件

發布時間:2024/6/21 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转载】COM 组件设计与应用(四)——简单调用组件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:http://vckbase.com/index.php/wv/1211.html

?

一、前言

同志們、朋友們、各位領導,大家好。
 

 VCKBASE 不得了, 
 網友眾多文章好。 
 組件設計怎么學? 
 知識庫里悶頭找! 
  摘自---楊老師打油集錄

在 VCKBASE 的頂力支持下,在各位網友回帖的鼓勵下,我才能順利完成系列論文的前三回。書到本回,我們終于開始寫代碼啦。寫點啥那?恩,有了!咱們先從如何調用現成的簡單的組件開始吧,同時也順便介紹一些相關的知識。

二、組件的啟動和釋放

在第三回中,大家用“小本本”記錄了一個原則:COM 組件是運行在分布式環境中的 。于是,如何啟動組件立刻就遇到了嚴重的問題,大家看這段代碼:

1.p =?new?對象; 2.p->對象函數(); 3.delete?p;

這樣的代碼再熟悉不過了,在本地進程中運行是不會有問題的。但是你想想,如果這個對象是在“地球另一邊”的計算機上,結果會如何?嘿嘿,C++ 在設計 new 的時候,可沒有考慮遠程的實現呀(計算機語言當然不會,也沒必要去設計)。因此啟動組件、調用接口的功能,當然就由 COM 系統來實現了。

圖一 組件調用機制

由上圖可以看出,當調用組件的時候,其實是依靠代理(運行在本地)和存根(運行在遠端)之間的通訊完成的。具體來說,當客戶程序通過 CoCreateInstance() 函數啟動組件,則代理接管該調用,它和存根通訊,存根則它所在的本地(相對于客戶程序來說就是遠程了)執行 new 操作加載對象。對于初學者,你可以不用理它,代理和存根對我們來說是透明的。只要大約知道是怎么一回事就一切OK了。

問題又來了,這個遠程的對象什么時候消滅呢?在第二回介紹接口概念的時候,當時我們特意忽略了兩個函數,就是IUnknown::AddRef()和IUnknown::Release(),從函數名就能猜到了,一個是對內部引用記數器(Ref)加1,一個是釋放(減1),當記數器減為0的時候,就是釋放的機會啦。看起來很復雜,沒辦法,因為這是在介紹原理。其實在我們寫程序的時候到比較簡單,請大家遵守幾個原則:

1、啟動組件得到一個接口指針(Interface)后,不要調用AddRef()。因為系統知道你得到了一個指針,所以它已經幫你調用了AddRef()函數;

2、通過QueryInterface()得到另一個接口指針后,不要調用AddRef()。因為......和上面的道理一樣;

3、當你把接口指針賦值給(保存到)另一個變量中的時候,請調用AddRef();

4、當不需要再使用接口指針的時候,務必執行Release()釋放;

5、當使用智能指針的時候,可以省略指針的維護工作;(注1)

三、內存分配和釋放

自從學習了C語言,老師就教導我們說:對于動態內存的申請和釋放,一定要遵守“誰申請,誰釋放”的原則。在此原則的指導下,不僅是我、不僅是你,就連特級大師都設計了這樣怪怪的函數:

函數說明評論
GetWindowText(HWND,LPTSTR,int)取得窗口標題。需要在參數中給出保存標題所使用的內存指針,和這塊內存的尺寸。暈!我又不知道窗口標題的長度,居然還要我提供尺寸?!沒辦法,只能估摸著給一個大一些的尺寸吧。
sprintf(char *,const char *,...)格式化一個字符串。這個函數不用給出緩沖區的長度啦。恩,雖然不用給出長度了,但你敢給個小尺寸嗎?哼!
int CListBox::GetTextLen(int)
CListBox::GetText(int,LPTSTR)
取得列表窗中子項目的標題。需要調用兩個函數,先取得長度,然后分配內存,再實際取得標題內容。真煩!

說實在的,不但函數調用者感覺別扭,就連函數設計者心情也不會爽的,而這一切都是為了滿足所謂“誰申請,誰釋放”的原則。 解決這個問題最好的方式就是:函數內部根據實際需要動態申請內存,而調用者負責釋放。這雖然違背了上述原則,但 COM 從方便性和效率出發,確實是這么設計的。

 C語言C++語言Windows 平臺COMIMalloc 接口BSTR
申請malloc()newGlobalAlloc()CoTaskMemAlloc()Alloc()SysAllocString()
重新申請realloc() GlobalReAlloc()CoTaskRealloc()Realloc()SysReAllocString()
釋放free()deleteGlobalFree()CoTaskMemFree()Free()SysFreeString()

以上這些函數必須要按類型配合使用(比如:new 申請的內存,則必須用 delete 釋放)。在 COM 內部,當然你可以隨便使用任何類型的內存分配釋放函數,但組件如果需要與客戶進行內存的交互,則必須使用上表中的后三類函數族。

1、BSTR 內存在上回書中,已經有比較豐富的介紹了,不再重復;

2、CoTaskXXX()函數族,其本質上就是調用C語言的函數(malloc...);

3、IMalloc 接口又是對 CoTaskXXX() 函數族的一個包裝。包裝后,同時增強了一些功能,比如:IMalloc::GetSize()可以取得尺寸,使用 IMallocSpy 可以監視內存的使用;

四、參數傳遞方向

在C語言的函數聲明中,尤其當參數為指針的時候,你是看不出它傳遞方向的。比如:

void fun(char * p1, int * p2); 請問,p1、p2 哪個是入參?哪個是出參?甚或都是入參或都是出參?由于牽扯到內存分配和釋放等問題,COM 需要明確標注參數方向。以后我們寫程序,就類似下面的樣子:

1.HRESULT?Add([in]?long?n1, [in]?long?n2, [out]?long?*pnSum);??// IDL文件(注2) 2.STDMETHOD(Add)(/*[in]*/?long?n1,?/*[in]*/?long?n2,?/*[out]*/?long?*pnSum);??// .h文件

如果參數是動態分配的內存指針,那么遵守如下的規定:

方向申請人釋放人提示
[in]調用者調用者組件接收指針后,不能重新分配內存
[out]組件調用者組件返回指針后,調用者“愛咋咋地”(注3)
[in,out]調用者調用者組件可以重新分配內存

五、示例程序

示例一、由 CLSID 得到 ProgID。(程序以 word 為例子。如果運行不正確,嘿嘿,你沒有安裝 word 吧?)

::CoInitialize( NULL );HRESULT hr; // {000209FF-0000-0000-C000-000000000046} = word.application.9 CLSID clsid = {0x209ff,0,0,{0xc0,0,0,0,0,0,0,0x46}}; LPOLESTR lpwProgID = NULL;hr = ::ProgIDFromCLSID( clsid, &lpwProgID ); if ( SUCCEEDED(hr) ) {::MessageBoxW( NULL, lpwProgID, L"ProgID", MB_OK );IMalloc * pMalloc = NULL;hr = ::CoGetMalloc( 1, &pMalloc ); // 取得 IMallocif ( SUCCEEDED(hr) ){pMalloc->Free( lpwProgID ); // 釋放ProgID內存pMalloc->Release(); // 釋放IMalloc} }::CoUninitialize();

  

示例二、如何使用“瀏覽文件夾”選擇對話窗。

CString BrowseFolder(HWND hWnd, LPCTSTR lpTitle) {// 調用 SHBrowseForFolder 取得目錄(文件夾)名稱// 參數 hWnd: 父窗口句柄// 參數 lpTitle: 窗口標題char szPath[MAX_PATH]={0};BROWSEINFO m_bi;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;LPITEMIDLIST pidl = ::SHBrowseForFolder( &m_bi );if ( pidl ){if( !::SHGetPathFromIDList ( pidl, szPath ) ) szPath[0]=0;IMalloc * pMalloc = NULL;if ( SUCCEEDED ( ::SHGetMalloc( &pMalloc ) ) ) // 取得IMalloc分配器接口{pMalloc->Free( pidl ); // 釋放內存pMalloc->Release(); // 釋放接口}}return szPath; }

  

示例三、在窗口中顯示一幅 JPG 圖象。

void CxxxView::OnDraw(CDC* pDC) {::CoInitialize(NULL); // COM 初始化HRESULT hr;CFile file;file.Open( "c:\\aa.jpg", CFile::modeRead | CFile::shareDenyNone ); // 讀入文件內容DWORD dwSize = file.GetLength();HGLOBAL hMem = ::GlobalAlloc( GMEM_MOVEABLE, dwSize );LPVOID lpBuf = ::GlobalLock( hMem );file.ReadHuge( lpBuf, dwSize );file.Close();::GlobalUnlock( hMem );IStream * pStream = NULL;IPicture * pPicture = NULL;// 由 HGLOBAL 得到 IStream,參數 TRUE 表示釋放 IStream 的同時,釋放內存hr = ::CreateStreamOnHGlobal( hMem, TRUE, &pStream );ASSERT ( SUCCEEDED(hr) );hr = ::OleLoadPicture( pStream, dwSize, TRUE, IID_IPicture, ( LPVOID * )&pPicture );ASSERT(hr==S_OK);long nWidth,nHeight; // 寬高,MM_HIMETRIC 模式,單位是0.01毫米pPicture->get_Width( &nWidth ); // 寬pPicture->get_Height( &nHeight ); // 高原大顯示//CSize sz( nWidth, nHeight );pDC->HIMETRICtoDP( &sz ); // 轉換 MM_HIMETRIC 模式單位為 MM_TEXT 像素單位pPicture->Render(pDC->m_hDC,0,0,sz.cx,sz.cy,0,nHeight,nWidth,-nHeight,NULL);按窗口尺寸顯示 // CRect rect; GetClientRect(&rect); // pPicture->Render(pDC->m_hDC,0,0,rect.Width(),rect.Height(), // 0,nHeight,nWidth,-nHeight,NULL);if ( pPicture ) pPicture->Release();// 釋放 IPicture 指針if ( pStream ) pStream->Release(); // 釋放 IStream 指針,同時釋放了 hMem::CoUninitialize(); }

  

示例四、在桌面建立快捷方式

在閱讀代碼之前,先看一下關于“快捷方式”組件的結構示意圖。

?

圖二、快捷方式組件的接口結構示意圖

從結構圖中可以看出,“快捷方式”組件(CLSID_ShellLink),有3個(其實不止)接口,每個接口完成一組相關功能的函數。IShellLink 接口(IID_IShellLink)提供快捷方式的參數讀寫功能(見圖三),IPersistFile 接口(IID_IPersistFile)提供快捷方式持續性文件的讀寫功能。對象的持續性(注5),是一個非常常用,并且功能強大的接口家族。但今天,我們只要了解其中兩函數,就可以了:IPersistFile::Save()和IPersistFile:Load()。(注6)

?

圖三、快捷方式中的各種屬性

#include < atlconv.h > void CreateShortcut(LPCTSTR lpszExe, LPCTSTR lpszLnk) {// 建立塊捷方式// 參數 lpszExe: EXE 文件全路徑名// 參數 lpszLnk: 快捷方式文件全路徑名::CoInitialize( NULL );IShellLink * psl = NULL;IPersistFile * ppf = NULL;HRESULT hr = ::CoCreateInstance( // 啟動組件CLSID_ShellLink, // 快捷方式 CLSIDNULL, // 聚合用(注4)CLSCTX_INPROC_SERVER, // 進程內(Shell32.dll)服務IID_IShellLink, // IShellLink 的 IID(LPVOID *)&psl ); // 得到接口指針if ( SUCCEEDED(hr) ){psl->SetPath( lpszExe ); // 全路徑程序名 // psl->SetArguments(); // 命令行參數 // psl->SetDescription(); // 備注 // psl->SetHotkey(); // 快捷鍵 // psl->SetIconLocation(); // 圖標 // psl->SetShowCmd(); // 窗口尺寸// 根據 EXE 的文件名,得到目錄名TCHAR szWorkPath[ MAX_PATH ];::lstrcpy( szWorkPath, lpszExe );LPTSTR lp = szWorkPath;while( *lp ) lp++;while( ''\\'' != *lp ) lp--;*lp=0;// 設置 EXE 程序的默認工作目錄psl->SetWorkingDirectory( szWorkPath );hr = psl->QueryInterface( // 查找持續性文件接口指針IID_IPersistFile, // 持續性接口 IID(LPVOID *)&ppf ); // 得到接口指針if ( SUCCEEDED(hr) ){USES_CONVERSION; // 轉換為 UNICODE 字符串ppf->Save( T2COLE( lpszLnk ), TRUE ); // 保存}}if ( ppf ) ppf->Release();if ( psl ) psl->Release();::CoUninitialize(); }void OnXXX() {CreateShortcut(_T("c:\\winnt\\notepad.exe"), // 記事本程序。注意,你的系統是否也是這個目錄?_T("c:\\Documents and Settings\\Administrator\\桌面\\我的記事本.lnk"));// 桌面上建立快捷方式(lnk)文件的全路徑名。注意,你的系統是否也是這個目錄?// 如果用程序實現尋找桌面的路徑,則可以查注冊表// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders }

  

七、小結

本回介紹的內容比較實用。大家不要只抄襲代碼,而一定要理解它。結合 MSDN 的說明去思索代碼、理解其含義。好了,想方設法把代碼忘掉!三天后(如過你還沒有忘記,那就再過三天),你在不參考示例代碼,但可以隨便翻閱 MSDN 的情況下,自己能獨立地再次完成這四個例程,那么恭喜你,你已經入門了:0) 從下回開始,我們要用 ATL 做 COM 的開發工作啦,您老人家準備好了嗎?

作業,留作業啦......

1、你已經學會如何建立快捷方式了,那么你知道怎么讀取它的屬性嗎?(如果寫不出這個程序,那么你就不用繼續學習了。因為......動點腦筋呀!我還沒有見過象你這么笨的學生呢!)

2、示例程序三中使用了 IPicture 接口顯示一個 JPG 圖象。那么你現在去完成一個功能,把 JPG 文件轉換為 BMP 文件。

注1:智能指針的概念和用法,后續介紹。

注2:IDL 文件,下回就要介紹啦。

注3:東北話,想干什么都可以,反正我不管啦。

注4:聚合,也許在第30回中介紹吧:-)

注5:持續性,IPersistXXXXXX是一個非常強大的接口家族,后續介紹。

注6:想知道 IShellLink、IPersistFile接口的所有函數嗎?別愣著,快去看MSDN呀......

轉載于:https://www.cnblogs.com/zhehan54/p/4993064.html

總結

以上是生活随笔為你收集整理的【转载】COM 组件设计与应用(四)——简单调用组件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久久久久九九九 | 99re视频| 欧美日韩另类在线 | 国产盗摄一区二区三区 | 三上悠亚三级 | 欧美一级免费视频 | 狠狠v欧美v日韩v亚洲ⅴ | 亚洲天堂中文字幕在线观看 | 超碰最新上传 | 免费一级特黄特色大片 | 亚洲精品一区三区三区在线观看 | 日韩在线视 | 天天操免费视频 | 奇米精品一区二区三区在线观看一 | 欧美精品一区二区三区三州 | 亚洲视频在线观看网站 | 亚洲图片一区二区 | 久久久久久久999 | 国产探花一区二区三区 | 涩涩在线观看 | 欧洲精品一区二区三区 | 国产人与zoxxxx另类 | 黄色a网站 | 97精品视频在线观看 | 国产老熟妇精品观看 | 国产精品123 | 深夜网站在线 | 亚洲精品7777 | 在线射| 久久综合一区二区三区 | 激情网站在线观看 | 国产av精国产传媒 | 日韩激情第一页 | 阿v天堂2017 欧美小视频在线观看 | 久久一二三四区 | 国产亚洲久一区二区 | 激情午夜网 | 欧美精品久久久久久久久 | 青娱乐导航 | 久久久亚洲一区 | 波多野结衣片子 | 国产精品第8页 | 欧美xxxx非洲 | 九九热最新网址 | 中文字幕免费在线视频 | 国产字幕在线观看 | 日本特级片 | 在线观看国产精品一区 | 长河落日电视连续剧免费观看 | 人妻在客厅被c的呻吟 | 一色综合| 99久久精品国产亚洲 | 久草福利资源在线 | 色涩涩| 亚洲资源在线观看 | 日韩av无码一区二区三区 | 69av视频在线观看 | 精品无码一区二区三区 | 少妇饥渴难耐 | 国产精品一区网站 | 天天做日日做 | 欧美一区二区三区大屁股撅起来 | avav国产 | 另类欧美亚洲 | 国产精品久久综合 | 日本亚洲欧美在线 | 一区二区欧美在线观看 | 国产极品久久 | 中文在线资源天堂 | 先锋成人 | 黄色喷水视频 | 中国白嫩丰满人妻videos | 欧美专区 日韩专区 | 91www | 日日夜夜超碰 | 人人模人人爽 | 欧美一级做a爰片久久高潮 久热国产精品视频 | 亚洲男人皇宫 | 1769国产精品视频 | 亚洲国产情侣 | 欧美一卡二卡在线观看 | 放几个免费的毛片出来看 | 亚州男人的天堂 | 国产xxxx| 国产99精品视频 | 成人综合久久 | 美女福利在线视频 | 国产美女无遮挡免费视频 | 婷婷在线观看视频 | 爱插网| 久久精品国产视频 | 中文字字幕码一二三区 | 亚州国产| 久久久久久九九九九 | 寂寞少妇让水电工爽hd | 丁香色欲久久久久久综合网 | 中文字幕在线看高清电影 | av免费观看大全 | 欧美性在线视频 |