XL 2013 api createmetafile ne fonctionne pas comme createenHmetafile

Boostez vos compétences Excel avec notre communauté !

Rejoignez Excel Downloads, le rendez-vous des passionnés où l'entraide fait la force. Apprenez, échangez, progressez – et tout ça gratuitement ! 👉 Inscrivez-vous maintenant !

patricktoulon

XLDnaute Barbatruc
Bonjour à tous
j'ai un soucis avec la sauvegarde directe d'un object (shape picture, etc..) en WMF sans passer par olecreatepictureindirect
si quelqu'un sait je prends

VB:
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As LongPtr) As LongPtr
Private Declare PtrSafe Function CopyMetaFileA Lib "gdi32" (ByVal hmf As LongPtr, ByVal lpFileName As String) As LongPtr
Private Declare PtrSafe Function DeleteEnhMetaFile Lib "gdi32" (ByVal hEmf As LongPtr) As Long
Private Declare PtrSafe Function IsClipboardFormatAvailable Lib "user32" (ByVal Format As Long) As Long

'LA FONCTION POUR LE FORMAT WMF
Function copyObjToWmfFile(obj As Object, Optional cheminX = "")
    Dim hMeta As LongPtr, hCopy As LongPtr
    If cheminX = "" Then cheminX = ThisWorkbook.Path & "\captureObject.Wmf"
    ' Copier la shape au format Metafile
    OpenClipboard (0): EmptyClipboard: CloseClipboard
    obj.CopyPicture
    ' Récupérer l'image en Metafile dans le presse papier et le sauve vers un fichier
    If OpenClipboard(0) Then
       Debug.Print "available in clip : " & IsClipboardFormatAvailable(&H3)
       If IsClipboardFormatAvailable(&H3) = 0 Then MsgBox " pas de meta dans le clip": Exit Function
       hMeta = GetClipboardData(&H3) ' VF_METAFILE = 0x3 (format WMF)soit au format Hex "&H3"
        Debug.Print "Handle hMeta : " & hMeta
        If hMeta <> 0 Then hCopy = CopyMetaFileA(hMeta, cheminX) ' Copier l'EMF dans un fichier
        Debug.Print "hcopy : " & hCopy
        DeleteEnhMetaFile hCopy ' Libérer la mémoire
    End If
    CloseClipboard ' Fermer le presse-papiers
    copyObjToWmfFile = cheminX
End Function

Sub TestF()
    copyObjToWmfFile ActiveSheet.Shapes("boule"), Environ("userprofile") & "\DeskTop\wmfboule.wmf"
End Sub
 
Solution
Oui j'ai fait un test et ca fonctionnait mais désolé le code que j'ai tapé n'"était pas précis , il faut récupérer l'adresse de la structure METAFILEPICT
ensuite ajouter un décalage de 12 octets qui correspondent aux 3 Longint pour avoir finalement l'adresse du handle de meafile je pense que c'est assez intuitif .

Code:
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As LongPtr) As LongPtr
Private Declare PtrSafe Function CopyMetaFileA Lib "gdi32" (ByVal hmf As LongPtr...
c'est normal c'est pas la bonne fonction il faut utiliser CopyEnhMetaFile. Voici un code qui fonctionne chez moi et c'est pas du wmf qui est généré c'est de l'emf chez moi.
VB:
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As LongPtr) As LongPtr
Private Declare PtrSafe Function CopyMetaFileA Lib "gdi32" (ByVal hmf As LongPtr, ByVal lpFileName As String) As LongPtr
Private Declare PtrSafe Function DeleteEnhMetaFile Lib "gdi32" (ByVal hEmf As LongPtr) As Long
Private Declare PtrSafe Function IsClipboardFormatAvailable Lib "user32" (ByVal Format As Long) As Long
Private Declare PtrSafe Function CopyEnhMetaFile Lib "gdi32" Alias "CopyEnhMetaFileA" (ByVal hemfSrc As LongPtr, ByVal lpszFile As String) As LongPtr

