Problème de BackgroundWorker

Résolu
cs_LaNono Messages postés 37 Date d'inscription mardi 30 septembre 2008 Statut Membre Dernière intervention 26 avril 2011 - 5 déc. 2008 à 11:57
cs_LaNono Messages postés 37 Date d'inscription mardi 30 septembre 2008 Statut Membre Dernière intervention 26 avril 2011 - 5 déc. 2008 à 16:30
Bonjour à tous,

J'ai un programme qui effectue une traitement en boucle et durant ce traitement, il peut faire des opérations comme :
- Dessiner sur un composant graphics et sauvegarder ce fichier sur le disque
- Créer une capture d'écran

Si je n'utilise pas de multitâche, le traitement se passe très bien, les images sont créées et sauvées.

Comme le traitement dur un certain temps, j'ai insérer ce traitement dans un multithread à l'aide du composant BackgroundWorker. qui me permet d'avoir un bouton "Annuler" en cours du traitement

Mon problème est que depuis que j'utilise ce composant, des exceptions sont levées lorsque j'utilise l'instruction Save d'un objet bitmap et que la lecture de données dans le presse papier (Au moment de la capture d'écran) me retourne une valeur nulle.

Quelqu'un connait-il la raison de cette erreur? peut-on accéder à l'OS (Système de fichier, clipboard) depuis une application multithread?

merci d'avance

6 réponses

cs_LaNono Messages postés 37 Date d'inscription mardi 30 septembre 2008 Statut Membre Dernière intervention 26 avril 2011 1
5 déc. 2008 à 16:30
Re !

Alors j'ai résolu mon problème grâce à ce lien :
http://social.technet.microsoft.com/Forums/en-US/netfxbcl/thread/112578d1-9011-4a5c-b4d9-1911cb683995/

Apparemment, mon problème vient du fait que BackgroundWorker travaille avec des threads en mode MTA alors qu'ils doivent être en mode STA pour accéder au clipboard.
j'ai pas tout compris mais tout fonctionne maintenant ;-)

merci encore pour ton aide
3
Le newbie Messages postés 200 Date d'inscription mardi 17 octobre 2006 Statut Membre Dernière intervention 24 mars 2012 2
5 déc. 2008 à 12:15
Salut,

Si tu pouvais nous donner les exception qui sont levées on pourrait plus t'aider.
Ensuite, est ce que tu fais ton le traitement de capture dans le background worker c'est à dire prise de l'image et enregistrement du fichier. Ou est ce que tu fais la capture dans le background et la sauvegarde dans ton thread principal.

Il me semble que tu dois tout faire dans le background worker puisque les seuls échanges possibles entre tes threads sont des entiers qui te permettent de connaître l'état d'avancmeent de ton thread dérivé. Cela expliquerait peut être pourquoi ta capture est NULL.

Un tuto sympa sur l'utilisation du BG : http://glarde.developpez.com/dotnet/bgworker/vb/

Tiens nous au courant. 
0
cs_LaNono Messages postés 37 Date d'inscription mardi 30 septembre 2008 Statut Membre Dernière intervention 26 avril 2011 1
5 déc. 2008 à 13:35
Hello,

merci de ta réponse!

J'effectue l'entier du traitement des images dans le BackgroundWorker

l'exception levée lorsque j'utilise l'expression :

MonBitmap.Save(FileName, Imaging.ImageFormat.Bmp)

est la suivante :

L'exception System.Runtime.InteropServices.ExternalException n'a pas été gérée par le code utilisateur
ErrorCode=-2147467259
Message="Une erreur générique s'est produite dans GDI+."
Source="System.Drawing"
StackTrace:
à System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
à System.Drawing.Image.Save(String filename, ImageFormat format)
à DocumentationGOelan.DGToolImageManager.DGToolImageManager_DrawTool(String FileName, DGImageGOelan Image) dans D:\work\petignat_tp_goelan_trunk\Application\DocumentationGOelan\DocumentationGOelan\DGToolImageManager.vb:ligne 572
à DocumentationGOelan.DGGOelanManager.DGGOelanManager_SetGOelanGammeValues(List`1& Controls, List`1& GOelanImages, DGPaper& Paper, List`1& ReturnedDataList, List`1& ReturnedImageList, Int32 ProgressMaxValue, Int32& ProgressCurrentValue, BackgroundWorker& Worker, DoWorkEventArgs& WorkerEvent) dans D:\work\petignat_tp_goelan_trunk\Application\DocumentationGOelan\DocumentationGOelan\DGGOelanManager.vb:ligne 810
à DocumentationGOelan.DGGenerationFrm.DGGenerationFrm_ReadGOelanData(BackgroundWorker ReadWorker, DoWorkEventArgs WorkerEvent) dans D:\work\petignat_tp_goelan_trunk\Application\DocumentationGOelan\DocumentationGOelan\DGGenerationFrm.vb:ligne 150
à DocumentationGOelan.DGGenerationFrm.bgwBackground_DoWork(Object sender, DoWorkEventArgs WorkerEvent) dans D:\work\petignat_tp_goelan_trunk\Application\DocumentationGOelan\DocumentationGOelan\DGGenerationFrm.vb:ligne 183
à System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
à System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)

