Vb6 Impression pdf multiples en batch

frc691 Messages postés 7 Date d'inscription lundi 19 décembre 2005 Statut Membre Dernière intervention 2 juin 2009 - 26 mai 2009 à 17:55
frc691 Messages postés 7 Date d'inscription lundi 19 décembre 2005 Statut Membre Dernière intervention 2 juin 2009 - 2 juin 2009 à 17:42
Bonjour,

Au cours du traitement de fichiers de coordonnées x,y, j'en retire des polaires qui sont affichées dans un formulaire spécifique comprenant textes et graphiques. Mon but est de transformer, à la volée, ces formulaires en pages pdf par le biais de CuteWriter tout en agrémentant un fichier .sql pour la mise à jour d'une DB. En gros, le principe fonctionne et j'obtiens bien le résultat voulu, sauf que :
- le soft tourne parfois plusieurs fois sur la même entrée pendant l'impression et le .sql grossit de plusieurs doublons (j'en fais mon affaire !:),
- certains fichiers sont traités mais ne sont pas imprimés ! Car il me faut définir à chaque fois le nom du fichier destination (comme pour toute imprimante de type fichier),
Une petite précision : pour le traitement de 1 à 5 fichiers : tout va bien ! Au delà, c'est la pagaille. Pour info, j'ai en tout plus de 2000 fichiers à traiter ainsi en mode batch, par lots de 55 à près de 1000.

Voici mon code d'impression (l'impression se fait par des printer.... et se termine par printer.EndDoc) :

Private Declare Sub Sleep Lib "kernel32" (ByVal dwTime As Long)
Public Sub Imprime_Polaire()
    Dim Ordre As String
    'Impression du formulaire de Polaire sur PDF CutWriter / imprimante par défaut
    frmImgPol.Imprimer   'Se termine par printer.enddoc
    'Transmission du nom de fichier et validation
    Sleep 500   'Temps de démarrage de la boîte de dialogue d'impression
    Ordre = App.Path & "" & NomCatalogue & "\images-pol" & NomDat & ".pdf{ENTER}"
    SendKeys Ordre, True
    Sleep 20000   'Temps de traitement de l'impression en pdf
End Sub

J'ai tenté de nombreuses permutations et valeurs d'attente, sans résultat probant ! Si l'un de vous peut ne serait-ce que tenter de m'orienter vers une solution viable :je suis preneur !
Il doit sans doute y avoir qqch auquel je n'ai pas songé :-) mais là, je ne vois plus !!! J'ai vainement tenté la voie de tester la fermeture de la boîte de dialogue d'impression via vb6, peut-être est-ce pourtant une possibilité ?!
Si vous avez des idées...
Cordialement,
François

6 réponses

cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
27 mai 2009 à 01:10
Salut
Manque de précision.
Tu parles de boucle de traitement, mais on ne vois que la procédure pour un seul.
Difficile de te dire pourquoi ça bugue.
De toute façon, l'utilisation de SendKeys est toujours hasardeuse puisqu'elle se base (dans ton cas) sur une temporisation.
Tout le monde aura remarqué que l'appel d'un programme n'a jamais la même durée, environnement oblige.
Donc, la seule solution est de te pencher sur la détection (par les APIs) d'une fenêtre par son nom (caption), ça te donnera un Handle.
Quand tu seras sûr d'avoir obtenu cette info, c'est que la fenêtre sera bien présente, alors, tu pourras sans crainte envoyer ton SendKeys.
Ensuite, après la validation, cela durera aussi un certains temps.
Pendant cette période, une (autre ?) fenêtre est surement ouverte --> même principe : retrouver son handle, puis attendre que ce handle disparaisse, tu seras alors sûr que la tâche est terminée et tu pourras penser en démarrer une autre.

Pour t'aider avec les APIs : http://logiciel.codes-sources.com/logiciels/API-Guide-197.aspx
Pour t'aider sur les constantes utilisées autour de ces APIs : http://www.activevb.de/rubriken/apiviewer/index-apiviewereng.html
Pour t'aider à trouver les Handles, et les liens de parenté : <WinID>
Tout le reste est parmi les tutoriels, codes et questions forum du site.

C'est assez complexe, mais c'est la seule façon sérieuse d'arriver à tes fins.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