'LA FONCTION POUR LE FORMAT EMF
Function copyObjToEmfFile(obj As Object, Optional cheminX = "")
    Dim hMeta As LongPtr, hCopy As LongPtr
    If cheminX = "" Then cheminX = ThisWorkbook.path & "\captureObject.emf"
    ' Copier la shape au format Metafile
    OpenClipboard (0): EmptyClipboard: CloseClipboard
    obj.CopyPicture xlScreen, XLPicture
    ' Récupérer l'image en Metafile dans le presse papier et le sauve vers un fichier
    If OpenClipboard(0) Then
       Debug.Print "available in clip : " & IsClipboardFormatAvailable(14)
       If IsClipboardFormatAvailable(14) = 0 Then MsgBox " pas de meta dans le clip": Exit Function
       hMeta = GetClipboardData(14) ' CF_ENHMETAFILE = 14 (format EMF)soit au format 14
        Debug.Print "Handle hMeta : " & hMeta
        If hMeta <> 0 Then hCopy = CopyEnhMetaFile(hMeta, cheminX) ' Copier l'EMF dans un fichier
        Debug.Print "hcopy : " & hCopy
        DeleteEnhMetaFile hCopy ' Libérer la mémoire
    End If
    CloseClipboard ' Fermer le presse-papiers
    copyObjToEmfFile = cheminX
End Function
 
re non CopyenHmetafile te sort un EMF pas un WMF sinon tu pense bien que je l'aurait gardé mon ancienne version

car pour sortir un vrai wmf avec copyenHmetafile il faut le restructurer avec olecreatepictureindirect comme je fait avec ma fonction perso copyXlPicture

il y a deux api
VB:
Private Declare PtrSafe Function CopyEnhMetaFileA Lib "gdi32" (ByVal HwndImage As LongPtr, ByVal Direction As String) As LongPtr
Private Declare PtrSafe Function CopyMetaFileA Lib "gdi32" (ByVal hmf As LongPtr, ByVal lpFileName As String) As LongPtr
l'une pour le emf et l'autre pour le wmf
l'une attend un CF_METAFILEPICT = 3 "&H3"pour Copymetatfile
et l'autre attend un CF_ENHMETAFILE = 14 "&HE" pour CopyenHmetatfile
 
Dernière édition:
re non CopyenHmetafile te sort un EMF pas un WMF sinon tu pense bien que je l'aurait gardé mon ancienne version

car pour sortir un vrai wmf avec copyenHmetafile il faut le restructurer avec olecreatepictureindirect comme je fait avec ma fonction perso copyXlPicture
Hello,
je sens que tu va galérer à vouloir exploiter le CF_METAFILEPICTURE.
En fait ce que tu récupère en lisant ce format en provenance du presse-papiers c'est un pointeur vers une structure
voici en c++ (je n'ai pas trouvé de code en VBA) la structure
C++:
typedef struct tagMETAFILEPICT {
  LONG      mm;
  LONG      xExt;
  LONG      yExt;
  HMETAFILE hMF;
} METAFILEPICT, *LPMETAFILEPICT;

et un moyen de lire les données :
C++:
HGLOBAL hMetaFilePict = GetClipboardData(CF_METAFILEPICT);
if (hMetaFilePict != NULL) {
    METAFILEPICT* metaFilePict = (METAFILEPICT*)GlobalLock(hMetaFilePict);
    if (metaFilePict != NULL) {
        HGLOBAL hMetaFileBits = GetMetaFileBitsEx(metaFilePict->hMF);
        if (hMetaFileBits != NULL) {
            // Use the hMetaFileBits to create an EMF or WMF
            HENHMETAFILE hEnhMetaFile = SetWinMetaFileBits(GlobalSize(hMetaFileBits), (BYTE*)GlobalLock(hMetaFileBits));
            // Handle the hEnhMetaFile as needed
            GlobalUnlock(hMetaFileBits);
        }
        GlobalUnlock(hMetaFilePict);
    }
}
Et je n'ai pas trouvé de code où les données était enregistrées dans un fichier. Seulement en visualisation.

Bon courage ! et est-ce que cela en vaut vraiment la peine ? car le CF_ENHMETAFILE est beaucoup plus facile à exploiter et permet de sauvegarder en format vectoriel emf équivalent.
J'ai essayé le code que j'ai mis plus haut avec la forme étoile dans un Excel 2010 sous Win7 , le fichier est bien généré c'est un emf il fait 2ko et on peut l'insérer en image dans Excel.
Ami calmant, J.P
 
Oui j'ai fait un test et ca fonctionnait mais désolé le code que j'ai tapé n'"était pas précis , il faut récupérer l'adresse de la structure METAFILEPICT
ensuite ajouter un décalage de 12 octets qui correspondent aux 3 Longint pour avoir finalement l'adresse du handle de meafile je pense que c'est assez intuitif .

Code:
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As LongPtr) As LongPtr
Private Declare PtrSafe Function CopyMetaFileA Lib "gdi32" (ByVal hmf As LongPtr, ByVal lpFileName As String) As LongPtr
Private Declare PtrSafe Function DeleteEnhMetaFile Lib "gdi32" (ByVal hEmf As LongPtr) As Long
Private Declare PtrSafe Function IsClipboardFormatAvailable Lib "user32" (ByVal Format As Long) As Long
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As Long
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (Destination As Any, ByVal Source As LongPtr, ByVal Length As LongPtr)
 