Concernant le clipboard, je l'utilise de la manière suivante :


Call keybd_event(System.Windows.Forms.Keys.Snapshot, 0, 0, 0)

data = Clipboard.GetDataObject()


Lorsque je suis dans le BackgroundWorker, data est à nothing alors qu'il contient l'image prise par la capture d'écran si je n'utilise pas de background worker

J'avoue que je suis un peu paumée (Disons que ces histoires de multitâche n'ont jamais vraiment été claires pour moi ;-) )

As-tu une idée de mon problème?
Merci encore
0
Le newbie Messages postés 200 Date d'inscription mardi 17 octobre 2006 Statut Membre Dernière intervention 24 mars 2012 2
5 déc. 2008 à 14:03
Merci des détails que tu as donné.

1. Est ce que tu as le même problème en faisant : System.Windows.Forms.Keys.PrintScreen

2. As tu bien mis un as New à ta déclaration de Data ?

2. Remplace ta déclaration de data en un truc du style

Dim MaBmp as New System.Drawing.Bitmap(picImage.Image)
En gros un objet de type image quoi comme ici http://msdn.microsoft.com/en-us/library/9t4syfhh.aspx

Un exemple de quelqu'un qui a contourné le même problème que toi : http://www.developpez.net/forums/d129067/dotnet/csharp/windows-forms/csharp-erreur-gdip/

Personnelement, comme tu peux le voir, je ne pense en aucun cas que cela puisse venir du BGW. Je pense que c'est un pb de code. Cependant tu as l'air de dire que cela marche.

PS : hésite pas à mettre un petit peu plus de code histoire qu'on comprènnent bien. Voir tes déclarations, des procédures complètes et si tu as des données confidentielles, tu les rempace par des XXXXXX par exemple mais n'hésite pas à en mettre plus.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_LaNono Messages postés 37 Date d'inscription mardi 30 septembre 2008 Statut Membre Dernière intervention 26 avril 2011 1
5 déc. 2008 à 15:41
Re!

En fait, je crois que je me suis mal exprimée, je vais suivre ton conseil et mettre plus de code ;-)

Les deux erreurs que j'ai décrites se passent à deux endroits et pour deux tâches complètement différentes

Première erreur : Bitmap.save
------------------------------

Je viens de résoudre cette erreur :

En fait, comme j'ajoute la gestion avec le BackgroundWorker petit à petit, j'ai commenter toute la suite de mon code qui me prenait beaucoup de temps
Du coup, juste après que j'enregistre le bitmap, je n'ai plus rien à faire et je me retrouve à la fin de la fonction qui lance mon thread.