<hr />Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
27 mai 2009 à 01:11
PS : "API Guide" accompagne chaque API par un exemple en VB6
A toi de t'exercer avec
0
frc691 Messages postés 7 Date d'inscription lundi 19 décembre 2005 Statut Membre Dernière intervention 2 juin 2009
27 mai 2009 à 18:49
Bonjour Jack,

Je te remercie pour ta réponse. Je vais de ce pas me pencher sur ce qui me semblait être la meilleure solution (Api's et Handles).
Effectivement, seule la procédure présentée me pose souci. Le reste du traitement fonctionne parfaitement. Il est en boucle et demande beaucoup de temps de traitement intermédiaire (soufflerie numérique) et plusieurs machines tournent sur le même traitement en cross-domain. Cette procédure dite d'impression est appelée par le serveur à la fin de chaque traitement, d'où cette présentation.

A te relire en cas de besoin :-),
Cordialement,
François
0
frc691 Messages postés 7 Date d'inscription lundi 19 décembre 2005 Statut Membre Dernière intervention 2 juin 2009
28 mai 2009 à 14:57
Bonjour !!!

Je ne connaissais pas ce outils et les conseille à tous (http://logiciel.codes-sources.com/logiciels/API-Guide-197.aspx et <WinID>) !
La solution que j'ai trouvée n'est pas à proprement parler très élégante (scrutation et non bufferisation), cependant elle fonctionne avec au moins 100 impressions successives, le tout, sans avoir - apparemment - de pb de pile, ni de mémoire.

Pour ceux que cela intéresse, la solution trouvée est la suivante :

Créer un module avec :

Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long

Public HandlePrn As Long
Public HandlePrnOld As Long
Public NbImp As Integer

Public Function ChercheWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Boolean
    Dim sSave As String, Ret As Long
    Ret = GetWindowTextLength(hwnd)
    sSave = Space(Ret)
    GetWindowText hwnd, sSave, Ret + 1
    If (Trim(sSave) = "Enregistrer sous") Then
        HandlePrn = hwnd
    End If
    'Continue l'énumeration.
    ChercheWindowsProc = True
End Function

Et dans le code du formulaire (créer un bouton cmdImprim) :

Private Sub Form_Load()
    HandlePrn = -1        // Handle de la nouvelle boite de dialogue d'impression.
    HandlePrnOld = -1   // Handle de l'ancienne pour comparaison ultérieure.
    NbImp = 0              // Nb de demande d'impressions.
End Sub

Private Sub cmdImprim_Click()   // Lancement des impressions successives.
    For NbImp = 0 To 100: Impression: Next NbImp
End Sub

Private Sub Impression()
    Dim Ordre As String    // Nom du fichier à enregistrer à intégrer dans la dialogbox.
    'Impression de la page // pour exemple.
    'Fonctionne très bien avec 198 contrôles à imprimer sur la même page comme avec une seule ligne graphique.
    'Testé avec CuteWriter, SymantecFax et Phantom AutoCad.
    Printer.Line (0, 0)-(1000, 1000)
    Printer.EndDoc
    'Attente d'un nouveau handle de fenêtre "Enregistrer sous"
    While HandlePrn = HandlePrnOld
        EnumWindows AddressOf ChercheWindowsProc, ByVal 0&
    Wend
    'Sauvegarde du nouveau handle pour comparaison ultérieure
    HandlePrnOld = HandlePrn
    'Envoi de la séquence de définition du nom de fichier
    Ordre = App.Path; "\test"; CStr(NbImp); ".pdf{ENTER}"
    SendKeys Ordre, True
End Sub

J'ai tenté de rendre la boîte de dialogue d'impression non-visible, mais cela ne fait pas gagner un temps fou (moins de 1%). Un constat : le serveur peut fonctionner tout seul, tout en faisant autre chose. Cependant, il vaut mieux ne pas changer de tâche ni surtout utiliser de commandes clavier (cela paraît évident !) pendant le traitement. Le gain de temps d'avec l'utilisation de Sleep paraît être de l'ordre de 30 à 65% selon les besoins externes et se défie de tous les temps de demandes extérieures. Cela me rapelle le vieux temps des noyaux temps réel en i8085 ! Sinon, la gestion d'erreur est relativement simple à assurer,

Pour Jack : Les choses ne sont pas si complexes quand l'on fut bien formé et avec plus de 20 ans de métier derrière soi ! Mais plus spécialisé dans les DB et les réseaux, j'avais un peu oublié ces fondements. Merci à toi.

Bien à vous tous,
François
0

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

Posez votre question
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
30 mai 2009 à 20:17
Re François
Impec.
Tu peux même pousser la recherche encore plus loin :
Après avoir trouvé le handle de la fenêtre "Enregistrer sous", tu peux rechercher l'objet "zone de texte" (classe "Edit") et le bouton (classe "Button") de validation : ce sont des Child de la forme.
Comme ça, même si la fenêtre perd le focus (obligatoire pour un SendKeys), tu pourras quand même poursuivre.

Exemple d'un truc que j'avais écrit il y a longtemps :
Public Function mChercheEditEtRemplit(ByVal ParentHwnd As Long, _
                                      ByVal NomFichier As String) As Boolean



    ' Ecrit le nom du fichier à utiliser à une fentre de selection
    ' Renvoie True si Ok
    Dim Temp As String
    Dim r As Long
    Dim sClasse As String
    Dim mHwnd As Long
    Dim Carré As RECT
   
    ' Cherche la ligne Edit (Nom du fichier)
    Screen.MousePointer = vbHourglass
        DoEvents
        Call Sleep(250)
    Screen.MousePointer = vbDefault
    mHwnd = GetWindow(ParentHwnd, GW_CHILD)
    Do While mHwnd <> 0
        sClasse = String(256, "<")
        r = GetClassName(mHwnd, sClasse, 256)
        sClasse = Left$(sClasse, r)
        If LCase(sClasse) = "edit" Then
            Exit Do
        End If
        mHwnd = GetWindow(mHwnd, GW_HWNDNEXT)
        DoEvents
    Loop
    If mHwnd = 0 Then Exit Function
   
    ' Envoie le nom du fichier
    DoEvents
    Temp = StrConv(NomFichier, vbFromUnicode, ByVal 1033)
    Call SendMessage(mHwnd, WM_SETTEXT, ByVal 0&, ByVal StrPtr(Temp))
    DoEvents
   
    ' Cherche le bouton Ouvrir et Clic
    mHwnd = GetWindow(ParentHwnd, GW_CHILD)
    Do While mHwnd <> 0
        sClasse = String(256, "<")
        r = GetClassName(mHwnd, sClasse, 256)
        sClasse = Left$(sClasse, r)
        If LCase(sClasse) = "button" Then
            Temp = String(256, "<")
            r = GetWindowText(mHwnd, Temp, 256)
            Temp = Left$(Temp, r)
            If LCase(Temp) Like "*ouvrir" Then
                Call GetWindowRect(mHwnd, Carré)
                With Carré
                    .Left = ((.Right - .Left) / 2) + .Left
                    .Top = ((.Bottom - .Top) / 2) + .Top
                End With
                Call SetCursorPos(Carré.Left, Carré.Top)
                Call mouse_event(MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP, 0, 0, 0, ByVal 0)
                Exit Do
            End If
        End If
        mHwnd = GetWindow(mHwnd, GW_HWNDNEXT)
        DoEvents
    Loop
    If mHwnd = 0 Then Exit Function
    mChercheEditEtRemplit = True
End Function



Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés





<hr />

Le savoir est la seule matière qui s'accroit quand on la partage (Socrate)
0
frc691 Messages postés 7 Date d'inscription lundi 19 décembre 2005 Statut Membre Dernière intervention 2 juin 2009
2 juin 2009 à 17:42
Joli !
Voila une manière élégante de détourner le système. J'en prend bonne note. Cela me servira bientôt.
Cependant, comme ma tournure m'a déjà permis de batcher plus de 500 impressions pdf, j'en resterai là. Après tout, je ne devrai m'en servir que 2 fois / an !
Une petite chose : dans le msg précédent, je voulais parler d'interruption et non de bufférisation. Tout le monde aura bien sûr compris.
Par contre, si tu connaissais (ou qq'un) un - même vague - algorythme permettant de définir si 2 cylindres dans l'espace sont ou non sécants.... Plusieurs Profs de maths (enseignant en Lycée et MSpé) ont déjà "passé l'éponge". C'est à titre perso pour la reconstitution d'un trière de l'époque d'Alexandre le Grand (rien que 170 rames à faire mouvoir ensemble...) et nous avons besoin d'une simulation avant construction.
En tous les cas, merci pour tes avis qui furent d'un bon secours.
Cordialement,
François
0
Rejoignez-nous