'LA FONCTION POUR LE FORMAT WMF
Function copyObjToWmfFile(obj As Object, Optional cheminX = "")
    Dim hMeta As LongPtr, hCopy As LongPtr, hGlobal As LongPtr
    If cheminX = "" Then cheminX = ThisWorkbook.Path & "\captureObject.Wmf"
    ' Copier la shape au format Metafile
    OpenClipboard (0): EmptyClipboard: CloseClipboard
    obj.CopyPicture
    ' Récupérer l'image en Metafile dans le presse papier et le sauve vers un fichier
    If OpenClipboard(0) Then
       Debug.Print "available in clip : " & IsClipboardFormatAvailable(&H3)
       If IsClipboardFormatAvailable(&H3) = 0 Then MsgBox " pas de meta dans le clip": Exit Function
        hGlobal = GetClipboardData(&H3) ' VF_METAFILE = 0x3 (format WMF)soit au format Hex "&H3"
        hMeta = GlobalLock(hGlobal)
        GlobalUnlock hGlobal
        RtlMoveMemory hMeta, hMeta + 12, Len(hMeta)
        Debug.Print "Handle hMeta : " & hMeta
        If hMeta <> 0 Then hCopy = CopyMetaFileA(hMeta, cheminX) ' Copier l'EMF dans un fichier
        Debug.Print "hcopy : " & hCopy
        DeleteEnhMetaFile hCopy ' Libérer la mémoire
    End If
    CloseClipboard ' Fermer le presse-papiers
    copyObjToWmfFile = cheminX
End Function

Par contre le fichier créé n'est pas fermé par DeleteEnhMetaFile et a partir de ce moment cette solution basé surCopMetaFile n'est plus tres pratique essaie de copier les données de l'image dans un vecteur ensuite enregistrer-le , regarde du coté GetMetaFileBitsEx
 
Dernière édition:
Oui j'ai fait un test et ca fonctionnait mais désolé le code que j'ai tapé n'"était pas précis , il faut récupérer l'adresse de la structure METAFILEPICT
ensuite ajouter un décalage de 12 octets qui correspondent aux 3 Longint pour avoir finalement l'adresse du handle de meafile je pense que c'est assez intuitif .