Le problème c'est qu'à la fin de cette fonction, une ligne de code supprime ces images, car elles sont temporaires
Ce qui s'est passé, c'est que les images étaient supprimées alors que leur enregistrement n'était même pas terminé. d'où l'erreur.

Deuxième erreur : Réalisation d'une capture d'écran
---------------------------------------------------

Le problème n'est pas de mettre mon code, mais c'est qu'il y a tellement de traitement pour arriver à la capture que c'est difficile à expliquer ;-)

J'ai donc reproduit l'erreur pour la capture d'écran par un petit exemple que voici :



' .: Forme principale du projet :.
' Cette forme contient deux boutons :
' 1 pour faire une capture sans BackgroundWorker
' 1 pour faire une capture dans un BackgroundWorker

Imports System.ComponentModel

Public Class Form1

'Capture d'écran sans BackgroundWorker
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
DGSnapshotGOelanManager_MakeBitmapFromScreenShot(Application.StartupPath + "/TMP/TMP.bmp")
End Sub

'Capture d'écran avec le backgroundWorker
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Me.bgw.RunWorkerAsync()
End Sub

Private Sub bgw_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgw.DoWork
Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
DGSnapshotGOelanManager_MakeBitmapFromScreenShot(Application.StartupPath + "/TMP/TMPbgw.bmp")

End Sub

End Class

'-------------------------------------------------------------------------------------------------------------------


' .:Module de gestion des captures d'écran :.
Imports System.Drawing
Imports System.Drawing.Imaging

Module DGSnapshotGOelanManager

'Procédure de l'API Windows keybd_event permettant de simluer une touche pressée au clavier
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)

Private Function DGSnapshotGOelanManager_SaveScreen(ByVal FileName As String) As Boolean
Dim data As IDataObject
Dim bmap As Bitmap
Dim FramedBitmap As Bitmap
Dim Text As String = ""
Dim ImageGraphics As Graphics

'Récupération de l'image enregistrée dans le presse papier par la capture d'écran
data = Clipboard.GetDataObject()

'Enregistrement de cette image au format BMP
If data.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
'Conversion de l'image au format bitmap
bmap = CType(data.GetData(GetType(System.Drawing.Bitmap)), Bitmap)

'recadrage de l'image
FramedBitmap = New Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height)
ImageGraphics = Graphics.FromImage(FramedBitmap)
ImageGraphics.DrawImage(bmap, New PointF(0, 0))

'Enregistrement de l'image au format Bitmap
FramedBitmap.Save(FileName, Imaging.ImageFormat.Bmp)
ImageGraphics.Dispose()
End If
End Function

Public Sub DGSnapshotGOelanManager_MakeBitmapFromScreenShot(ByVal FileName As String)
'Copie d'écran
Call keybd_event(System.Windows.Forms.Keys.PrintScreen, 0, 0, 0)
'attente que l'image soit finie de copier
System.Windows.Forms.Application.DoEvents()
DGSnapshotGOelanManager_SaveScreen(FileName)
End Sub

End Module

'-------------------------------------------------------------------------------------------------------------------

La solution sans BackgroundWorker (Bouton1) fonctionne très bien
Pour la solution dans le BackgroundWorker(Bouton2), l'instruction Clipboard.GetDataObject() retourne Nothing

Je ne comprend pas très bien ce qui peut se passer

Merci encore
0
Le newbie Messages postés 200 Date d'inscription mardi 17 octobre 2006 Statut Membre Dernière intervention 24 mars 2012 2
5 déc. 2008 à 15:58
Re : Est tu sur de pouvoir faire un call dans un BGW. Il me semble que les seuls events gérables sont ceux du BGW.

 Call keybd_event(System.Windows.Forms.Keys.PrintScreen, 0, 0, 0)
        'attente que l'image soit finie de copier
        System.Windows.Forms.Application.DoEvents() 

Est ce que tu as mis un point d'arrêt pour voir s'il passait bien de partout. Ton problème serait peut être là.

@++
0
Rejoignez-nous