none
Comment faire tourner l'API BitBlt, et les API en général ? RRS feed

  • Question

  • Bonjour,

    C'est la première fois que j'utilise une API, je tente d'utiliser l'API BitBlt.dll mais j'ai deux erreur, comme suit :

    Option Explicit On
    Public Class Form2
     Private Declare Function BitBlt Lib "gdi32" ( _
          ByVal hDestDC As Long, _
          ByVal X As Long, _
          ByVal Y As Long, _
          ByVal nWidth As Long, _
          ByVal nHeight As Long, _
          ByVal hSrcDC As Long, _
          ByVal XSrc As Long, _
          ByVal YSrc As Long, _
          ByVal dwRop As Long) As Long
     Private Const SRCCOPY = &HCC0020
    ' ...
    
    Sub recopie()
    r = BitBlt(Me.hdc, 12, 193, PictureBox2.Width, PictureBox2.Height, PictureBox2.Image.hdc, 0, 0, SRCCOPY)
    End Sub
    

    Les erreurs sont ici :

    Me.hdc
    PictureBox2.Image.hdc
    

    Leur libellé est :

    HDC n'est pas un membre de WindowsApplication1.form2

    HDC n'est pas un membre de System.Drawing.Image

    Et si j'enlève HDC ça donne pour les deux :

    Ne peut pas être converti en Long.

    Le but est de copier tout le contenu de la pictureBox2 et de le balancer sur la form(Me) à x, y

    Merci si vous pouvez de me retaper cette ligne de code, qu'elle fonctionne ?

    Cordialement.


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    lundi 16 août 2010 22:06

Réponses

  • Clipboard.Image retourne une image (ni un IDataObject et encore moins un Point), le type de retour est visible dans Intellisense lorsqu'on tape le code. Pour cette partie, cela donne donc :

     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      If Clipboard.ContainsImage Then
       Me.PictureBox1.SizeMode = PictureBoxSizeMode.Zoom
       Me.PictureBox1.Image = Clipboard.GetImage
      End If
     End Sub
    
    

     J'ai posté il y a peu du code que tu devrais trouver ci-dessous pour traiter facilement la deuxième partie du problème (qui serait donc de récupérer la couleur qui correspond au point qui se trouve sous la souris, la difficulté étant que l'image a été mise à une autre échelle ?). Je copie donc l'aspect du contrôle PictureBox dans une image et j'utilise directement les coordonnées de la souris pour récupérer la couleur du pixel correspondant dans cette image.

    Accessoirement, je ne vois pas vraiment la différence avec VB6. Là aussi on a des contrôles qui vont s'afficher d'eux même sur le formulaire et comme dans VB6 il est possible éventuellement de supplanter ce mécanisme pour dessiner explicitement ce que l'on veut sur le formulaire. J'ai l'impression surtout que l'absence d'un objectif clair nous fait partir dans plein de directions.

    Notamment je suggère de demander de l'aide sur le problème exact que tu as. J'ai l'impression qu'ici tu as demandé de l'aide sur la mise en oeuvre d'une solution que tu avais déjà choisie et qui n'était pas forcément la plus simple.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    mardi 17 août 2010 12:28
    Modérateur