Par contre le fichier créé n'est pas fermé par DeleteEnhMetaFile et a partir de ce moment cette solution basé surCopMetaFile n'est plus tres pratique essaie de copier les données de l'image dans un vecteur ensuite enregistrer-le , regarde du coté GetMetaFileBitsEx
Très bien Rheem cela fonctionne maintenant.
Alors j'ai fait le test sous Excel 2016 Windows 11 :
1 - Avec une forme (l'étoile) :
Le fichier généré par mon code et par ton code sont des emf de taille équivalente (2ko)
2 - Avec une forme contenant une image WMF (le bébé d'une autre discussion taille initiale 26 ko)
Avec mon code un emf de 58 Ko est généré pas de problème pour le lire.
Avec ton code un wmf de 82 Ko est généré pas de problème pour le lire et identique visuellement au précédent.

Donc à voir si cela offre un intérêt de générer un Wmf.
 
je ne peux que plussoyer @Rheem👏👍💪

alors en effet en wmf le travail est plus long
2.59 kilo en WMF
1.26 kilo en EMF
mais bon c'est bon de les avoir ces fonctions
j'ai donc 2 fonctions WMF

1 wmf convertie avec olecreatepictureindirect

2 wmf avec rtlmovememory et copymetafile

3 emf avec copyenHmetafile

4 bitmap avec olecreatepictureindirect et le clist pour la structure dispatch

5 png avec le strzam du tableau de bit dans un fichier avec open for en binaire
 
et pour conclure on ajoute la petite soeur a deleteenHmetafile ("deletemetafile") qui fait la même chose sauf que l'on travaille en WMF
VB:
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As LongPtr) As LongPtr
Private Declare PtrSafe Function CopyMetaFileA Lib "gdi32" (ByVal hmf As LongPtr, ByVal lpFileName As String) As LongPtr
Private Declare PtrSafe Function DeleteEnhMetaFile Lib "gdi32" (ByVal hEmf As LongPtr) As Long
Private Declare PtrSafe Function IsClipboardFormatAvailable Lib "user32" (ByVal Format As Long) As Long
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As Long
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (Destination As Any, ByVal Source As LongPtr, ByVal Length As LongPtr)
Private Declare PtrSafe Function DeleteMetaFile Lib "GDI32.dll" (ByVal hmf As LongPtr) As Long

'LA FONCTION POUR LE FORMAT WMF
Function copyObjToWmfFile2(obj As Object, Optional cheminX = "")
    Dim hMeta As LongPtr, hCopy As LongPtr, hGlobal As LongPtr
    If cheminX = "" Then cheminX = ThisWorkbook.Path & "\captureObject.Wmf"
    ' Copier la shape au format Metafile
    OpenClipboard (0): EmptyClipboard: CloseClipboard
    obj.CopyPicture
    ' Récupérer l'image en Metafile dans le presse papier et le sauve vers un fichier
    If OpenClipboard(0) Then
        If IsClipboardFormatAvailable(&H3) = 0 Then MsgBox " pas de meta dans le clip": Exit Function
        hGlobal = GetClipboardData(&H3) ' VF_METAFILE = 0x3 (format WMF)soit au format Hex "&H3"
        hMeta = GlobalLock(hGlobal): GlobalUnlock hGlobal
        RtlMoveMemory hMeta, hMeta + 12, Len(hMeta)
        If hMeta <> 0 Then hCopy = CopyMetaFileA(hMeta, cheminX) ' Copier l'EMF dans un fichier
        Debug.Print "hcopy : " & hCopy
        If hCopy <> 0 Then DeleteMetaFile hCopy
    End If
    CloseClipboard ' Fermer le presse-papiers
    copyObjToWmfFile2 = cheminX
End Function

Sub TestG()
    copyObjToWmfFile2 ActiveSheet.Shapes("boule"), Environ("userprofile") & "\DeskTop\wmfboule.wmf"
End Sub

et woila jouste oun pti peee d'ochoooode
 
et voila je partage avec vous ma collection de fonction images
VB:
'*****************************************************************************************************
'    ___     _     _______  __      _   ____  _   _  _______  ___     _   _   _    ___     _     _.
'   //  \\  /\\      //    // \\   //  //    //  //    //    //  \\  //  //  //   //  \\  //|   //
'  //___// //__\    //    //__//  //  //    //__//    //    //   // //  //  //   //   // // |  //
' //      //   \\  //    //  \\  //  //    //  \\    //    //   // //  //  //   //   // //  | //
'//      //    // //    //   // //  //___ //    \\  //     \\__// //__//  //___ \\__// //   |//
'****************************************************************************************************
'Module de copie en image (JPG / EMF / WMF / PNG / BMP) de tout object sur feuille(Range / Shapes / Graphique /  etc...)
's'en servir dans un control image dans un userform
'ou exporter
'patricktoulon sur developpez.com
'utilisation d'un  clisd pour la structure IPictureIID pour le Bitmap
'date/22/03/2010
'remasteurisation du code date: 12/09/2023
'api creation object image
'mise ajour 18/09/2023
'ajout de la fonction copyObjToEmfFile( fichier ".EMF")
'abandon du vb6
'mise  à  jour 15/11/2024
'Ajout de la fonction CopyPngPicture
'ajout de l'export en WMF directe
'intervenant
'@patricktoulon
'@jurassic pork
'@Rhemm
 
Option Explicit
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As LongPtr) As Long
Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As LongPtr) As LongPtr
Private Declare PtrSafe Function RegisterClipboardFormatW Lib "user32" (ByVal lpszFormat As LongPtr) As Long
Private Declare PtrSafe Function IsClipboardFormatAvailable Lib "user32" (ByVal Format As Long) As Long
Private Declare PtrSafe Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long

