[com] création d'un objet vide (qui ne fait rien) [masm,32bits+vs]

Description

Un code simple démontrons l'implémentation d'une classe COM dans une DLL.
Pour le compiler il vous faudra le Visual Studio car il nécessite MIDL pour compiler le fichier .IDL.
Le composant peut-être testé très facilement en appelant CoCreateInstance d'une source C++.
Je ne connais pas VB mais on dit qu'il ets très simple d'y incorporer des composants COM. Si quelqu'un sait comment faire, je me ferais un plaisir d'y mettre sa méthode.
L'ajout de fonctionnalités au composant se fait de manière quasi-intuitive (tout est relatif ;p). Il suffit de rajouter une entrée dans la VMT (il ne faut pas oublier le fichier .IDL).

note : la source ne comprend pas la routine de désenregistrement du composant et elle ne sera pas mis à jour pour l'incorporer (manque de temps et pour moi ce n'est pas primordial étant donné que je travail toujorus avec le même CLSID).

note 2 : le fichier .RC est fourni mais il vous faut compiler le fichier .IDL pour obtenir la TypeLib (.TLB)

note 3 : la présentation est laide sur le site mais pas dans la source donc downloadez le ZIP pour plus de clarté dans la lecture !

Source / Exemple :


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                      ;;
;;    Basic COM unique class implementation                             ;;
;;                                                                      ;;
;;  auteur : gblade/Garus Blade                                         ;;
;;                                                                      ;;
;;  description : bases d'un élément COM programmé en pur ASM           ;;
;;   nous n'étudierons ici que les éléments uniques/statics		;;
;;                                                                      ;;
;;  note : la routine de désenregistrement n'est pas implémentée        ;;
;;   il est à votre charge de nettoyer le registre                      ;;
;;   ou plus simplement d'écrire cette procédure par vous-même          ;;
;;                                                                      ;;
;;  note1 : ceci est une version de debuggage                           ;;
;;   ceci n'implique pas qu'elle ne soit pas fonctionnelle              ;;
;;   simplement, elle contient des élément de pistage d'erreurs         ;;
;;                                                                      ;;
;;  note2 : les labels ne sont pas tous appelés                         ;;
;;   ils sont présent à titre informatif pour facilité la relecture     ;;
;;                                                                      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.386                            ;nous utiliserons les instructions du 386
option casemap:none             ;respect de la casse
option language:syscall         ;convention de nommage SYSCALL (pas d'underscores)
option proc:private             ;visibilité des procédure mis à PRIVATE (seules les les fonctions exportées seront déclarées publiques)
option prologue:none            ;génération manuelle du code de prologue
option epilogue:none            ;génération manuelle du code d'épilogue

assume cs:flat,ds:flat,ss:flat,es:flat,fs:nothing,gs:nothing            ;model de segmentation FLAT (segment unique, model des modules win32)

;****************************************
;***** section importations (début) *****
;** il est conseillé d'utiliser les en-têtes prédéfinis (kernel32.inc, user32.inc, etc...)
;** les fonctions sont incluses ici manuellement pour une identifications plus rapide de l'apartenance à une librairie
;** les procédures importées sont classées par apartenance aux librairies

 extrn _GetModuleFileNameA@12:near
 GetModuleFileName equ <_GetModuleFileNameA@12>
 extrn _MultiByteToWideChar@24:near
 MultiByteToWideChar equ <_MultiByteToWideChar@24>
includelib kernel32.lib
 extrn _MessageBoxA@16:near
 MessageBox equ <_MessageBoxA@16>
includelib user32.lib
 extrn _IsEqualGUID@8:near
 IsEqualGUID equ <_IsEqualGUID@8>
includelib ole32.lib
 extrn _LoadTypeLib@8:near
 LoadTypeLib equ <_LoadTypeLib@8>
 extrn _RegisterTypeLib@12:near
 RegisterTypeLib equ <_RegisterTypeLib@12>
includelib oleaut32.lib
 extrn _RegCreateKeyA@12:near
 RegCreateKey equ <_RegCreateKeyA@12>
 extrn _RegSetValueA@20:near
 RegSetValue equ <_RegSetValueA@20>
 extrn _RegSetValueExA@24:near
 RegSetValueEx equ <_RegSetValueExA@24>
 extrn _RegCloseKey@4:near
 RegCloseKey equ <_RegCloseKey@4>
includelib advapi32.lib

;***** section importations (fin) *****
;**************************************

;*********************************************
;***** équivalences de fonctions (début) *****
;** ce sont les équivalence entre le nom court et le nom complet des fonctions qui le requiert

DllMain equ <_DllMain@12>               ;équivalence des noms court/complet de _DllMain@12

;***** équivalences de fonctions (fin) *****
;*******************************************

;**************************
;***** macros (début) *****

DEFINE_GUID macro name:req,l:req,w1:req,w2:req,b1:req,b2:req,b3:req,b4:req,b5:req,b6:req,b7:req,b8:req          ;macro de définition de GUIDs
 name:
  dd l
  dw w1
  dw w2
  db b1
  db b2
  db b3
  db b4
  db b5
  db b6
  db b7
  db b8
endm

trace macro msg:req             ;macro de debuggage
  push 0
  push offset msg
  push offset msg
  push 0
 call MessageBox
endm

;***** macros (fin) *****
;************************

;******************************
;***** constantes (début) *****
;** il est conseillé d'utiliser windows.inc

TRUE equ 1                                      ;vrai binaire
FALSE equ 0                                     ;faux binaire
NULL equ 0000h                                  ;adresse nulle
MAX_PATH equ 260                                ;nombre de caractères maximum pour un chemin
CP_ACP equ 0                                    ;page de code (caractères) ANSI
DLL_PROCESS_ATTACH equ 1                        ;attachement d'une DLL au même processus
HKEY_CLASSES_ROOT equ 80000000h                 ;clé prédéfinie HKEY_CLASSES_ROOT
REG_SZ equ 1                                    ;type chaîne de caractères pour une valeur de clé du registre
S_OK equ 0                                      ;code de retour sans erreur
S_FALSE equ 1                                   ;code de retour sans erreur indiquant une réponse négative de la fonction
E_FAIL equ 80004005h                            ;code d'erreur indiquant un échec
E_INVALIDARG equ 80070057h                      ;code d'erreur indiquant qu'un ou plusieurs des arguments passés à la procédure
E_POINTER equ 80000005h                         ;code d'erreur indiquant qu'un des pointeurs passés en argument à la procédure était invalide (avait une valeur nulle)
CLASS_E_CLASSNOTAVAILABLE equ 80040111h         ;code d'erreur indiquant que la classe (CLSID) demandée n'est pas pris en charge
CLASS_E_NOAGGREGATION equ 80040110h             ;code d'erreur indiquant que l'aggregation demandée n'est aps prise en charge
E_NOINTERFACE equ 80004002h                     ;code d'erreur indiquant que l'interface (IID) demandée n'est aps prise en charge
E_NOTIMPL equ 80000001h                         ;code d'erreur indiquant que la procédure demandée n'est pas prise en charge (n'est pas implémentée)

;***** constantes (fin) *****
;****************************

;*****************************************
;***** types supplémentaires (début) *****
;** ces types sont déclarés afin de facilité la lecture du code
;** il est possible d'utiliser windows.inc

handle typedef dword
pointer typedef dword
dp equ <dd>
char typedef byte
dc equ <db>
wchar typedef word

;***** types supplémentaires (fin) *****
;***************************************

;**********************************
;***** constantes POO (début) *****
;** ces constantes sont définies dans le but d'implémenter plus simplement la POO

_self equ <8[ebp]>              ;pointeur équivalent du pointeur this en C++

;***** constantes POO (fin) *****
;********************************

;***************************
;***** données (début) *****

_DATA segment dword public 'DATA'

 ;;chaînes de caractères ASCIIs
 $ProgID dc 'ProgID',0
 $ProgID_MyComponent dc 'MyComponent',0
 $Desc dc 'A simple COM component',0
 $CLSID dc 'CLSID',0
 $CLSID_MyComponent dc '{EDFC5B3D-FFE7-47b5-94D7-63BC8CA9355F}',0
 $Inproc dc 'InprocServer32',0
 $ThreadingModel dc 'ThreadingModel',0
 $ThreadingType dc 'Both',0
 
 ;;chaînes de dubuggage
 ;;ces chaînes devraient être supprimées si aucune utilité n'en est faites
 $dllmain dc 'DllMain',0
 $dllcanunloadnow dc 'DllCanUnloadNow',0
 $dllgetclassobject dc 'DllGetClassObject',0
 $queryfactory dc 'QueryInterface Factory',0
 $addfactory dc 'AddRef Factory',0
 $releasefactory dc 'Release Factory',0
 $createinstance dc 'CreateInstance',0
 $lockserver dc 'LockServer',0
 $queryinterface dc 'QueryInterface',0
 $addref dc 'AddRef',0
 $release dc 'Release',0
 
 ;;déclarations des GUIDs, les GUIDs ont été générés par uuidgen.exe de Microsoft
 DEFINE_GUID CLSID_MyComponent,0EDFC5B3Dh,0FFE7h,47b5h,94h,0D7h,63h,0BCh,8Ch,0A9h,35h,5Fh
 DEFINE_GUID IID_IUnknown,00000000h,0000h,0000h,0C0h,00h,00h,00h,00h,00h,00h,46h
 DEFINE_GUID IID_IClassFactory,00000001h,0000h,0000h,0C0h,00h,00h,00h,00h,00h,00h,46h
 DEFINE_GUID IID_IMyComponent,0EDFC5B3Eh,0ed8bh,4a9dh,0ach,0f7h,9eh,1dh,4fh,22h,0fch,90h
 
 ;;variables globales
 _hDllInstance dd NULL          ;handle de l'instance de la DLL
 
 _dwGlobalCount dd 0            ;ompteur global (valeur additionnée de tous les compteurs d'objets de la DLL)
 
 ;;objets statics/uniques et VMTs
 _ClassFactoryObject:                   ;objet static,unique ClassFactory
  dp offset _IClassFactoryVMT           ;pointeur sur la Virtual Methods Table (VMT) par défaut (IClassFactory)
  dd 0                                  ;compteur de l'objet
  
 _IClassFactoryVMT:                                     ;Virtual Methods Table (VMT) de l'interface IClassFactory
  dp QueryInterface@ClassFactory$IUnknown               ;méthode virtuelle QueryInterface, héritée de IUnknown
  dp AddRef@ClassFactory$IUnknown                       ;méthode virtuelle AddRef, héritée de IUnknown
  dp Release@ClassFactory$IUnknown                      ;méthode virtuelle Release, héritée de IUnknown
  dp CreateInstance@ClassFactory$IClassFactory          ;méthode virtuelle CreateInstance de interface par défaut IClassFactory
  dp LockServer@ClassFactory$IClassFactory              ;méthode virtuelle LockServer de interface par défaut IClassFactory
  
 _MyComponentObject:                    ;objet static,unique MyComponent
  dp offset _IMyComponentVMT            ;pointeur sur la Virtual Methods Table (VMT) par défaut (IClassFactory)
  dd 0                                  ;compteur de l'objet
  
 _IMyComponentVMT:                                      ;Virtual Methods Table (VMT) de l'interface IMyComponent
  dp QueryInterface@MyComponent$IUnknown                ;méthode virtuelle QueryInterface, héritée de IUnknown
  dp AddRef@MyComponent$IUnknown                        ;méthode virtuelle AddRef, héritée de IUnknown
  dp Release@MyComponent$IUnknown                       ;méthode virtuelle Release, héritée de IUnknown
 
_DATA ends

;***** données (fin) *****
;*************************

;************************
;***** code (début) *****

_TEXT segment para use32 public 'CODE'

 ;;point d'entrée de la DLL
 public DllMain                 ;déclare la routine publique pour exportation (voir fichier DEF)
  _hModuleInstance$=8           ;instance de la DLL
  _dwReason$=12                 ;raison de l'appel
  _pReserved$=16                ;réservé
 DllMain proc near
  @entry:
  push ebp                      ;initialise la pile
  mov ebp,esp
  
  @processing:
  ;trace $dllmain
  
  mov eax,handle ptr _hModuleInstance$[ebp]             ;charge dans le handle global l'instance de la DLL
  mov handle ptr [_hDllInstance],eax
  
  xor eax,eax
  cmp dword ptr _dwReason$[ebp],DLL_PROCESS_ATTACH              ;vérifie la raison de l'appel
  sete al                                                       ;réagit en conséquence
  
  @exit:
  pop ebp               ;restore EBP
  retn 12               ;enlève les arguments passés à la fonction
 DllMain endp
 
 ;;routine d'enregistrement de la classe COM
 public DllRegisterServer               ;déclare la routine publique pour exportation (voir fichier DEF)
 DllRegisterServer proc near
  _hKey?ProgID?$=-4                     ;handle destiné à contenir la clé HKEY_CLASSES_ROOT\%ProgID%
  _hKeyCLSID$=-4                        ;handle destiné à contenir la clé HKEY_CLASSES_ROOT\CLSID
  _hKeyCLSID?GUID?Inproc$=-4            ;handle destiné à contenir la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\InprocServer32
  _hKeyCLSID?GUID?ProgID$=-4            ;handle destiné à contenir la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\ProgID
  _hKey?ProgID?CLSID$=-8                ;handle destiné à contenir la clé HKEY_CLASSES_ROOT\%ProgID%\CLSID
  _hKeyCLSID?GUID?$=-8                  ;handle destiné à contenir la clé HKEY_CLASSES_ROOT\CLSID\%GUID%
  _pTypeLib$=-12                        ;pointeur sur une interface ITypeLib
  _szDllPath$=-(MAX_PATH+12)            ;chaîne de caractères ASCII destinée à contenir le chemin complet de la DLL
  _wcDllPath$=-(MAX_PATH*2+12)          ;chaîne de caractères Unicode destinée à contenir le chemin complet de la DLL
  @entry:
  push ebp                              ;initialise la pile
  mov ebp,esp
  add esp,-(MAX_PATH*2+12)              ;réserve l'espace sur la pile pour les variables locales
  
  @processing:
   lea eax,handle ptr _hKey?ProgID?$[ebp]               ;crée/ouvre la clé HKEY_CLASSES_ROOT\%ProgID%
   push eax
   push offset $ProgID_MyComponent
   push HKEY_CLASSES_ROOT
  call RegCreateKey
  test eax,eax
  jnz @exit
  
   push 22                                      ;assigne à la clé HKEY_CLASSES_ROOT\%ProgID% la description du composant
   push offset $Desc
   push REG_SZ
   push NULL
   push handle ptr _hKey?ProgID?$[ebp]
  call RegSetValue
  test eax,eax
  jnz @exit
  
   lea eax,handle ptr _hKey?ProgID?CLSID$[ebp]          ;crée/ouvre la clé HKEY_CLASSES_ROOT\%ProgID%\CLSID
   push eax
   push offset $CLSID
   push handle ptr _hKey?ProgID?$[ebp]
  call RegCreateKey
  test eax,eax
  jnz @exit
  
   push 38                                              ;assigne à la clé HKEY_CLASSES_ROOT\%ProgID%\CLSID le CLSID de notre composant
   push offset $CLSID_MyComponent
   push REG_SZ
   push NULL
   push handle ptr _hKey?ProgID?CLSID$[ebp]
  call RegSetValue
  test eax,eax
  jnz @exit
  
   push handle ptr _hKey?ProgID?CLSID$[ebp]             ;ferme la clé HKEY_CLASSES_ROOT\%ProgID%\CLSID
  call RegCloseKey                                      ;cela nous permet également d'employer la mémoire précédemment occupée par la variable
  test eax,eax                                          ;ici, nous emploirons jusqu'à quatre fois le même emplacement mémoire sous quatre noms différents
  jnz @exit
  
   push handle ptr _hKey?ProgID?$[ebp]          ;ferme la clé HKEY_CLASSES_ROOT\%ProgID%
  call RegCloseKey
  test eax,eax
  jnz @exit
  
   lea eax,handle ptr _hKeyCLSID$[ebp]          ;crée/ouvre la clé HKEY_CLASSES_ROOT\CLSID
   push eax
   push offset $CLSID
   push HKEY_CLASSES_ROOT
  call RegCreateKey
  test eax,eax
  jnz @exit
  
   lea eax,handle ptr _hKeyCLSID?GUID?$[ebp]            ;crée/ouvre la clé HKEY_CLASSES_ROOT\CLSID\%GUID%
   push eax
   push offset $CLSID_MyComponent
   push handle ptr _hKeyCLSID$[ebp]
  call RegCreateKey
  test eax,eax
  jnz @exit
  
   push 22                                              ;assigne à la clé HKEY_CLASSES_ROOT\CLSID\%GUID% la description du composant
   push offset $Desc
   push REG_SZ
   push NULL
   push handle ptr _hKeyCLSID?GUID?$[ebp]
  call RegSetValue
  test eax,eax
  jnz @exit
  
   push handle ptr _hKeyCLSID$[ebp]             ;ferme la clé HKEY_CLASSES_ROOT\CLSID
  call RegCloseKey
  test eax,eax
  jnz @exit
  
   lea eax,handle ptr _hKeyCLSID?GUID?Inproc$[ebp]              ;crée/ouvre la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\InprocServer32
   push eax
   push offset $Inproc
   push handle ptr _hKeyCLSID?GUID?$[ebp]
  call RegCreateKey
  test eax,eax
  jnz @exit
  
   push MAX_PATH                                ;récupère le chemin complet de la DLL à partir de son instance
   lea eax,char ptr _szDllPath$[ebp]
   push eax
   push handle ptr [_hDllInstance]
  call GetModuleFileName
  test eax,eax
  setz al
  jz @exit
  
   push MAX_PATH                                        ;assigne à la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\InprocServer32 le chemin complet du composant (de la DLL)
   lea eax,char ptr _szDllPath$[ebp]
   push eax
   push REG_SZ
   push NULL
   push handle ptr _hKeyCLSID?GUID?Inproc$[ebp]
  call RegSetValue
  test eax,eax
  jnz @exit
  
   push 4                                               ;ajoute à la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\InprocServer32 la chaîne ThreadingModel ayant pour valeur "Both"
   push offset $ThreadingType
   push REG_SZ
   push 0
   push offset $ThreadingModel
   push handle ptr _hKeyCLSID?GUID?Inproc$[ebp]
  call RegSetValueEx
  test eax,eax
  jnz @exit
  
   push handle ptr _hKeyCLSID?GUID?Inproc$[ebp]         ;ferme la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\InprocServer32
  call RegCloseKey
  test eax,eax
  jnz @exit
  
   lea eax,handle ptr _hKeyCLSID?GUID?ProgID$[ebp]              ;crée/ouvre la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\ProgID
   push eax
   push offset $ProgID
   push handle ptr _hKeyCLSID?GUID?$[ebp]
  call RegCreateKey
  test eax,eax
  jnz @exit
  
   push 9                                               ;assigne à la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\ProgID le ProgID (qui est en fait le nom) de notre composant
   push offset $ProgID_MyComponent
   push REG_SZ
   push NULL
   push handle ptr _hKeyCLSID?GUID?ProgID$[ebp]
  call RegSetValue
  test eax,eax
  jnz @exit
  
   push handle ptr _hKeyCLSID?GUID?ProgID$[ebp]         ;ferme la clé HKEY_CLASSES_ROOT\CLSID\%GUID%\ProgID
  call RegCloseKey
  test eax,eax
  jnz @exit
  
   push handle ptr _hKeyCLSID?GUID?$[ebp]               ;ferme la clé HKEY_CLASSES_ROOT\CLSID\%GUID%
  call RegCloseKey
  test eax,eax
  jnz @exit
  
   push MAX_PATH                                ;convertit la chaîne ASCII contenant le chemin complet de notre DLL en chaîne Unicode
   lea eax,wchar ptr _wcDllPath$[ebp]
   push eax
   push -1
   lea eax,char ptr _szDllPath$[ebp]
   push eax
   push 0
   push CP_ACP
  call MultiByteToWideChar
  test eax,eax
  setz al
  jz @exit
  
   lea eax,pointer ptr _pTypeLib$[ebp]          ;charge la Type Library
   push eax
   lea eax,wchar ptr _wcDllPath$[ebp]
   push eax
  call LoadTypeLib
  test eax,eax
  jnz @exit
  
   push NULL                                    ;enregistre la Type Library
   lea eax,wchar ptr _wcDllPath$[ebp]
   push eax
   push pointer ptr _pTypeLib$[ebp]
  call RegisterTypeLib
  test eax,eax
  jnz @exit
  
   mov eax,pointer ptr _pTypeLib$[ebp]          ;libère le pointeur d'interface ITypeLib
   push eax
  mov ecx,pointer ptr [eax]
  call near ptr [ecx+2*4]
  
  xor eax,eax           ;retourne S_OK
  
  @exit:
  mov esp,ebp           ;restore EBP
  pop ebp
  retn
 DllRegisterServer endp
 
 ;;routine de vérification avant-libération de la DLL (traduction très mauvaise si quelqu'un propose autre chose...)
 public DllCanUnloadNow
 DllCanUnloadNow proc near
  @entry:
  @processing:
  ;trace $dllcanunloadnow
  
  xor eax,eax
  cmp dword ptr [_dwGlobalCount],eax            ;teste si le compteur global est à zero
  setne al                                      ;réagit en conséquence
  
  @exit:
  retn
 DllCanUnloadNow endp
 
 ;;routine de récupération de la classe fabrique (IClassFactory)
 public DllGetClassObject
  _pCLSID$=8		;classe demandée
  _pIID$=12		;interface demandée
  _ppObject$=16		;pointeur sur pointeur de l'interface, destiné à recevoir l'objet
 DllGetClassObject proc near
  @entry:
  push ebp		;initialise la pile
  mov ebp,esp
  
  @test:
  ;trace $dllgetclassobject
  
   push offset CLSID_MyComponent		;teste la validité de la classe (CLSID) demandé
   push pointer ptr _pCLSID$[ebp]
  call IsEqualGUID
  test eax,eax
  jnz @processing				;réagit en conséquence
  
  mov eax,pointer ptr _ppObject$[ebp]		;remplit le pointeur avec une valeur nulle
  mov pointer ptr [eax],NULL
  mov eax,CLASS_E_CLASSNOTAVAILABLE		;retourne l'erreur E_CLASSNOTAVAILABLE (classe non-supportée)
  jmp @exit
  
  @processing:
   push pointer ptr _ppObject$[ebp]		;demande une interface pour la classe MyComponent
   push pointer ptr _pIID$[ebp]
   push offset _ClassFactoryObject
  call QueryInterface@ClassFactory$IUnknown
  
  @exit:
  pop ebp		;restore EBP
  retn 12		;enlève les arguments passés à la fonction de la pile
 DllGetClassObject endp
 
 ;;fonction de demande d'interface pour l'objet ClassFactory
  _pIID$=12		;interface demandée
  _ppObject$=16		;pointeur sur pointeur de l'interface, destiné à recevoir l'objet
 QueryInterface@ClassFactory$IUnknown proc near
  @entry:
  push ebp		;initialise la pile
  mov ebp,esp
  
  @test:
  ;trace $queryfactory
  
   push offset IID_IUnknown			;teste la validité de l'ineterface demandée
   push pointer ptr _pIID$[ebp]
  call IsEqualGUID
  test eax,eax
  jnz @processing
   push offset IID_IClassFactory
   push pointer ptr _pIID$[ebp]
  call IsEqualGUID
  test eax,eax
  jnz @processing				;réagit en conséquence
  
  mov eax,pointer ptr _ppObject$[ebp]		;remplit le pointeur avec une valeur nulle
  mov pointer ptr [eax],NULL
  mov eax,E_NOINTERFACE				;retourne l'erreur E_NOINTERFACE (interface indisponible)
  jmp @exit
  
  @processing:
  inc dword ptr [_ClassFactoryObject+4]		;incrémente le compteur de l'objet ClassFactory (nous venons de créer une nouvelle inetrface)
  inc dword ptr [_dwGlobalCount]		;incrémente le compteur global
  
  mov eax,pointer ptr _ppObject$[ebp]				;remplit le pointeur avec l'adresse de l'objet ClassFactory
  mov pointer ptr [eax],offset _ClassFactoryObject
  xor eax,eax							;retournbe S_OK
  
  @exit:
  pop ebp		;restore EBP
  retn 12		;enlève les arguments passés à la fonction de la pile
 QueryInterface@ClassFactory$IUnknown endp
 
 ;;fonction d'incrémentation du compteur de l'objet ClassFactory
 AddRef@ClassFactory$IUnknown proc near
  @entry:
  @processing:
  ;trace $addfactory
  
  inc dword ptr [_ClassFactoryObject+4]		;incrémente le compteur de l'objet ClassFactory
  inc dword ptr [_dwGlobalCount]		;incrémente le compteur global
  
  @exit:
  mov eax,dword ptr [_ClassFactoryObject+4]		;retourne la valeur du compteur
  retn 4						;enlève les arguments passés à la fonction de la pile
 AddRef@ClassFactory$IUnknown endp
 
 ;;fonction de libération/nettoyage de l'objet ClassFactory (cette fonction joue le rôle de destructeur quand la classe n'est pas unique/statique; ici, nous nou contenterons de décrémenter le compteur)
 Release@ClassFactory$IUnknown proc
  @entry:
  @processing:
  ;trace $releasefactory
  
  dec dword ptr [_ClassFactoryObject+4]		;incrémente le compteur de l'objet ClassFactory
  dec dword ptr [_dwGlobalCount]		;incrémente le compteur global
  
  @exit:
  mov eax,dword ptr [_ClassFactoryObject+4]		;retourne la valeur du compteur
  retn 4						;enlève les arguments passés à la fonction de la pile
 Release@ClassFactory$IUnknown endp
 
 ;;fonction de création d'instances
  _pUnkwn$=12		;pointeur IUnknown (pour les aggregates)
  _pIID$=16		;interface demandée
  _ppObject$=20		;pointeur sur pointeur de l'interface, destiné à recevoir l'objet
 CreateInstance@ClassFactory$IClassFactory proc near
  @entry:
  push ebp		;initialise la pile
  mov ebp,esp
  
  @test:
  ;trace $createinstance
  
  cmp pointer ptr _pUnkwn$[ebp],NULL		;teste la présence du pointeur sur IUnknown (et du même coup la demande d'aggregate)
  je @processing				;réagit en conséquence
  
  mov eax,pointer ptr _ppObject$[ebp]		;remplit le pointeur avec une valeur nulle
  mov pointer ptr [eax],NULL
  mov eax,CLASS_E_NOAGGREGATION			;retourne l'erreur CLASS_E_NOAGGREGATION (aggregations non-supportées)
  jmp @exit
  
  @processing:
   push pointer ptr _ppObject$[ebp]			;demande une interface pour l'objet MyComponent
   push pointer ptr _pIID$[ebp]
   push offset _MyComponentObject
  call QueryInterface@MyComponent$IUnknown
  
  @exit:
  pop ebp		;restore EBP
  retn 16		;enlève les arguments passés à la fonction de la pile
 CreateInstance@ClassFactory$IClassFactory endp
 
 ;;fonction de vérouillage du serveur (de l'objet ClassFactory; étant donné que notre objet est static, nous nous contenterons de simuler l'action de cette fonction)
  _dwAction$=12
 LockServer@ClassFactory$IClassFactory proc near
  @entry:
  @test:
  ;trace $lockserver
  
  cmp dword ptr _dwAction$[ebp],FALSE		;teste l'action souhaitée
  je @processing$unlock				;réagit en conséquence
  
  @processing$lock:
  inc dword ptr [_ClassFactoryObject+4]		;incrémente le compteur de l'objet ClassFactory
  inc dword ptr [_dwGlobalCount]		;incrémente le compteur global
  
  @processing$unlock:
  dec dword ptr [_ClassFactoryObject+4]		;décrémente le compteur de l'objet ClassFactory
  dec dword ptr [_dwGlobalCount]		;décrémente le compteur global
  
  @exit:
  xor eax,eax		;retourne S_OK
  ret 8			;enlève les arguments passés à la fonction de la pile
 LockServer@ClassFactory$IClassFactory endp
 
 ;;fonction de demande d'interface pour l'objet MyComponent
  _pIID$=12		;interface demandée
  _ppObject$=16		;pointeur sur pointeur de l'interface, destiné à recevoir l'objet
 QueryInterface@MyComponent$IUnknown proc near
  @entry:
  push ebp		;initialise la pile
  mov ebp,esp
  
  @test:
  ;trace $queryinterface
  
   push offset IID_IUnknown		;teste la validité de l'interface demandée
   push pointer ptr _pIID$[ebp]
  call IsEqualGUID
  test eax,eax
  jnz @processing
   push offset IID_IMyComponent
   push pointer ptr _pIID$[ebp]
  call IsEqualGUID
  test eax,eax
  jnz @processing			;réagit en conséquence
  
  mov eax,pointer ptr _ppObject$[ebp]		;remplit le pointeur avec une valeur nulle
  mov pointer ptr [eax],NULL
  mov eax,E_NOINTERFACE				;retourne E_NOINTERFACE (interface non-supportée)
  jmp @exit
  
  @processing:
  inc dword ptr [_MyComponentObject+4]		;incrémente le compteur de l'objet MyComponent
  inc dword ptr [_dwGlobalCount]		;incrémente le compteur global
  
  mov eax,pointer ptr _ppObject$[ebp]				;remplit le pointeur avec l'adresse de l'objet MyComponent
  mov pointer ptr [eax],offset _MyComponentObject
  xor eax,eax							;retourne S_OK
  
  @exit:
  pop ebp		;restore EBP
  retn 12		;enlève les arguments passés à la fonction de la pile
 QueryInterface@MyComponent$IUnknown endp
 
 ;;fonction d'incrémentation du compteur de l'objet MyComponent
 AddRef@MyComponent$IUnknown proc near
  @entry:
  @processing:
  ;trace $addref
  
  inc dword ptr [_MyComponentObject+4]		;incrémente le compteur de l'objet MyComponent
  inc dword ptr [_dwGlobalCount]		;incrémente le compteur global
  
  @exit:
  mov eax,dword ptr [_MyComponentObject+4]		;retourne la valeur du compteur
  retn 4						;enlève les arguments passés à la fonction de la pile
 AddRef@MyComponent$IUnknown endp
 
 ;;fonction de libération/nettoyage d'interface de l'objet MyComponent
 Release@MyComponent$IUnknown proc
  @entry:
  @processing:
  ;trace $release
  
  dec dword ptr [_MyComponentObject+4]		;décrémente le compteur de l'objet MyComponent
  dec dword ptr [_dwGlobalCount]		;décrémente le compteur global
  
  @exit:
  mov eax,dword ptr [_MyComponentObject+4]		;retourne la valeur du compteur
  retn 4						;enlève les arguments passés à la fonction de la pile
 Release@MyComponent$IUnknown endp
 
_TEXT ends

end DllMain

Conclusion :


J'avais oublié de dire, laissez moi un commentaire que je sache ce qui va pas ;) Dans mon style de prog aussi (mais me dites pas d'utiliser la syntaxe simplifiée pour faire plus claire ^^).

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.