Toutes les réponses

  • Bonjour,

    Il faut passer par un objet Graphics :

    Dim b As Bitmap
    
    b = new Bitmap(PictureBox2.Width, PictureBox2.Length)
    
    Using g As Graphics = Graphics.FromImage(b)
    r = BitBlt(Me.hdc, 12, 193, PictureBox2.Width, PictureBox2.Height, g.GetHdc(), 0, 0, SRCCOPY)
      PictureBox2.Image = b;
    End Using
    

    Vous pouvez sinon utilisez la méthode Graphics.FromScreen() qui évite d'appeler la fonction BitBlt Windows : http://msdn.microsoft.com/fr-fr/library/system.drawing.graphics.copyfromscreen.aspx

    Cordialement


    Gilles TOURREAU - MVP C# - MCTS ADO .NET 3.5 - MCPD Windows Developper 3.5 - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    mardi 17 août 2010 06:47
    Modérateur
  • Bonjour Gilles,

    Merci, toutefois ça ne fonctionne pas :

    - Ça n'accepte pas  

    Me.hdc
    

    (hdc n'est pas un membre de indow.application.form2) ?

    - A quoi sert l'avant dernière ligne (p...2 = b), puisque c'est au niveau de la ligne d'avant que ça va écrire sur la form2 (quand la syntaxe sera acceptée) "r = ...", à quoi peut donc servir la ligne suivante une fois que le dessin est écrit ?

    Dim b As Bitmap
    b = new Bitmap(PictureBox2.Width, PictureBox2.Length)
    Using g As Graphics = Graphics.FromImage(b)
     r = BitBlt(Me.hdc, 12, 193, PictureBox2.Width, PictureBox2.Length, g.GetHdc(), 0, 0, SRCCOPY)
     PictureBox2.Image = b
    End Using
    
    

    RAJOUT

    Une autre commande ne fonctionne pas :

    PictureBox2.Length)
    Je présume qu'il faut remplacer par "Heignt" ?

    Cordialement.

     


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    • Modifié EhJoe mardi 17 août 2010 07:41 2 Précision
    mardi 17 août 2010 07:22
  • Bonjour,

    J'ai du mal à comprendre ce que vous souhaitez faire... Pourquoi Me.hdc ? Vous voulez prendre une capture d'écran et le mettre sur la fenêtre ? Ou dans une PictureBox ?

    Cordialement


    Gilles TOURREAU - MVP C# - MCTS ADO .NET 3.5 - MCPD Windows Developper 3.5 - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    mardi 17 août 2010 07:26
    Modérateur
  • Gilles,

    Pour ce qui est du lien et de la méthode graphique :

     http://msdn.microsoft.com/fr-fr/library/system.drawing.graphics.copyfromscreen.aspx

    Je ne comprends pas car les deux 1ers paramètres sont la position source et cible, certes, mais le troisième paramètre est la taille, ce qui ne veut rien dire !  Il faudrait pouvoir lui donner une longueur et une largeur (hauteur), sinon la taille... mais dans quel sens ? Peut être que Size accepte deux paramètres ?

    upperLeftSource
    Type : System.Drawing.Point
    Point situé dans l'angle supérieur gauche du rectangle source.
    
    upperLeftDestination
    Type : System.Drawing.Point
    Point situé dans l'angle supérieur gauche du rectangle de destination.
    
    blockRegionSize
    Type : System.Drawing.Size
    Taille de la zone à transférer.
    

    En fait je voudrais copier tous les pixels (position et couleur) de la pictureBox2 sur à forme courante (form2), à un endroit x, y dans le même ordre évidemment que la pictureBox2

    Peux-tu me donner un exemple qui fonctionne ?

    Merci, cordialement.

     


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    mardi 17 août 2010 07:38
  • Gilles, en réponse, voici ce que je veux faire :

    Copie tous les pixels de la form2.pictureBox2 dans l'ordre où ils sont et colle ce bloc sur la forme courante form2(à a position pixels x, y)

    Cordialement.


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    mardi 17 août 2010 07:47
  • Je serais d'accord avec Gilles. Avant de te lancer pourrais tu expliquer le but exact ?

    Suite à notre discussion précédente, un contrôle PictureBox ne sert qu'à afficher une image donc tu veux la couleur d'un point particulier sur lequel tu cliques dans un contrôle picture box (mais au milieu d'autres explications de choses que tu essayes et qui ne conviennent pas donc je ne suis pas sûr que cela soit bien ton problème), cela ne doit pas être trop difficile en examinant l'image originale quitte à transformer les coordonnées selon la façon dont l'image est affichée (cas de la mise à l'échelle).

    Au pire tous les contrôles disposent d'un méthode http://msdn.microsoft.com/en-us/library/system.windows.forms.control.drawtobitmap.aspx qui devrait permettre d'obtenir l'aspect exact de ce contrôle PictureBox dans une image.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    mardi 17 août 2010 08:19
    Modérateur
  •  

    Copie tous les pixels de la form2.pictureBox2 dans l'ordre où ils sont et colle ce bloc sur la forme courante form2(à a position pixels x, y)


    Au temps pour moi. Pour moi l'approche la plus simple serait :

    - d'ajouter un nouveau contrôle PictureBox dans le formulaire via code, de lui donner les coordonnées x,y voulues (et éventuellement autres propriétés utiles comme le mode de rendu) et notamment la même image comme source...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    mardi 17 août 2010 08:23
    Modérateur
  • Bonjour,

    Est ce que ce code là correspond à votre besoin ?

     Dim source As Point
     Dim dest As Point
    
     dest = New Point(10, 20)
     source = Me.PointToScreen(Me.PictureBox1.Location)
    
     Using g As Graphics = Me.CreateGraphics()
      g.CopyFromScreen(source, dest, New Size(Me.PictureBox1.Width, Me.PictureBox1.Height))
     End Using
    

    Cordialement


    Gilles TOURREAU - MVP C# - MCTS ADO .NET 3.5 - MCPD Windows Developper 3.5 - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    mardi 17 août 2010 08:33
    Modérateur
  • Gilles,

    Je t'ai envoyé un e-mail avec le code et les explications à "g...t...  @  pos.fr"

    Pour le code... je te dis, je vais regarder si ça tourne, mais en fait ce n'est pas à moi que ça n'allait pa, mais au compilateur :o)

    Cordialement.

     


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    mardi 17 août 2010 08:47
  • Bonjour Patrice,

    En fait c'est un truc étrange face auquel je suis, à l'origine je copiais tout simplement une copie d'écran dans le clipBoard, puis je restituais cette copie dans une picture en mode zoom afin que la picture ne faisant pas tout l'écran, j'ai néanmoisn la copie d'écran totale.

    Les problèmes ont commencé quand j'ai pipé dans cette picture zoomée, ça ne me rendait pas le bon pixel(couleur), après recherches j'ai compris, le mode zoom ne me rendait pas ce qu'il affaichait à l'écran mais ce qu'aurait affiché la picture en mode normal (soit disons en gros 1/3 décran), ce qui impliquait qu'en largeur par exemple, quand je pipais à la fin de l'image zoomée, il lisait un autre pixel (fin 1er tiers), il lisait ce qu'aurait affiché le mode normal (une partie de la copie)...

    Alors je me suis dit, je vais mettre deux images, une qui reçoit clipboard en zoom et une autre qui copie l'image réceptrice du presse-papiers, mais hélas ça revenait en mode normal (je perdais 2/3 d'écran); mais là ça pipais bien !

    De facto il y a ici peut être un moyen que je ne connais pas d'effectuer le transfert, moi, tout ce que j'ai vu, c'est de tenter de copier au pixel l'image zoumé (cete fois je copiais les bon pixels), et de la balancer soit sur la form, soit dans une autre picture, mais je ne savais pas le faire en vbNet, ah ah...

    Merci encore, cordialement.

     


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    mardi 17 août 2010 08:59
  • L'image source est absolument inchangée, le contrôle ne servant qu'afficher l'image.

    Mon approche serait de calculer les valeurs X et Y qui vont donner les coordonnées du point correspondant dans l'image originale, à partir des coordonnées x et y de la souris lorsqu'on clique sur la picture box.

    Cela nécessite d'être un peu méthodique mais cela ne devrait pas être trop compliqué. Il faut je pense :
    - calculer dans quel sens l'image a le ratio le plus petit, elle est centrée dans un sens ce qui donnera un décalage pour les coordonnées x ou y
    - utiliser ce ratio pour multiplier les coordonnées x,y de la souris
    - on devrait alors avoir les coordonnées X,Y qui indique quel est le point à aller tester dans l'image originale

    Cela doit être assez facile à trouver sur internet si cela n'est pas déjà intégré dans le contrôle PictureBox...

    Par exemple une recherche me donne :

    http://www.codeproject.com/KB/miscctrl/PictureBoxExtended.aspx (C3 mais voir surtout le principe)

    Et une fois que c'est fait le mettre dans sa boite à outils...

     


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    mardi 17 août 2010 09:37
    Modérateur
  • Gilles,

    Ça correspond caïman a mes besoins, sauf que ça a engendré la mise en valeur d'un autre problème, celui de la source pictureBox1, qui est masquée sur la feuille, puisque servant jute à ajuster en mode zoom, c'est à dire à faire tenir la copie d'écran totale dans la picture1.zoom qui est 3 fois plus petite, alors je dois désormais passer directement par le presse-papier (supprimant pictureBox1), et je ne sais pas l'inclure dans ta méthode, en plus, j'espère que ça va faire un effet zomm (rétrécissement), que le code va ajuster la copie d'écran du presse-papier à celle de la zone imposée (633 x 400) pixels ?

    Voici le code, si tu veux bien l'achever, enfin, je veux dire le terminer :o) merci ?

    'Dim source As Point = Me.PointToScreen(Me.PictureBox1.Location)
     Dim limage As IDataObject = Clipboard.GetDataObject()
     Dim source As Point = limage.GetFormats.Clone
     Dim cible As Point = New Point(12, 193)
     Using g As Graphics = Me.CreateGraphics()
      'g.CopyFromScreen(source, cible, New Size(Me.PictureBox1.Width, Me.PictureBox1.Height))
      g.CopyFromScreen(source, cible, New Size(633, 400))
    End Using
    

    Car

    = Clipboard.GetFormats.Clone
    
    

    C'est refusé, je ne sais absolument pas quoi mettre, j'ai mis au pif...

    Et si ce code ne fait pas l'effet zoom, rétrécissant la copie d'écran du clipboard, mettre stp un code qui effectue l'ajustement à la zone définie en 12, 193 de taille 633, 400, merci ;o)

    On y arrive, et ça m'apprend en même temps, c'est compliqué cet objet graphique par rapport à VB6 où c'était si simple, sauf qu'il fallait faire soi-même des changement de dimensions en calculant.

    Cordialement.


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    mardi 17 août 2010 10:20
  • Patrice,

    Attends, attends, la méthode de Gille est caïman aboutie, il manque juste une mise en forme de quelque mots de code, voire ma réponse à Gilles in fine, si d'ailleurs tu sais ?

    Cordialement.


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    mardi 17 août 2010 10:23
  • Je ne vois pas trop ce que le presse-papier vient faire là dedans. Je ne vois pas ce que tu cherches à faire avec GetFormats que je ne vois même pas dans la doc.

    Je ferais plutôt Clipboard.GetImage (avec un test sur ContainsImage d'abord par sécurité). La doc est là :

    http://msdn.microsoft.com/fr-fr/library/system.windows.forms.clipboard_members.aspx

    Cette image est-elle affectée à un picturebox ensuite ? (ou cette PictureBox est cachée auquel cas je ne vois pas trop l'intérêt, encore une fois ce contrôle sert à afficher une image, il ne modifie pas l'image affichée notamment sa taille).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    mardi 17 août 2010 10:59
    Modérateur
  • Patrice,

    Ben je connais assez bien vb6 mais peu vbNet, notamment du fait ici, qu'au lieu d'écrire sur la forme, on écrit dans une sorte de matrice graphique qu'on vide ensuite sur la form, le principe n'est pas du tout le même, alors je cherche le code au hasard d'Internet et je tente de le faire marcher, puis je viens ici quand ça coince, d'où le mot "GetFormat" qui fonctionne et que j'ai dû trouver dans un exemple...

    Le compilateur n'apprécie pas le code que tu me propose car il dit :

    Impossible d'effectuer un cast d'un objet de type 'System.Drawing.Bitmap' en type 'System.Windows.Forms.IDataObject'.

    à

    Dim limage As IDataObject = Clipboard.GetImage
    

    Et pas davantage pour la même raison à

    Dim source As Point = Clipboard.GetImage

     

    Je crois que c'est à cause de la méthode graphique, les source de code sont un mélange de deux classes que le compilateur semble peu apprécier, et je ne sais pas ce qu'il faut lui écrire pour concilier tout ça ?

    La question demeure :

    Comment coller la totalité du contenu image du presse-papiers issue d'une copie d'écran sur sa form à une position px, py en ajustant par rétrécissement (du tout), à une taille tx, ty ?

    La question est simple, mais pas la réponse en vbNet semble-t-il :o)

    Nota bene : En fait le problème demeure car à chaque solution ça démasque un nouveau problème pour le moment (1 la form zoomée ne donne pas les bon pixels de visu, puis 2 la forme zoomée et cachée servant de moulage à l'image ne fonctionne pas quand elle n'est pas visible sur la feuille (a contrario de vb6), puis en 3 on passe à l'objet graphique qui n'accepte pas les précédentes méthode pas trop compatibles ; et 4 : on en termine (j'espère), à coller le contenu du presse-papiers directement sur la form, la question subsidiaire est "quel va être le problème numéro 5", car en VB6 j'aurais déjà fini depuis longtemps)...

    Cordialement.

     

     


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    • Modifié EhJoe mardi 17 août 2010 11:31 modif 3 precisions
    mardi 17 août 2010 11:09
  • Donc personnellement une solution simple serait :

     Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
      Dim pb As PictureBox = DirectCast(sender, PictureBox)
      If pbImage Is Nothing Then
       pbImage = New Bitmap(pb.Width, pb.Height)
       pb.DrawToBitmap(pbImage, New Rectangle(0, 0, pb.Width, pb.Height))
      End If
      Label3.BackColor = pbImage.GetPixel(e.X, e.Y)
     End Sub
    

     Mais je ne suis pas sûr de comprendre ce que l'on veut faire. Pour l'instant je crois comprendre que l'on veut la couleur du pixel qui se trouve sous le pointeur de la souris dans un PictureBox. Donc je fais le rendu du PictureBox vers une image et j'utilise GetPixel sur cette image directement avec les coordonnées de la souris. Une autre approche serait donc de calculer x,y dans l'image originale. Je n'ai pas trop suivi celle que tu essaies actuellement de mettre en place avec Gilles.

    Je pars du principe que l'aspect "Presse-papiers etc..." fait partie de l'application mais ne concerne pas le point particulier que tu cherches à résoudre...


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    mardi 17 août 2010 11:49
    Modérateur
  • Clipboard.Image retourne une image (ni un IDataObject et encore moins un Point), le type de retour est visible dans Intellisense lorsqu'on tape le code. Pour cette partie, cela donne donc :

     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
      If Clipboard.ContainsImage Then
       Me.PictureBox1.SizeMode = PictureBoxSizeMode.Zoom
       Me.PictureBox1.Image = Clipboard.GetImage
      End If
     End Sub
    
    

     J'ai posté il y a peu du code que tu devrais trouver ci-dessous pour traiter facilement la deuxième partie du problème (qui serait donc de récupérer la couleur qui correspond au point qui se trouve sous la souris, la difficulté étant que l'image a été mise à une autre échelle ?). Je copie donc l'aspect du contrôle PictureBox dans une image et j'utilise directement les coordonnées de la souris pour récupérer la couleur du pixel correspondant dans cette image.

    Accessoirement, je ne vois pas vraiment la différence avec VB6. Là aussi on a des contrôles qui vont s'afficher d'eux même sur le formulaire et comme dans VB6 il est possible éventuellement de supplanter ce mécanisme pour dessiner explicitement ce que l'on veut sur le formulaire. J'ai l'impression surtout que l'absence d'un objectif clair nous fait partir dans plein de directions.

    Notamment je suggère de demander de l'aide sur le problème exact que tu as. J'ai l'impression qu'ici tu as demandé de l'aide sur la mise en oeuvre d'une solution que tu avais déjà choisie et qui n'était pas forcément la plus simple.


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".

    mardi 17 août 2010 12:28
    Modérateur
  • Bonjour,

    EhJoe, je vous prie de bien vouloir éviter de poser la même question sur différente conversations !

    Il devient difficile aux utilisateurs qui fréquentent constamment les forums de s'y retrouver...

    Un problème = Une discussion

    Merci pour votre compréhension

    Cordialement


    Gilles TOURREAU - MVP C# - MCTS ADO .NET 3.5 - MCPD Windows Developper 3.5 - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    mercredi 18 août 2010 08:11
    Modérateur
  • Gilles,

    Oui, je vais y veiller, mais en fait à cause d'impossibilités imprévues, le problème a tellement dévié que le titre de la question n'avait plus rien à voir avec les message (on partait d'une DLL) et on en est à (la méthode graphique pour coller sur un form)...

    Cordialement aussi.

     


    Joseph Attila PUSZTAY
    EhJoe       Logiciels       Romans       Ecrire
    mercredi 18 août 2010 08:26