Private Declare PtrSafe Function CopyEnhMetaFileA Lib "gdi32" (ByVal HwndImage As LongPtr, ByVal Direction As String) As LongPtr
Private Declare PtrSafe Function CopyMetaFileA Lib "gdi32" (ByVal hmf As LongPtr, ByVal lpFileName As String) As LongPtr
Private Declare PtrSafe Function DeleteMetaFile Lib "GDI32.dll" (ByVal hmf As LongPtr) As Long
Private Declare PtrSafe Function DeleteEnhMetaFile Lib "gdi32" (ByVal hEmf As LongPtr) As Long
Private Declare PtrSafe Function CopyImage Lib "user32" (ByVal handle As LongPtr, ByVal un1 As LongPtr, ByVal n1 As LongPtr, ByVal n2 As LongPtr, ByVal un2 As LongPtr) As LongPtr
Private Declare PtrSafe Function OleCreatePictureIndirect Lib "oleaut32.dll" (pPictDesc As PICTDESC, ByRef riid As GUID, ByVal fOwn As Long, ByRef ppvObj As IPicture) As Long
Private Declare PtrSafe Function IIDFromString Lib "ole32" (ByVal lpsz As String, ByRef lpiid As GUID) As LongPtr

Private Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, ByVal dwBytes As Long) As LongPtr
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As Long
Private Declare PtrSafe Function GlobalSize Lib "kernel32" (ByVal hMem As LongPtr) As Long
Private Declare PtrSafe Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByVal Destination As LongPtr, ByVal Source As LongPtr, ByVal Length As Long)
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (Destination As Any, ByVal Source As LongPtr, ByVal Length As LongPtr)

Type RECT: Left As Long: top As Long: Right As Long: BOTTOM As Long: End Type
Type GUID: Data1 As Long: Data2 As Integer: Data3 As Integer: Data4(0 To 7) As Byte: End Type
Type PICTDESC: cbSize As Long: picType As Long: hImage As LongPtr: hpal As LongPtr: End Type


'--------------------------------------------------------------------------------------------------------
'--------------------------------------------------------------------------------------------------------
'LA FONCTION POUR LE FORMAT WMF renvoi un object IpictureDisp
Function copyxlPicture(obj, Optional lPath As String = "") As IPicture
    '@patricktoulon
    Dim hCopy As LongPtr, PictStructure As PICTDESC, DispatchInfo As GUID, ipic As IPicture, T#
    obj.CopyPicture
    OpenClipboard 0
    T = Timer
    Do While hCopy = 0
        hCopy = CopyEnhMetaFileA(GetClipboardData(&HE), vbNullString)
        If Timer - T > 1 Then Exit Do
    Loop
    CloseClipboard
    If hCopy = 0 Then Set copyxlPicture = ipic: Exit Function ' si pas de handleimage WMF dans clip on arrete tout
    With DispatchInfo
        .Data1 = &H7BF80980: .Data2 = &HBF32: .Data3 = &H101A: .Data4(0) = &H8B: .Data4(1) = &HBB
        .Data4(2) = &H0: .Data4(3) = &HAA: .Data4(4) = &H0: .Data4(5) = &H30: .Data4(6) = &HC: .Data4(7) = &HAB
    End With
    With PictStructure: .cbSize = Len(PictStructure): .picType = 4: .hImage = hCopy: .hpal = 0: End With
    OleCreatePictureIndirect PictStructure, DispatchInfo, True, ipic
    Set copyxlPicture = ipic
    If lPath <> "" Then SavePicture ipic, lPath: Set ipic = Nothing
    OpenClipboard 0: EmptyClipboard: CloseClipboard
End Function

'--------------------------------------------------------------------------------------------------------
'--------------------------------------------------------------------------------------------------------
'LA FONCTION POUR LE FORMAT EMF
Function copyObjToEmfFile(obj As Object, Optional cheminX = "")
    '@patricktoulon
    '@jurassic pork
    Dim hMeta As LongPtr, hCopy As LongPtr
    If cheminX = "" Then cheminX = ThisWorkbook.Path & "\captureObject.emf"
    ' Copier la shape au format Metafile
    obj.CopyPicture
    ' Récupérer l'image en Metafile dans le presse papier et le sauve vers un fichier
    If OpenClipboard(0) Then
        hMeta = GetClipboardData(&HE) ' CF_ENHMETAFILE = 0x14 (format EMF)soit au format Hex "&HE"
        If hMeta <> 0 Then hCopy = CopyEnhMetaFileA(hMeta, cheminX) ' Copier l'EMF dans un fichier
        DeleteEnhMetaFile hCopy ' Libérer la mémoire
    End If
    CloseClipboard ' Fermer le presse-papiers
    copyObjToEmfFile = cheminX
