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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

masm32开发com组件

發布時間:2024/3/26 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 masm32开发com组件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
標題: masm32開發com組件介紹[一][二][三]
  作者: combojiang
  時間: 2007-12-10 14:09
  鏈接: http://bbs.pediy.com/showthread.php?t=56328
  詳細信息:
  聲明:本貼參考網站:http://ourworld.compuserve.com/
  [一]基礎知識篇
  組件對象模型(Com)在windows操作系統中應用越來越廣泛。com因為大量的技術細節顯得很復雜,但是正是這種復雜才使com組件的調用顯得十分簡單。 com和使用程序采用server/client架構。下面我們將在后續的兩篇中介紹com組件的編寫與調用。
  com編程時當前程序開發的熱點,各種編程語言都為組件編寫提供了很好的支持,但是匯編語言例外,匯編語言開發組件沒有優勢。但是透過匯編開發的了解,可以使我們了解com組件的工作原理。好了,閑話少說,開始介紹:)
  所有的inc頭文件都要滿足如下特點:
  1) masm32松散的類型定義約定將繼續使用。就是說參數可以被定義為他們的基本類型,代表性的如:DWORD
  2) 里面不能創建任何的代碼,僅僅包含定義信息,頭文件里面需要包含代碼,則必須定義為宏。
  3) 結構體應該參照他們的C原形來定義。
  4) GUID 結構定義在windows.inc文件中,GUID的值應該通過textequ宏來定義,這樣不會直接產生任何代碼。
  5) 接口定義分為兩步:
  1.一個通用的宏產生一個通用的接口結構。
  2.使用接口名字來修飾結構自身的方法名字。
  這種方式可以有效地避免namespace沖突,并且方便接口定義結構繼承。
  6)COM接口函數調用使用coinvoke宏。
  GUIDS
  EXAMPLE:
  sIID_IUnknown TEXTEQU ;; run thru args to see if edx is lurking in there
  IFIDNI ,
  .ERR
  ENDIF
  ENDM
  istatement CATSTR ,,
  IFNB ;; add the list of parameter arguments if any
  istatement CATSTR istatement, ,
  ENDIF
  mov edx, pInterface
  mov edx, [edx]
  istatement
  ENDM
  ;------------------------------------------------- --------------------
  例如:QueryInterface方法調用如下:
  coinvoke ppv ,IUnknown, QueryInterface, ADDR IID_SomeOtherInterface,
  ADDR ppnew
  HRESULTS
  任何一個com接口函數的返回值類型都是一個hResult, 4個字節長。返回值在eax寄存器中。可以用這個值來判斷函數調用是否成功。
  .IF !SIGN?
  ; function passed
  .ELSE
  ; function failed
  .ENDIF
  接下來,我們定義了宏來簡化它:
  .IF SUCCEEDED ; TRUE if SIGN bit not set
  .IF FAILED ; TRUE is SIGN bit set
  結論:
  以上這些是你用匯編開發com需要用到的,這些適用于activex的開發。
  [二]用匯編語言編寫com組件
  組件對象模型com是以win32 dll或exe形式發布的執行代碼組成的。Com是由一些對象和對象的接口組成,在com里,接口提供對象操作的機制。 而接口是由一個或者多個相關的方法、屬性、事件組成的。在這里我們開發一個簡單的但是功能齊全的一個進程內com組件(即以dll形式存在)。
  這里假設你已經了解了com對象模型的基礎知識,了解什么是虛表,什么是虛函數表指針。如果你不熟悉這些,建議看看《com本質論》這本書。
  我們先來分析下進程內com服務的組成。由于它是一個dll形式發布的,其中包括5個重要的函數。其中后面的四個是要作為dll導出函數來導出的。
  DllMain: 這是動態鏈接庫德第一個入口函數,它在庫被加載的時候被調用,通過這個函數,可以對客戶端程序進行檢查。
  DllRegisterServer:通過這個函數能夠實現組建的自我注冊,注冊信息作為資源保存在動態鏈接庫中,這個函數能夠讀取資源,把信息寫進注冊表,使用
  regsvr32.exe 注冊組建時,實際上是調用了組件輸出的這個函數。
  DllUnregisterServer: 當一個組件不再使用時,這個組件應該能夠提供自我卸載,regsvr32.exe能調用這個函數,實現這一步。
  DllCanUnloadNow: com服務中的全局變量用于保存它的狀態,客戶端可以周期性的調用這個函數,檢查組件服務器是否在使用,然后把它卸載。
  DllGetClassObject: 這是完成組件輸出的函數,這個輸出需要3個參數,創建組件的GUID,要創建組件接口的GUID以及創建后指向對象的指針。如果組件對象或者接口不被支持,執行將失敗。
  到現在為止,我們應該注意到一件事情,就是如果不是因為間接訪問,com將什么也不是。實際上,DllGetClassObject函數返回的對象不是我們要尋找的對象,它是類廠對象,一個類廠對象了解如何實例化其他任何的類。第一層的間接訪問允許組件創建的細節被指定,如果它僅僅是簡單而又直接的返回一個我們要尋找的對象指針,那么說明對象已經存在,那樣,我們將不能設置和控制關于構造對象的任何參數。
  DllGetClassObject返回一個IClassFactory接口,這個接口是從IUnknown派生的,另外他還有自己的兩個重要的成員函數。
  HRESULT CreateInstance(
  IUnknown * pUnkOuter, //Pointer to outer object when part of an
  // aggregate REFIID riid,
  REFIID riid, //Reference to the interface identifier
  oid** ppvObject); //Address of output variable that receives
  // the interface pointer requested in riid
  HRESULT LockServer(BOOL fLock);
  //Increments or decrements the lock count
  LockServer用來控制類廠對象的引用計數,系統檢查改計數以確定是否要卸載組件,即:控制類廠的生存期。
  CreateInstance是最重要的,類廠組件的唯一功能是創建其它組件。一個類廠組件可以對應多種普通COM組件,但每個類廠組件的實例只能創建一種COM組件。
  它接收一個接口GUID,返回該接口的指針。它并不接受組件的CLSID,所以一個類廠實例只能夠創建一種COM組件,即傳給 CoGetClassObject的CLSID對應的組件。
  客戶、COM庫、組件dll、類廠、組件之間的交互過程:
  1. 客戶首先調用COM庫的CoCreateInstance函數來創建COM組件。
  2. CoCreateInstance首先調用COM庫的CoGetClassObject獲取類廠。
  3. 該函數具體是通過調用了組件DLL輸出的DllGetClassObject來創建類廠。
  4. DllGetClassObject通過new函數產生一個Cfactory的對象,并通過QueryInterface獲取其接口指針(一般是IclassFactory指針)。
  5. 返回到COM庫的CoCreateInstance調用剛才獲得的接口指針(IclassFactory,類廠)的CreateInstance函數。
  6. 該函數new指定的組件類,通過QueryInterface獲得指定的接口
  7. CoCreateInstanse釋放掉IclassFactory指針(通過Release),然后向客戶程序返回獲得的指針。
  8. 可以在客戶中使用獲得的接口了。
  在第6步中,根據不同的CLSID創建不同的組件,可以實現一個類廠供該DLL中多個組件共用。但只是類共用,不是實例共用。一旦在創建類廠時通過CoGetClassObject指定了CLSID,則只能創建該COM組件的實例。
  在這里我們將深入c++對象模型,來看下一些內部的實現細節。通常編譯器來處理這些。com的設計者充分利用了這些,因此,我們需要了解它。
  當我們用匯編寫一個常規的程序時,我依靠編譯器為我們創建代碼段和數據段,內存中的一塊區域是我們執行的代碼,另一塊區域保存了我們需要的數據。
  C++運行時動態內存分配,給每一個類實例,每一個小的代碼段它自己的數據段。換句話講,一個類的實例就是這個數據段,每一個類實例的數據描述都是保存在一個動態的數據區域。
  或許你聽說過c++傳遞對象成員函數參數時,有一個隱藏的參數,即this指針。當一個人為對象寫一個低層的代碼時(在c++中編譯器會作這個工作,你不需要考慮),
  你首先遇到的問題是"我在給哪個對象寫代碼?"
  This指針是一個簡單的指針,它指向這個動態數據內存區域的這個類對象實例。當一個類對象函數被調用時,this指針就會被悄悄地傳遞過去。當這個對象的私有數據被訪問時,類的代碼區域就會使用this指針,來找到它的對象實例的數據。
  對于一個com接口指針跟this指針很類似。使用中,com是一個接口規范,讓你看不到它的代碼實現。
  ; declare the ClassFactory object structure
  ClassFactoryObject STRUCT
  lpVtbl DWORD 0 ; function table pointer
  nRefCount DWORD 0 ; object and reference count
  ClassFactoryObject ENDS
  ; declare the MyCom object structure
  MyComObject STRUCT
  lpVtbl DWORD 0 ; function table pointer
  nRefCount DWORD 0 ; reference count
  nValue DWORD 0 ; interface private data
  MyComObject ENDS
  第一個lpVtbl是一個虛表指針,它指向一個虛函數表,我用它來控制每個接口的私有數據。就像這里的nRefCount和nValue。
  這些結構所在的動態內存是通過CoTaskMemAlloc和CoTaskMemFree這兩個API函數來分配和釋放的。這兩個函數是由ole32.dll導出的。Ole32.dll還導出了很多的函數,例如比對GUIDs值和把轉換GUIDs為字符串,或者把字符串轉換為GUIDs。
  為了舉例說明com接口的工作原理,我們創建一個簡單接口IMyCom(注:所有的com接口都有一個"I"前綴。同其他接口一樣,他派生于IUnknown接口,也就是說他的前三個函數是QueryInterface, AddRef, 和Release。下面我們添加幾個接口函數。下面看到的是c風格的函數原形:
  HRESULT SetValue(long *pVal);
  HRESULT GetValue(long newVal);
  HRESULT RaiseValue(long newVal);
  其中,SetValue 和 GetValue用于讀,設置我們接口的數據成員。RaiseValue用于增加這個數據的值。
  這個結構在內存中的形式如下:
  客戶端僅僅擁有一個分布式結構的指針(ppv)這個名字來源于它的c++形式的定義("pointer to pointer to (void)."),當創建類實例的時候,這個對象數據塊是動態分配和初始化的,虛函數表vtable和server functions是靜態的,他們在編譯時定義好。
  有一點需要注意的是,虛函數表擁有的是函數指針,而并非是函數本身。因此,我們可以修改虛函數表中指向的例程,就可以簡單的"override"一個派生函數。
  在例子中,IClassFactory和IMyCom都是派生于IUnknown接口,都繼承了QueryInterface,但是他們支持不同的接口,它們需要指向不同的例程,返回不同的結果。
  因此,它們有各自的QueryInterface例程(QueryInterfaceCF 和 QueryInterfaceMC)被不同的虛函數表指向。
  同樣的,AddRef和Release也要被不同的支持他們的接口來定制。
  類型庫:
  每一個com接口都是從系統注冊表中得到信息,這些接口的定義都是由一個被稱為接口定義語言(IDL)來描述的,在windows平臺下,使用MIDL進行編譯。我們可以利用vc開發環境,通過向導來創建一個原始的接口定義文件。
  -------------------------------------------------- --------------------------------------------------- ----------------On WinTel platforms,
  我建一個ATL工程,命名為MyComApp,然后選擇"insert a new ATL object",然后選擇"Simple Object",命名為:MyCom。這樣就創建了一個空的IMyCom接口,然后通過右鍵菜單,我們添加屬性SetValue和GetValue,并增加一個RaiseValue方法。然后我們保存退出工程,拷貝MyComApp.idl文件到我的匯編工程目錄。
  下面就是這個idl文件的內容:
  // MyCom.idl : IDL source for MyCom.dll
  //
  // This file will be processed by the MIDL tool to
  // produce the type library (MyCom.tlb) and marshalling code
  import "oaidl.idl";
  import "ocidl.idl";
  [
  object,
  uuid(F8CE5E41-1135-11d4-A324-0040F6D487D9),
  helpstring("IMyCom Interface"),
  pointer_default(unique)
  ]
  interface IMyCom : IUnknown
  {
  [propget, helpstring("property Value")]
  HRESULT Value([out, retval] long *pVal);
  [propput, helpstring("property Value")]
  HRESULT Value([in] long newVal);
  [helpstring("method Raise")]
  HRESULT Raise(long Value);
  };
  [
  uuid(F8CE5E42-1135-11d4-A324-0040F6D487D9),
  version(1.0),
  helpstring("MyComApp 1.0 Type Library")
  ]
  library MyComLib
  {
  importlib("stdole32.tlb");
  importlib("stdole2.tlb");
  [
  uuid(F8CE5E43-1135-11d4-A324-0040F6D487D9),
  helpstring("MyCom Class")
  ]
  coclass MyCom
  {
  [default] interface IMyCom;
  };
  };
  這個文件可以被用來作為原型進一步進行接口定義。注意這里面有三個GUIDs,一個是為接口,一個是為coclass,一個是為類型庫。對于新的應用,它們的值一定不同。
  透過這個定義的文件結構,我們很容易了解他的內容。
  [propget, helpstring("property Value")] HRESULT Value([out, retval] long *pVal); [propput, helpstring("property Value")] HRESULT Value([in] long newVal); [helpstring("method Raise")] HRESULT Raise(long Value);
  下面是這些接口在masm32中的定義:
  GetValue PROTO :DWORD, :DWORD
  SetValue PROTO :DWORD, :DWORD
  RaiseValue PROTO :DWORD, :DWORD
  他們有很大的不同,但是原因很簡單。類型庫中的接口是作為通用的,可以直接被客戶端象VB來使用。
  為了創建類型庫,可以使用MIDL命令行來編譯idl文件:
  MIDL MyCom.idl
  編譯產生的幾個文件,除了MyCom.tlb外,其他的都可以忽略,接下來我們需要把類型庫添加到dll資源文件中。例如:
  1 typelib MyCom.tlb
  讓他作為資源文件中的第一個元素是很重要的,后續我們將會使用LoadTypeLib API函數來使用這個庫,同時這個函數也是希望在第一位置發現這個庫。 注冊組件:
  DllRegisterServer 和 DllUnregisterServer 為我們注冊組件和注銷組件用.內容如下:
  HKEY_CLASSES_ROOT\CMyCom
  (Default) "CMyCom simple client"
  HKEY_CLASSES_ROOT\CMyCom\CLSID
  (Default) "{A21A8C43-1266-11D4-A324-0040F6D487D9}"
  HKEY_CLASSES_ROOT\CLSID\{A21A8C43-1266-11D4-A324-0 040F6D487D9}
  (Default) "CMyCom simple client"
  HKEY_CLASSES_ROOT\CLSID\{A21A8C43-1266-11D4-A324-0 040F6D487D9}\CMyCom
  (Default) "CMyCom"
  HKEY_CLASSES_ROOT\CLSID\{A21A8C43-1266-11D4-A324-0 040F6D487D9}\InprocServer32
  (Default) "C:\MASM32\MYCOM\MYCOM.DLL"
  ThreadingModel "Single"
  HKEY_CLASSES_ROOT\TypeLib\{A21A8C42-1266-11D4-A324 -0040F6D487D9}
  (Default) (value not set)
  HKEY_CLASSES_ROOT\TypeLib\{A21A8C42-1266-11D4-A324 -0040F6D487D9}\1.0
  (Default) "MyCom 1.0 Type Library"
  HKEY_CLASSES_ROOT\TypeLib\{A21A8C42-1266-11D4-A324 -0040F6D487D9}\1.0\0
  (Default) (value not set)
  HKEY_CLASSES_ROOT\TypeLib\{A21A8C42-1266-11D4-A324 -0040F6D487D9}\1.0\0\win32
  (Default) " C:\masm32\COM\MyCom \MYCOM.DLL"
  HKEY_CLASSES_ROOT\TypeLib\{A21A8C42-1266-11D4-A324 -0040F6D487D9}\1.0\FLAGS
  (Default) "O"
  HKEY_CLASSES_ROOT\TypeLib\{A21A8C42-1266-11D4-A324 -0040F6D487D9}\1.0\HELPDIR
  (Default) "C:\masm32\COM\MyCom"
  有一個鍵值是變化的,它是服務dll自身的路徑和文件名,在我的系統上,我把它放置在 "C:\MASM32\COM\MYCOM\MYCOM.DLL",當我注冊組件的時候,這個可以被檢測到,DllRegisterServer通過調用GetModuleFileName可以發現dll自身的存儲位置。
  這里有大量的信息是關于這個com服務的,但是我們僅僅需要傳遞{A21A8C43-1266-11D4-A324-0040F6D487D9}這個ID和一個有效的接口ID給CoCreateInstance函數來實例化我們的com服務。這個函數將會跟蹤注冊表設置,利用CLSID來發現創建組件需要的東西,一旦它創建了組件,它將加載類型庫,以獲取更多需要的信息。
  對我們來說非常幸運,最后的5個注冊入口項通過RegisterTypeLib函數可以完成。在DllRegisterServer中,我們通過一些列的注冊表函數來設置前面5項鍵值。然后調用RegisterTypeLib。 DllUnregisterServer函數刪除DllRegisterServer中的注冊表項,然后調用UnRegisterTypeLib。注意不要完全刪除HKEY_CLASSES_ROOT\CLSID\
  實現 Unknown
  AddRef_MC proc this_:DWORD
  mov eax, this_
  inc (MyComObject ptr [eax]).nRefCount
  mov eax, (MyComObject ptr [eax]).nRefCount
  ret ; note we return the object count
  AddRef_MC endp
  Release_MC proc this_:DWORD
  mov eax, this_
  dec (MyComObject ptr [eax]).nRefCount
  mov eax, (MyComObject ptr [eax]).nRefCount
  .IF (eax == 0)
  ; the reference count has dropped to zero
  ; no one holds reference to the object
  ; so let's delete it
  invoke CoTaskMemFree, this_
  dec MyCFObject.nRefCount
  xor eax, eax ; clear eax (count = 0)
  .ENDIF
  ret ; note we return the object count
  Release_MC endp
  MyCom自己的成員實現:
  GetValue proc this_:DWORD, pval:DWORD
  mov eax, this_
  mov eax, (MyComObject ptr [eax]).nValue
  mov edx, pval
  mov [edx], eax
  xor eax, eax ; return S_OK
  ret
  GetValue endp
  SetValue proc this_:DWORD, val:DWORD
  mov eax, this_
  mov edx, val
  mov (MyComObject ptr [eax]).nValue, edx
  xor eax, eax ; return S_OK
  ret
  SetValue endp
  RaiseValue PROC this_:DWORD, val:DWORD
  mov eax, this_
  mov edx, val
  add (MyComObject ptr [eax]).nValue, edx
  xor eax, eax ; return S_OK
  ret
  RaiseValue ENDP
  MyCom.dll, 這個com服務工程需要以下5個文件來編譯:
  MyCom.asm 匯編源程序
  MyCom.idl IDL文件,用于編譯產生MyCom.tlb
  MyCom.tlb 類型庫,需要一個rc資源文件
  rsrc.rc 資源文件,從中可以獲得類型庫信息
  MyCom.DEF 標準的dll輸出文件
  編譯后,代碼不會做任何事情,直到我們注冊它,我們可以使用命令行:
  regsvr32 MyCom.dll注冊。
  [三]用匯編語言訪問com對象
  大量的細節使得Com看上去很復雜,但是使用起來卻很簡單。最難的部分就是理解里面的數據結構,盡管COM是語言無關的,但是他借用了很多c++的術語來描述自己。
  為了能使用某個對象的com接口函數,你必須首先要從類廠中創建這個對象,并且讓他來返回接口指針。這個過程被CoCreateInstance這個API函數完成。當你使用完接口時,要調用Release方法。一個COM對象可以看作是一個服務,調用com的應用程序就是他的客戶端。
  在調用com接口函數之前,你需要了解接口是什么,一個com接口就是一個函數指針表,我們還是從IUnknown接口開始,如果你創建了一個組件導出了IUnknown接口,那么你就有了一個全功能的com對象。IUnknown有三個基本的幾口方法,既然所有的接口都是從它派生出來,那么我們一定要記住,一個接口實際上就是一個函數指針成員組成的結構體。
  例如:
  IUnknown STRUCT DWORD
  ; IUnknown methods
  IUnknown_QueryInterface QueryInterface_Pointer ?
  IUnknown_AddRef AddRef_Pointer ?
  IUnknown_Release Release_Pointer ?
  IUnknown ENDS
  它只有12個字節長,它具有3個DWORD指針來指向實際的實現函數。對于虛函數表,你一定聽說過,這些指針定義如下,因此我們可以讓masm在編譯我們的調用時進行一些類型檢查。
  QueryInterface_Pointer typedef ptr QueryInterface_Proto
  AddRef_Pointer typedef ptr AddRef_Proto
  Release_Pointer typedef ptr Release_Proto
  最后我們定義我們的函數如下:
  QueryInterface_Proto typedef PROTO :DWORD, :DWORD, :DWORD
  AddRef_Pointer typedef PROTO :DWORD
  Release_Pointer typedef PROTO :DWORD
  為了保持masm32松散的類型檢查一致,函數參數都定義為dword
  定義接口是一個相當大的編輯就是,masm不支持前向引用。因此,我們不得不顛倒一下定義的順序。先定義函數頭,再定義函數指針,最后定義接口。實際上在使用接口時,你需要一個指向它的指針。
  CoCreateInstance函數能用來直接返回一個接口指針。它實際上指向了擁有接口的對象。這個結構看上去如圖所示:
  這個結構里有大量的間接訪問,使用宏可以簡化它。
  當客戶端調用COM庫創建com組件時,它傳進了一個地址用于存放對象指針。這個就是我們所說的ppv. 從c++的角度來講,叫做指向指針的指針,void類型代表無類型。它保存了另一個指針pv的地址。pv指向了虛函數表。
  例如:我們使用CoCreateInstance函數成功的返回了一個接口指針ppv,我們想看下它是否支持其他的接口,我們可以調用QueryInterface方法。用c++的方法描述QueryInterface如下:
  (HRESULT) SomeObject::QueryInterface (this:pObject, IID:pGUID, ppv2:pInterface)
  用匯編寫法如下:
  ; get pointer to the object
  mov eax, ppv
  ; and use it to find the interface structure
  mov edx, [eax]
  ; push the function parameters onto the stack
  push OFFSET ppv2
  push OFFSET IID_ISomeOtherInterface
  push dword ppv
  ; and then call that method
  call dword ptr [edx + 0]
  使用invoke調用簡化如下:
  ; get pointer to the object
  mov eax, ppv
  ; and use it to find the interface structure
  mov edx, [eax]
  ; and then call that method
  invoke (IUnknown PTR [edx]).IUnknown_QueryInterface, ppv,
  ADDR IID_SomeOtherInterface, ADDR ppv_new
  注意IUnknown PTR [edx]這個類型轉換,是讓編譯器知道使用哪個結構來得到QueryInterface函數在虛表中的正確偏移。其中有一個模糊的地方,注意我修改了函數名字為"IUnknown_QueryInterface",這個名字修飾時必要的。當你有一個大的com工程,有許多相似的接口,你就會遇到麻煩。不同的接口對應不同的方法表示,是非常有效的。
  coinvoke 宏,這個宏定義在oaidl.inc文件中。使用它,可以進一步簡化com調用。
  ;------------------------------------------------- --------------------
  ; coinvoke MACRO
  ;
  ;
  ; pInterface pointer to a specific interface instance
  ; Interface the Interface's struct typedef
  ; Function which function or method of the interface to perform
  ; args all required arguments
  ; (type, kind and count determined by the function)
  ;
  coinvoke MACRO pInterface:REQ, Interface:REQ, Function:REQ, args:VARARG
  LOCAL istatement, arg
  FOR arg, ;; run thru args to see if edx is lurking in there
  IFIDNI ,
  .ERR
  ENDIF
  ENDM
  istatement CATSTR ,,
  IFNB ;; add the list of parameter arguments if any
  istatement CATSTR istatement, ,
  ENDIF
  mov edx, pInterface
  mov edx, [edx]
  istatement
  ENDM
  ;------------------------------------------------- --------------------
  因此,前面的QueryInterface方法調用就可以簡化成:
  coinvoke ppv ,IUnknown, QueryInterface, ADDR IID_SomeOtherInterface,
  ADDR ppnew
  注意這里名字修飾是隱藏在宏中處理的。
  代碼后面附上。。。

總結

以上是生活随笔為你收集整理的masm32开发com组件的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 丁香激情小说 | 国产一区999| 美景之屋电影免费高清完整韩剧 | 国产毛毛片 | 亚洲免费激情视频 | 午夜精品久久久久久久99黑人 | 超碰在线98 | 日韩精品123 | 黄色片在线观看免费 | 精品国产乱码久久久久久1区2区 | 亚洲精品丝袜 | 男人天堂五月天 | 亚洲精品中文字幕乱码三区91 | 国产成人99久久亚洲综合精品 | 视频一区国产 | 国产精品视频www | 香蕉影院在线 | 日韩av三区 | 中文字幕在线视频免费观看 | 在线观看免费国产 | 中文字幕日本一区 | 人妻无码一区二区三区久久 | 黑人精品欧美一区二区蜜桃 | xxx久久久| 第一福利视频 | 娇妻之欲海泛舟无弹窗笔趣阁 | 你懂的日韩 | 五月天综合 | 国产精品剧情 | 国产精品久久无码一三区 | 天堂在线观看中文字幕 | 亚洲免费一区二区 | 久久免费看少妇高潮 | 日韩欧美一区二区三区在线观看 | 精品xxxxx | 日本免费黄色片 | 国产日韩欧美在线观看 | 一区二区三区有限公司 | 三级无遮挡| 精品国产欧美一区二区三区成人 | 亚洲国产tv| 给我看高清的视频在线观看 | feel性丰满白嫩嫩hd | 亚洲AV成人无码精品久久盆瓶 | 美女视频黄的免费 | 射射av| 亚洲美女爱爱 | 超碰成人免费 | 日韩视频在线观看免费视频 | 操日本女人 | 狠狠插视频 | 国产黄色网址在线观看 | 日日操日日射 | 最近中文字幕 | 欧美激情图 | 一区av在线 | 三级黄色在线 | 动漫美女无遮挡免费 | 综合视频一区 | 一级做a爱片久久毛片 | 黄色综合网站 | h视频在线免费看 | 久久久久久久久久久久Av | 精品中文字幕在线播放 | 国产成人精品视频 | 亚洲天堂成人网 | 国产精品国产精品国产专区不片 | 狼人av在线 | 亚洲日本网站 | 日不卡 | 插插插日日日 | 先锋av资源在线 | 色94色欧美| 一区二区三区四区人妻 | 少妇与公做了夜伦理69 | 久久精品国产亚洲av麻豆图片 | 免费在线a | 久久免费在线视频 | 青青草97国产精品麻豆 | 日韩第一视频 | 国产大片中文字幕 | 饥渴丰满的少妇喷潮 | 欧美日韩在线视频观看 | 日本a级无毛 | 国产欧美一区二区三区在线看蜜臀 | 性开放耄耋老妇hd | 国产六区| 日本久热| 久久精品伦理 | 日本精品三级 | 天堂а√在线中文在线新版 | 中文不卡视频 | 91片看| 国产一级淫片a视频免费观看 | 男人激烈吮乳吃奶爽文 | 日韩视频在线免费播放 | va在线播放 | 123成人网 | 在线亚洲欧美 |