End Function

'LA FONCTION POUR LE FORMAT WMF
Function copyObjToWmfFile2(obj As Object, Optional cheminX = "")
   '@Rheeem
   '@Patricktoulon
   Dim hMeta As LongPtr, hCopy As LongPtr, hGlobal As LongPtr
    If cheminX = "" Then cheminX = ThisWorkbook.Path & "\captureObject.Wmf"
     OpenClipboard (0): EmptyClipboard: CloseClipboard 'vide le clipboard
    obj.CopyPicture ' Copier la shape au format Metafile
      ' Récupérer l'image en Metafile dans le presse papier et le sauve vers un fichier
    If OpenClipboard(0) Then
        If IsClipboardFormatAvailable(&H3) = 0 Then MsgBox " pas de meta dans le clip": Exit Function
        hGlobal = GetClipboardData(&H3) ' VF_METAFILE = 0x3 (format WMF)soit au format Hex "&H3"
        hMeta = GlobalLock(hGlobal): GlobalUnlock hGlobal
        RtlMoveMemory hMeta, hMeta + 12, Len(hMeta)
        If hMeta <> 0 Then hCopy = CopyMetaFileA(hMeta, cheminX) ' Copier l'EMF dans un fichier
           If hCopy <> 0 Then DeleteMetaFile hCopy
    End If
    CloseClipboard ' Fermer le presse-papiers
    copyObjToWmfFile2 = cheminX
End Function

'--------------------------------------------------------------------------------------------------------
'--------------------------------------------------------------------------------------------------------
'LA FONCTION POUR LE FORMAT BMP
Function CopyBitmapPicture(obj As Object, Optional lPath As String = "")
    'patricktoulon
    Dim ipic As IPicture, hCopy&, tIID As GUID, PictStructure As PICTDESC, x#, ret&
    Call OpenClipboard(0): EmptyClipboard: CloseClipboard
    obj.CopyPicture Format:=xlBitmap
    OpenClipboard 0&
    x = Timer
    Do While (hCopy = 0)
        hCopy = CopyImage(GetClipboardData(&H2), 0, 0, 0, &H8)
        If Timer - x > 1 Then Exit Do
    Loop
    CloseClipboard
    If hCopy = 0 Then Set CopyBitmapPicture = ipic: Exit Function
    Const IPictureIID = "{7BF80981-BF32-101A-8BBB-00AA00300CAB}"
    ret = IIDFromString(StrConv(IPictureIID, vbUnicode), tIID)
    If ret Then Set CopyBitmapPicture = ipic: Exit Function
    With PictStructure: .cbSize = Len(PictStructure): .picType = 1: .hImage = hCopy: End With
    ret = OleCreatePictureIndirect(PictStructure, tIID, 1, ipic)
    If ret Then Set CopyBitmapPicture = ipic: Exit Function
    Set CopyBitmapPicture = ipic
    If lPath <> "" Then SavePicture ipic, lPath: Set ipic = Nothing
    OpenClipboard 0: EmptyClipboard: CloseClipboard
End Function

'--------------------------------------------------------------------------------------------------------
'--------------------------------------------------------------------------------------------------------
'LA FONCTION POUR LE FORMAT PNG
Public Function CopyPngPicture(obj As Object, lPath As String, Optional RangeTransparency As Boolean = False) As Variant
    'patricktoulon
    Dim i&, hClipMemory As LongPtr, lpClipMemory As LongPtr, memSize As Long, apiRetVal As Long, dataFormat, tmpBuffer() As Byte
    If TypeName(obj) = "Range" Then
        obj.CopyPicture ' on reste en xlpicture par defaut(la capture est de meilleure qualité)
        obj.Parent.Paste 'on recole sur la feuille
        If Not RangeTransparency Then
            Selection.ShapeRange.Fill.ForeColor.RGB = vbWhite 'on mremet le fond en blanc
            Selection.ShapeRange.Fill.Visible = True 'le fond est visible
        End If
        Selection.Copy 'on recopie la capture donc une image (copy tout court pour disposer des formats dans le clipboard)
        Selection.Delete 'on peut supprimer l'image temporaire
        Do Until IsClipboardFormatAvailable(14) > 0 Or i > 1000: i = i + 1: DoEvents: Loop
    Else
        obj.Copy 'si c'est une shapes , picture , ou tout autre object(sauf range) on copy tout court
    End If
    dataFormat = RegisterClipboardFormatW(StrPtr("PNG"))
    If Not CBool(OpenClipboard(0)) Then MsgBox "L'Ouverture tu ClipBord a échoué": CopyPngPicture = False: Exit Function
    If Not CBool(IsClipboardFormatAvailable(dataFormat)) Then MsgBox "Aucun Png dispo dans le clipboard": CopyPngPicture = False: Exit Function
    hClipMemory = GetClipboardData(dataFormat)
    If Not CBool(hClipMemory) Then MsgBox "Aucun Stream de Png dispo dans le clipboard": CopyPngPicture = False: Exit Function
    memSize = GlobalSize(hClipMemory)
    lpClipMemory = GlobalLock(hClipMemory)
    If CBool(lpClipMemory) Then
        ReDim tmpBuffer(0 To memSize - 1) As Byte
        Call CopyMemory(VarPtr(tmpBuffer(0)), lpClipMemory, memSize)
        apiRetVal = GlobalUnlock(hClipMemory)
    Else
        MsgBox " Récupération du STREAM du png a echoué": Exit Function
    End If
    Open lPath For Binary Access Write As #1: Put #1, 1, tmpBuffer: Close #1
    CopyPngPicture = lPath
    EmptyClipboard
    CloseClipboard
End Function

Sub ListClipboardDisponibleFormats()
    'patricktoulon
    Dim formatID As Long
    OpenClipboard 0
    formatID = EnumClipboardFormats(0)

    Do While formatID <> 0
        Debug.Print "Format disponible : " & Hex(formatID)
        formatID = EnumClipboardFormats(formatID)
    Loop
    CloseClipboard
End Sub

exemple de sub de tests
VB:
'*****************************************************************************************************
'    ___     _     _______  __      _   ____  _   _  _______  ___     _   _   _    ___     _     _.
'   //  \\  /\\      //    // \\   //  //    //  //    //    //  \\  //  //  //   //  \\  //|   //
'  //___// //__\    //    //__//  //  //    //__//    //    //   // //  //  //   //   // // |  //
' //      //   \\  //    //  \\  //  //    //  \\    //    //   // //  //  //   //   // //  | //
'//      //    // //    //   // //  //___ //    \\  //     \\__// //__//  //___ \\__// //   |//
'****************************************************************************************************

'                                       MODULE DE TESTS

Sub TestA()
    copyxlPicture ActiveSheet.Shapes("boule"), Environ("userprofile") & "\DeskTop\wmfboule.wmf"
End Sub

Sub testAb()
    With UserForm1
        .Show 0
        .Image1.Picture = copyxlPicture(ActiveSheet.Shapes("boule"))
    End With
End Sub


Sub TestB()
    copyObjToEmfFile ActiveSheet.Shapes("boule"), Environ("userprofile") & "\desktop\emfboule.emf" ' À remplacer selon le bon index
End Sub

Sub TestC()
    CopyPngPicture ActiveSheet.Shapes("boule"), Environ("userprofile") & "\desktop\output.png"
End Sub

Sub TestD()
    CopyPngPicture [A1:C7], Environ("userprofile") & "\desktop\output2.png" ', True'le 3eme argumen(true/false) pour laisser la transparence pour les range
End Sub

Sub TestE()
    CopyBitmapPicture ActiveSheet.Shapes("boule"), Environ("userprofile") & "\desktop\output.bmp"
End Sub

Sub TestF()
    copyObjToWmfFile2 ActiveSheet.Shapes("boule"), Environ("userprofile") & "\DeskTop\wmfboule.wmf"
End Sub
voila un sujet fini
 
- Navigue sans publicité
- Accède à Cléa, notre assistante IA experte Excel... et pas que...
- Profite de fonctionnalités exclusives
Ton soutien permet à Excel Downloads de rester 100% gratuit et de continuer à rassembler les passionnés d'Excel.
Je deviens Supporter XLD

Discussions similaires

Réponses
46
Affichages
2 K
Réponses
7
Affichages
531
Réponses
7
Affichages
1 K
Retour