Powerbuilder pour les completement Geeks !

Le forum (ô combien francophone) des utilisateurs de Powerbuilder.

Recherche rapide

Annonce

Certaines rubriques, dont des cours, sont uniquement visibles par les membres du forum ^^.
Dans la rubrique Liens & Références, vous avez accès à un sommaire de téléchargement, profitez-en !
Il existe maintenant un nouveau TOPIC "Votre CV en Ligne" accessible uniquement par demande.
  • Index
  •  » Powerscripts
  •  » Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

#1 08-10-2008 08:54:33

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Bonjour !

J'essaie de faire appel à l'événement Windows WM_PRINT pour imprimer une fenêtre.
En effet, ma fenêtre contient une datawindow à imprimer, et le contenu de cette datawindow a été modifié dynamiquement via une DLL qui y a ajouté une image. Lorsque j'utilise la fonction datawindow.print() de PowerBuilder, l'image n'est pas imprimée car elle n'est pas un objet reconnu de la datawindow.

L'événement WM_PRINT devrait me permettre de lancer l'impression de la fenêtre, mais je n'y parviens pas. Le but c'est que ce soit Windows qui gère l'impression, plutôt que PowerBuilder.

Voici la documentation MSDN de WM_PRINT : WM_PRINT
Ici on a un exemple de déclenchement d'événement Windows, par Sybase : Exemple Sybase pour WM_CLOSE

Je me suis donc tout d'abord entrainé avec l'événement WM_CLOSE, qui fonctionne parfaitement :

Code: pb

    // Obtention de l'handle de ma fenêtre
    ulong hdl
    hdl=Handle(this)

    // Envoi de l'événement Windows demandant la fermeture de ma fenêtre
    // 16 = 10 en héxadécimal = constante de l'event définie dans windows.h = #define WM_CLOSE 0x0010
    Post(hdl, 16, 0, 0) 


Ensuite j'ai voulu faire la même chose avec l'événement d'impression.
Je dispose d'un exemple VB6 qui m'aide à me mettre sur la bonne voie (l'exemple imprime bien, mais l'image n'est pas visible)

Code: vb

    Printer.Print
    Printer.ScaleMode = vbInches
    Printer.Font.Name = "Arial"
    Printer.Font.Size = 12
    Printer.CurrentX = 1: Printer.CurrentY = 1
    Printer.Print "Print Test";

    Printer.CurrentX = 100: Printer.CurrentY = 100
    
    SendMessage pctPreview1.hwnd, WM_PRINT, Printer.hdc, 20


Après une  recherche sur le net, il semblerait que WM_PRINT = 0x0317 en héxadécimal. (#define WM_PRINT 0x0317)
A partir de là, la calculatrice Windows me dit que 317 en héxadécimal ça fait 791 en décimal.
Je pars donc sur une solution avec pour code de base le suivant :

Code: pb

    ulong hdl
    hdl=Handle(this)

    Post(hdl, 791, 0, 0) 


Malheureusement ce code ne fait rien, la page n'est pas imprimée.
A priori c'est normal : il faut indiquer l'imprimante de destination en 3ème argument... Le fameux HDC.
C'est sur ce point là que je suis bloqué pour le moment : je ne comprends pas comment récupérer le HDC  de mon imprimante par défaut sous PowerBuilder.

J'ai pu obtenir une piste à partir de cette page, mais bien que le "device context" me soit correctement retourné par GetDC(), l'impression n'est pas lancée.

Code: pb

    // Global external function : 
     Function ulong GetDC(ulong hwnd) library "user32.dll"

    // appel
    ulong hdl
    ulong hdc
    hdl=Handle(this)
    hdc = GetDC(hdl)

    Post(hdl, 791, hdc, 0) 


J'ai aussi pu obtenir des informations sur l'imprimante par défaut via :

Code: pb

String ls_fullstring
String ls_name, ls_driver, ls_port, ls_temp
Long ll_place

ls_fullstring=PrintGetPrinter()
ll_place=pos (ls_fullstring, "~t")
ls_name=left(ls_fullstring, ll_place -1)
ls_temp=mid(ls_fullstring, ll_place +1)
ll_place=pos (ls_temp, "~t")
ls_driver=left(ls_temp, ll_place -1)
ls_port=mid(ls_temp, ll_place +1)

messagebox('', ls_name + ' - ' + ls_driver + ' - ' + ls_port)
// Ce qui m'affiche le nom de l'imprimante, le nom du driver et le port


Ou, plus précisément, le nom de l'imprimante de ma datawindow :

Code: pb

messagebox('', string(      dw_suspect_tr_details_print.Object.DataWindow.Printer      ))


Le problème c'est que je n'obtiens toujours pas de HDC avec ça.
Auriez-vous une idée ?

Dernière modification par Nyphel (08-10-2008 09:29:03)

Hors ligne

 

#2 08-10-2008 12:29:16

Cortex  
Modérateur
Lieu: Arlon
Date d'inscription: 08-02-2008
Messages: 194
Pépites: 6,904
Banque: 2,109,818,425,070

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Pour récupérer le DC (Device Context) de ton imprimante, GetDC ne te sert à rien du tout. Je me demande d'ailleurs avec quel Hwnd tu l'as appelé... Bref, si tu veux récupérer le DC de ton imprimante, il faut que tu apelle la fonction CreateDC, en lui passant en paramètres les info du driver de ton imprimante. (Ne me demande pas de détails, je ne me souviens plus...)

Si tu y arrives, fait un signe, parce que j'émet quelques doutes sur le succès de ton entreprise
Je ne pense pas que tu aura de meilleurs résultats comme cela, car au final, il y a un vrai problème de refresh quand on dessine avec GDI sur des objets PB, à part pour un simple affichage (je pense te l'avoir déjà signalé d'ailleurs)... Mais vu que tu vas sûrement tenter le test, et si ça ne marche pas, je pense à un truc: code l'opération de dessin dans un user event correspondant à PBM_onpaint. Peut-être cela permettra à windows de prendre en compte ton dessin lors de l'impression...

Hors ligne

 

#3 08-10-2008 12:42:48

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Héhé oui tu me l'a déjà signalé, malheureusement je dois faire avec et prendre le risque ;).

Merci encore une fois pour ces conseils avisés, Cortex !

Hors ligne

 

#4 08-10-2008 13:57:55

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Je me suis donc tourné vers CreateDC...

Voici mon nouveau "Global external functions" :

Code: pb

FUNCTION ulong CreateDC(ref string lpDriverName, ref string lpDeviceName, ref string lpOutput, ref DEVMODE lpInitData) LIBRARY "gdi32.dll" ALIAS FOR "CreateDCA"

Function ulong GetDC(ulong hwnd) library "user32.dll"


Voici la structure DEVMODE, récupérée sur le net et quelque peu complétée (voir plus bas) :

Code: pb

global type devmode from structure
  character    dmdevicename[32]
  integer    dmspecversion
  integer    dmdriverversion
  integer    dmsize
  integer    dmdriverextra
  long    dmfields
  integer    dmorientation
  integer    dmpapersize
  integer    dmpaperlength
  integer    dmpaperwidth
  integer    dmscale
  integer     dmCopies
  integer    dmdefaultsource
  integer    dmprintquality
  long    dmPosition
  long    dmDisplayOrientation
  long    dmDisplayFixedOutput
  integer    dmcolor
  integer    dmduplex
  integer    dmresolution
  integer    dmttoption
  integer    dmcollate
  character    dmformname[32]
  integer    dmlogpixels
  long    dmbitsperpel
  long    dmpelswidth
  long    dmpelsheight
  long    dmdisplayflags
  long    dmNup
  long    dmdisplayfrequency
  long    dmicmmethod
  long    dmicmintent
  long    dmmediatype
  long    dmdithertype
  long    dmreserved1
  long    dmreserved2
  long    dmPanningWidth
  long    dmPanningHeight
end type


Et voici maintenant mes appels powerscript :

Code: pb

// Recherche des infos sur l'imprimante par défaut : nom, driver, port
String ls_fullstring=PrintGetPrinter()
String ls_name, ls_driver, ls_port, ls_temp
Long ll_place
ll_place=pos (ls_fullstring, "~t")
ls_name=left(ls_fullstring, ll_place -1)
ls_temp=mid(ls_fullstring, ll_place +1)
ll_place=pos (ls_temp, "~t")
ls_driver=left(ls_temp, ll_place -1)
ls_port=mid(ls_temp, ll_place +1)

// Driver trouvé = "winspool"
ls_driver += ".drv"  // Testé avec "windspool" et "windspool.drv"
    
// Print test    
string ls_null
long ll_null
SetNull(ls_null)
SetNull(ll_null)
  
ulong hdl = Handle(this) // Handle de ma fenêtre à imprimer
ulong hdc

devmode lstr_devmode_null

// Test 1
hdc = GetDC(hdl)
MessageBox('', string(hdl) + ' - ' + string(hdc)) // 1116054 - 453055004
Post(hdl, 791, hdc, 0) // Rien ne se passe
  
// Test 2
hdc = CreateDC(ls_driver, ls_null, ls_null, lstr_devmode_null)  
MessageBox('', string(hdl) + ' - ' + string(hdc)) // 1116054 - 0
Post(hdl, 791, hdc, 0) // Rien ne se passe


Je ne comprends pas bien pourquoi il me faut utiliser CreateDC, mais quoi qu'il en soit je ne dois pas faire ce qu'il faut. La documentation sur CreateDC dit que ça retourne NULL si la fonction échoue ou si la structure DEVMODE n'est pas la structure courante. En effet, ma structure ne contenait pas autant de choses que celle montrée dans le lien précédant... Je l'ai donc complétée, sans améliorer mes résultats. Je conserve un gros doute au sujet de ma structure, d'autant plus que ça signifie que mon application sera dépendante de la version de la DLL gdi32.dll du poste client.

Bref, je dois encore creuser pour réussir à simplement appeler CreateDC, même si selon moi GetDC faisait ce qu'il fallait (mon imprimante est installée et positionnée comme imprimante par défaut. Il en sera de même chez le client final).

Dernière modification par Nyphel (08-10-2008 14:17:09)

Hors ligne

 

#5 08-10-2008 14:31:29

Cortex  
Modérateur
Lieu: Arlon
Date d'inscription: 08-02-2008
Messages: 194
Pépites: 6,904
Banque: 2,109,818,425,070

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Nyphel a écrit:

Bref, je dois encore creuser pour réussir à simplement appeler CreateDC, même si selon moi GetDC faisait ce qu'il fallait (mon imprimante est installée et positionnée comme imprimante par défaut. Il en sera de même chez le client final).

Je te jure que non:

MSDN a écrit:

The GetDC function retrieves a handle to a device context (DC) for the client area of a specified window or for the entire screen.

Pour les définitions de fonctions externes, il va falloir prendre position ANSI/Unicode! Si ton PB < 10, tu peux appeller les version Ansi (comme tu as fait pour CreateDCA), sinon, soit tu ajoute un ;Ansi à la clause ALIAS FOR, soit tu utilise la version Unicode (ici CreateDCU). Sinon, tu envoies des string nawak à la dll...

Code: pb

FUNCTION ulong CreateDC(string lpDriverName, string lpDeviceName, long lIgnored1, long lIgnored2) LIBRARY "gdi32.dll" ALIAS FOR "CreateDCA;Ansi"
// ne met pas de 'ref' quand MSDN stipule des argument en [in]
// lIgnored1 et 2 sont là pour passer la valeur NULL (0 en C++) de manière plus conviviale...

Function ulong GetDC(ulong hwnd) library "user32.dll"


Tu vois, j'avais dit que c'était pas facile...

A mon avis, pas besoin de la struct DEVMODE puisque:

MSDN a écrit:

Pointer to a DEVMODE structure containing device-specific initialization data for the device driver. [...] The lpInitData parameter must be NULL if the device driver is to use the default initialization (if any) specified by the user.

A mon sens, NULL ira très bien... Donc l'appel sera:

Code: pb

hdc = CreateDC(ls_driver, ls_device, 0, 0)
// je regrette de dire que tu dois fournir un ls_device valide et non NULL


Nyphel a écrit:

Je ne comprends pas bien pourquoi il me faut utiliser CreateDC

Tu vois, WM_PRINT demande à une window de se dessiner sur un DC spécifié. Or, la manière de dessiner est dépendante du device sur lequel tu dessine (sur l'écran n'est pas pareil que sur un imprimante matricielle ou sur une imprimante offset, etc...). Donc, dans GDI, les DC sont un moyen de rendre le dessin independant du device. Et donc chaque type de support a sa fonction qui sert à créer un DC: GetDC pour les fenêtres, CreateCompatibleDC pour les bitmap en mémoire... et CreateDC pour les périphériques gérés par des drivers spécifiques...

Pour finir, je crois que tu devrais faire marche arrière. Tu te lance dans la partie la plus foireuse de la prog Windows, et avec un langage qui n'est pas fait pour ça.
Evidemment, c'est toi qui voit...

Hors ligne

 

#6 08-10-2008 14:47:54

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Oula je comprends beaucoup mieux tout à coup. Je croyais que CreateDC créait un contexte, et que GetDC me retournait le handle d'un contexte... Indépendamment du support technique/driver. Et comme WM_PRINT demande un handle de contexte, je pensais que tout était parfait

J'ai donc ajouté mon ";Ansi" dans mon "Global external functions" :

Code: pb

FUNCTION ulong CreateDC(ref string lpDriverName, ref string lpDeviceName, ref string lpOutput, ref DEVMODE lpInitData) LIBRARY "gdi32.dll" ALIAS FOR "CreateDCA;Ansi"

J'avoue que je découvre ces appels de DLLs, et je n'avais pas compris que la spécification de l'encodage variait d'une version à l'autre de PowerBuilder.

En revanche, je ne peux pas faire mon appel comme ceci :

Code: pb

hdc = CreateDC(ls_driver, ls_device, 0, 0)

Pb me dit alors : "Reference argument must be a non-constant and non-readonly variable reference."

Ca m'ennuie aussi de perdurer dans cette voie, mais sinon je ne vois pas comment imprimer ma fenêtre avec ses images.
Nous avions déjà mentionné l'idée d'enregistrer l'image sur le disque, de la loader dans un Picture Control et d'imprimer le tout... Toutefois je ne parviens pas à récupérer le "texte/code" de l'image elle-même (JPG) dans le but de l'enregistrer. L'image est cryptée, et je ne parviens pas à faire l'appel de la méthode qui me retourne le contenu décrypté. C'est ce que j'essaie de faire depuis un moment, et ce pour quoi j'ai demandé de l'aide dans ce post... Sur lequel tu m'aides déjà activement

Encore une fois, merci pour tout Cortex !

Dernière modification par Nyphel (08-10-2008 14:48:59)

Hors ligne

 

#7 08-10-2008 14:58:12

Cortex  
Modérateur
Lieu: Arlon
Date d'inscription: 08-02-2008
Messages: 194
Pépites: 6,904
Banque: 2,109,818,425,070

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Nyphel a écrit:

En revanche, je ne peux pas faire mon appel comme ceci :

Code: pb

hdc = CreateDC(ls_driver, ls_device, 0, 0)

Pb me dit alors : "Reference argument must be a non-constant and non-readonly variable reference."

1. Tu as pas vu que j'avais changé les arguments de la fonction externe:

FUNCTION ulong CreateDC(string lpDriverName, string lpDeviceName, long lIgnored1, long lIgnored2) LIBRARY "gdi32.dll" ALIAS FOR "CreateDCA;Ansi"

2. Si l'erreur perdure, ne met pas les 0 directement mais passe par des variables long initialisées à 0.

Nyphel a écrit:

Ca m'ennuie aussi de perdurer dans cette voie, mais sinon je ne vois pas comment imprimer ma fenêtre avec ses images.
Nous avions déjà mentionné l'idée d'enregistrer l'image sur le disque, de la loader dans un Picture Control et d'imprimer le tout... Toutefois je ne parviens pas à récupérer le "texte/code" de l'image elle-même (JPG) dans le but de l'enregistrer.

Bon, d'abord, essaie de décrire une fois pour toutes ce que tu essaies de faire: tu veux rajouter une image dans une DW, mais l'image vient d'où, c'est quoi,... Ensuite, es-tu arrivé à généré l'image (j'imagine puisque tu parles de JPG), alors n'arrives-tu pas à la mettre dans un picture controle?
Et finalement, que diable vient faire cette histoire de décryptage dans le chmilblik?

Je suis sûr qu'on passe à côté d'un truc essentiel là

Hors ligne

 

#8 08-10-2008 15:25:54

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Haem... Désolé ! Avec la nouvelle déclaration de la fonction, je peux exécuter le code sans problème. Toutefois je n'ai toujours pas de HDC retourné.

Code: pb

FUNCTION ulong CreateDC(string lpDriverName, string lpDeviceName, long lIgnored1, long lIgnored2) LIBRARY "gdi32.dll" ALIAS FOR "CreateDCA;Ansi"

Code: pb

  hdc = CreateDC(ls_driver, ls_null, 0, 0)  
  MessageBox('', string(hdl) + ' - ' + string(hdc))  
      Post(hdl, 791, hdc, 0)


Tu as raison, je vais expliquer un peu tout cela, clairement, et en détails !

L'idée est la suivante : une caméra prend des photos et les stocke dans un dossier.
Mon application Pb affiche ces photos.

Toutefois, par soucis de sécurité, il est indispensable que ces photos ne puissent jamais être modifiées entre le moment où elles sont prises, et le moment où l'utilisateur a fini d'utiliser l'application Pb qui les affiche et permet de les consulter. Pour cela plusieurs mesures sont prises :
- dès que la photo est faite, elle est encryptée
- quand mon application souhaite afficher une photo, elle fait appel à une DLL (objet COM) qui décrypte la photo. L'objet COM prend en argument le handle de la fenêtre où je souhaite afficher cette photo, et c'est ensuite l'objet COM lui-même qui se charge de décrypter et d'afficher la photo dans la fenêtre. Mon application n'a aucun contrôle sur la photo.

Techniquement, côté Pb, ça se passe comme suit :
- j'ai une datawindow qui retrouve des données via une procédure stockée Oracle. Pour chaque row, j'ai une colonne qui me donne le chemin d'accès à la photo correspondant aux données.
- ma datawindow est bien entendu placée dans une fenêtre.
- lorsque l'utilisateur clic sur un row, j'affiche l'image qui correspond à ce row, dans ma fenêtre.

Depuis ma fenêtre, mon utilisateur peut demander à imprimer les données concernant 1 row (et un seul...). Dès lors, je prends les données du row en question et je vais les "mettre en page" dans une datawindow masquée qui ne sert qu'à ça. Au lieu d'avoir mes informations sous forme de colonnes, je fais un vrai rapport détaillé et mis en page, avec logos et tout le tralala.
Ma datawindow disposant elle aussi d'un handle, je peux y afficher mon image : je demande à mon objet COM d'afficher l'image dans la datawindow, ce qu'il fait très bien.

Vient le moment d'imprimer : ma datawindow s'imprime correctement, mais l'image n'est pas imprimée. Soit... C'est pas si étrange que ça, puisque l'image est "posée" sur la datawindow mais qu'elle 'nen fait pas partie.

Plusieurs solutions furent abordées sur différents posts du forums :

1) Ici, où j'ai voulu tout simplement passer le handle d'un control de ma datawindow à mon objet COM, pour qu'il dessine dans un PictureControl imprimable. Toutefois, on a pas de handle pour les control qui sont dans une datawindow, qui est dans une fenêtre... Et Pb crashe en tentant d'y accéder. J'ai même tenté de faire un nested report dans ma datawindow, mais le handle retourné vaut 0.

2) J'ai ensuite tenté d'utiliser une méthode de mon objet COM. Cette méthode devait me retourner le contenu de l'image décryptée, sous format chaine de caractères. Dès lors il me suffisait d'enregistrer cette image dans un fichier texte temporaire, puis de charger cette image dans un PictureControl de ma datawindow, avant d'imprimer le tout. Il n'y a pas de problème de confidentialité, l'image peut être copiée tant que l'original n'est pas modifié.
Malheureusement, il y a plusieurs problèmes :
- Tout d'abord, la méthode de l'objet COM prend un argument de type unsigned char**. Je ne parviens pas à lui transmettre un argument Pb du bon type, et l'application crashe inexorablement. Ce problème fut abordé par ici.
- Ensuite, je me suis aperçu que le paramètre attendu n'était peut-être pas une chaine de caractère qui serait modifiée par la méthode de l'objet COM, mais plutôt une adresse mémoire obtenue via la GCHandle structure... Et ce fut abordé par là.
On notera mon manque de documentation sur le sujet. J'essaie d'en obtenir mais sans réel succès.

3) Enfin, vient l'idée de ne plus imprimer ma fenêtre en utilisant la méthode dw.print() de PowerBuilder, mais en utilisant directement l'événement d'impression Windows. C'est le but de ce post-ci

Voili voilà, je ne sais pas si c'est très clair, mais j'espère avoir "posé" une vue d'ensemble de la problématique.

Hors ligne

 

#9 08-10-2008 15:43:57

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

my 2 cents : tu pourrais aussi faire un printscreen de ta window et imprimer l'image globale résultante...

pour le printscreen : http://eric.aling.tripod.com/PB/tips/pbtip35.htm  (d'ailleurs y'a du GetDC )


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 

#10 08-10-2008 15:45:39

Cortex  
Modérateur
Lieu: Arlon
Date d'inscription: 08-02-2008
Messages: 194
Pépites: 6,904
Banque: 2,109,818,425,070

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Ok, magnifique, on y voit plus clair

Bon, l'idéal aurait été que les gars qui ont fait le composant COM en aient fait un composant embeddable (avec composante graphique), et alors tu l'aurais ajouté comme OLE object parmi les controles de ta DW, il aurait juste servi à traduire ton image. Ca, c'est la solution 100% propre, chacun faisant exactement ce qu'il sait faire... Evidemment, j'imagine que vu que tu arrives pas à trouver la doc, c'est aussi que la team en question est tout aussi injoignable...

Il reste la possibilité de faire ce fameux contrôle embeddable, soit en C++ (bonjour l'angoisse) mais plus aventageusement en .NET.

Tu peux aussi faire un petit outil en .NET par exemple qui extraierait les images en clair dans un folder fixé, à la demande de ton applic PB (tu met cette applic .NET en COM visible, comme ça tu l'appelle de PB comme n'importe quel objet COM/OLE).

Sinon tu peux aussi te faire un Wrapper en utilisant PBNI (comme l'a proposé Buck), mais si tu n'en as jamais fait, ni non plus de C++, vaut mieux abandonner et préférer les soluces .NET, beaucoup plus faciles même si tu n'a pas d'expérience.

Voilà à chaud ce que je vois comme solutions à discuter peut-être avec ton équipe...

Hors ligne

 

#11 08-10-2008 15:47:25

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Erasorz,
J'avoue que ça m'a traversé l'esprit, mais j'ai vu nombre de problèmes à ce sujet sur le forum... Ce qui m'a refroidi
Qui plus est, à terme, la datawindow à imprimer sera masquée. C'est une datawindow de "mise en forme avant impression".
Enfin, je pourrais afficher la datawindow le temps de faire un printscreen, mais il est probable que le contenu de ma datawindow ne rentre pas sur l'écran... Qu'il faille donc scroller un peu.

Je vais tout de même regarder cela attentivement, ça pourrait aboutir là où les autres solutions bloquent
Merci ;)

Cortex,
Que de pistes !
Mon équipe étant composé d'un chef de projet, d'un collaborateur Oracle (pour les procédures stockées, migrations, etc.) et de moi-même qui débute sur PowerBuilder, notre marge de manœuvre est limitée ;)
C'est la première fois que j'utilise un objet COM/OLE, donc il faut encore que je me document sur le sujet, de sorte à mieux comprendre tes propositions. De même je n'ai jamais fait de .Net, même si ça semble intéressant et fort pratique pour compléter PowerBuilder.

Si on a pas de solution "simple", je ne pense pas que l'on s'engage sur la voie du .Net/C++/PBNI. On va creuser encore, puis on avisera. En effet mon fournisseur de l'objet COM est difficilement joignable, et n'a pas prévu de solution pour gérer l'impression directement depuis sont objet COM. De même, l'objet n'a pas été conçu pour être chargé sous Pb, ou alors c'est encore moi qui ai boulétisé ;)
Cet objet COM fonctionne parfaitement en VB6, parait-il... :-o

Merci pour vos remarques, j'en prends note !

Dernière modification par Nyphel (08-10-2008 15:57:57)

Hors ligne

 

#12 08-10-2008 15:50:04

Cortex  
Modérateur
Lieu: Arlon
Date d'inscription: 08-02-2008
Messages: 194
Pépites: 6,904
Banque: 2,109,818,425,070

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

erasorz a écrit:

my 2 cents : tu pourrais aussi faire un printscreen de ta window et imprimer l'image globale résultante...

Moui, aussi... à la limite... Jusqu'au jour où on te demande de juste rajouter telle ou telle info sur le print

erasorz a écrit:

(d'ailleurs y'a du GetDC )

Ca veut dire quoi au juste cette remarque? 'ttention hein...

Hors ligne

 

#13 08-10-2008 17:56:10

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Cortex a écrit:

erasorz a écrit:

my 2 cents : tu pourrais aussi faire un printscreen de ta window et imprimer l'image globale résultante...

Moui, aussi... à la limite... Jusqu'au jour où on te demande de juste rajouter telle ou telle info sur le print

bah tu la rajoutes sur ta fenêtre et puis "abana"...

Cortex a écrit:

erasorz a écrit:

(d'ailleurs y'a du GetDC )

Ca veut dire quoi au juste cette remarque? 'ttention hein...

rien de spécial...


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 

#14 09-10-2008 10:53:14

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Bien le bonjour,

En fait l'idée qui guide la discussion dans ce post, c'est de remplir une datawindow avec les données et l'image que je souhaite imprimer, puis de demander à Windows d'imprimer la fenêtre telle qu'elle... Plutôt que de demande à Pb d'imprimer la datawindow, dans laquelle il ne connait pas les images.

Au final, je pense qu'il y a une solution équivalente et beaucoup plus simple : je créé une fenêtre de stockage. Dans cette fenêtre je place ma datawindow, mais ma datawindow ne contiendra pas mon image. Du coup je peux obtenir le handle d'un picture control placé par-dessus la datawindow, dans lequel je vais charger l'image.
Suite à cela, j'ouvre un job d'impression, et j'envoie ma fenêtre complète.

C'est pas terrible, ça fait une fenêtre dédiée à cela, je vais devoir transmettre toutes mes données de ma fenêtre principale à celle-ci... Mais je pense que ça peut fonctionner.

Hors ligne

 

#15 09-10-2008 12:52:07

cposervices  
Membre completement Geek
Date d'inscription: 02-07-2008
Messages: 106
Pépites: 1,000,382
Banque: 0

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Une question bête : ton objet com n'a pas de méthode d'impression ?

Hors ligne

 

#16 09-10-2008 12:57:47

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Non, j'en ai réclamé une et ils ils gentiment répondu qu'il me suffisait de passait par l'événement WM_PRINT qui gère l'impression Windows ;)

Je me demande si il n'y aurait pas une piste avec un certains "COMDLG32.ocx".

Dernière modification par Nyphel (09-10-2008 13:01:30)

Hors ligne

 

#17 09-10-2008 13:26:41

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

J'ai donc tenté d'externaliser mon impression dans une autre fenêtre.

Lorsque je souhaite imprimer, je fais appel à une nouvelle fenêtre qui contient :
- 1 datawindow avec mes donnés textuelles
- 1 autre petite datawindow qui sert de recptacle pour mon image.

La petite datawindow est positionnée par dessus l'autre, et ça fait bien illusion.

Dans mon PostOpen() event, je demande donc à imprimer toute la fenêtre, et pas uniquement la datawindow :

Code: pb

long Job
Job = PrintOpen( )
this.Print(Job, 0,0)
PrintClose(Job)


Le résultat n'est pas terrible.
- La page imprimée est vide si la fenêtre est masquée. Moi je souhaite justement que ma fenêtre soit invisible...
- La page imprimée est comme un ImprEcran : on y voit la barre des taches, le menu Démarrer, et toute la fenêtre (barre bleue, menus, barre d'action, etc.). En revanche, il manque la moitié de mes données : tout ne rentre pas sur une seule page, il faut scroller vers le bas pour tout voir... Et ce qui n'est pas visible, n'est tout simplement pas imprimé.

Je vais donc devoir abandonner cette solution qui m'emplissait d'espoir ;-)

Dernière modification par Nyphel (09-10-2008 13:27:03)

Hors ligne

 

#18 09-10-2008 19:14:15

cposervices  
Membre completement Geek
Date d'inscription: 02-07-2008
Messages: 106
Pépites: 1,000,382
Banque: 0

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Ensuite j'ai voulu faire la même chose avec l'événement d'impression.
Je dispose d'un exemple VB6 qui m'aide à me mettre sur la bonne voie (l'exemple imprime bien, mais l'image n'est pas visible)

Code: vb
    Printer.Print
    Printer.ScaleMode = vbInches
    Printer.Font.Name = "Arial"
    Printer.Font.Size = 12
    Printer.CurrentX = 1: Printer.CurrentY = 1
    Printer.Print "Print Test";

    Printer.CurrentX = 100: Printer.CurrentY = 100
   
    SendMessage pctPreview1.hwnd, WM_PRINT, Printer.hdc, 20

Quel est le type de l'objet pctPreview1 dans ton exemple vb6 ?

Hors ligne

 

#19 10-10-2008 06:38:30

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Je n'y connais rien en VB6, mais d'après l'interface utilisateur, ca semble être l'équivalant du PictureControl de PowerBuilder.

Je pense que le "Printer" est obtenu via cette déclaration :

Code:

Object = "{F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.2#0"; "COMDLG32.OCX"

Je me suis donc intéressé à cet OCX, et il semblerait qu'il permette d'ouvrir les fenêtres de dialogue Windows pour gérer l'imprimante (Demande d'impression, choix de l'imprimante, etc.). Il m'a fallu installer Visual Studio 6 pour pouvoir l'ajouter à mon interface : la plupart des PC possèdent l'OCX et peuvent l'utiliser, par contre dès qu'on veut développer avec (ajout sur une interface, etc.), l'OCX bloque et demande une licence. Il faut alors installer Visual Studio pour l'activer.

Ne sachant pas me servir des OCX, je vais encore batailler un peu... Il y a peut-être une piste à creuser par là ;)

Je reprends donc mes essais d'impression, sachant que ole_ms_common_dialog_ctrl est mon nouveau OCX COMDLG32 :

Code: pb

// Default printer name, driver and port
String ls_fullstring=PrintGetPrinter()
String ls_name, ls_driver, ls_port, ls_temp
Long ll_place
ll_place=pos (ls_fullstring, "~t")
ls_name=left(ls_fullstring, ll_place -1)
ls_temp=mid(ls_fullstring, ll_place +1)
ll_place=pos (ls_temp, "~t")
ls_driver=left(ls_temp, ll_place -1)
ls_port=mid(ls_temp, ll_place +1)
messagebox('', ls_name + ' - ' + ls_driver + ' - ' + ls_port)
    
// Print test    
  string ls_null
  long ll_null
  devmode lstr_devmode_null
  SetNull(ls_null)
  SetNull(ll_null)
  
  ulong hdl
  ulong hdc
  
  hdl=Handle(this)
     
  hdc = GetDC(hdl)
  MessageBox('', string(hdl) + ' - ' + string(hdc)) // 1181718 - 16842438
  Post(hdl, 791, hdc, 0) 
  
  ls_driver += ".drv"  
  hdc = CreateDC(ls_driver, ls_null, 0, 0)  
  MessageBox('', string(hdl) + ' - ' + string(hdc)) // 1181718 - 0
  Post(hdl, 791, hdc, 0) 
     
  hdc = ole_ms_common_dialog_ctrl.object.hdc
  MessageBox('', string(hdl) + ' - ' + string(hdc)) // 1181718 - 7471184
  Post(hdl, 791, hdc, 20) 

Le HDL et le HDC varient à chaque exécution. Pour le HDL ça me semble tout à fait normal, pour le HDC je n'en sais rien.

Mais, une fois de plus, rien ne se passe : l'impression n'a pas lieu.
Qui plus est, je ne parviens pas à reproduire l'ensemble du code VB6 : je ne dispose pas des méthodes ou propriétés Print/ScaleMode/CurrentX/CurrentY/EndDoc dans mon OCX...

Juste par curiosité, l'un d'entre vous a-t-il déjà réussi à poster une demande d'impression WM_PRINT ? :-/

Dernière modification par Nyphel (10-10-2008 07:56:56)

Hors ligne

 

#20 10-10-2008 08:47:41

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Il semblerait finalement que cet OCX ne soit pas très intéressant.

Le principe est d'ouvrir la boite de dialogue d'impression, et de récupérer le HDC de l'imprimante sélectionnée... Sauf que dans mon cas je ne dois pas ouvrir la boite de dialogue, et donc je ne récupère pas de HDC viable. Qui plus est j'ai bien des difficultés à l'utiliser.

Je pense maintenant que la solution se situe au niveau du CreateDC. Il semblerait en fait que le second paramètre - obtenu par EnumDisplayDevices - soit requis, j'essaie de récupérer la valeur correcte de ce paramètre... Mais bon... Pour le moment j'ai du mal.

Dernière modification par Nyphel (10-10-2008 08:52:31)

Hors ligne

 

#21 10-10-2008 08:56:27

cposervices  
Membre completement Geek
Date d'inscription: 02-07-2008
Messages: 106
Pépites: 1,000,382
Banque: 0

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Donc, pourquoi n'utilises-tu pas un picture control et du transcrit le code vb en pb ?

Hors ligne

 

#22 10-10-2008 09:20:28

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Et bien en fait - avant de chercher à imprimer - je dois afficher la photo.
Pour afficher une photo, je dois appeler une fonction d'un objet COM qui se charge de décrypter la photo et de l'afficher dans une fenêtre. Cette fonction prend dont en argument le handle de cette fenêtre.

Je souhaite afficher ma photo au milieu de données textuelles, dans une datawindow.
Le code VB fait exactement la même chose, et place l'image dans un PictureControl. Pour ma part, l'idée sera donc d'avoir un PictureControl dans ma datawindow... Mais le hic c'est que Pb est incapable de me retourner le handle d'un objet placé dans une datawindow.

Dès lors, je ne peux plus placer ma photo dans un PictureControl d'une datawindow.
Si je le place directement dans une fenêtre, hors de la datawindow qui contient les données textuelles, alors j'ai des soucis à l'impression. Quand Pb imprime la fenêtre, on dirait qu'il imprime une sorte de screenshot/ImprEcran.

Hors ligne

 

#23 10-10-2008 09:37:25

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

ça me chiffonne quand même

http://eric.aling.tripod.com/PB/tips/pbtip35.htm

Eric Aling a écrit:

Some people asked me how to get the current window on the clipboard so that users could paste it in some doc or whatever. Well, you could do a Alt+PrintScreen and paste it. It would be nicer if we could automate this process from powerscript. Well, this is possibe. Check out the example pibble. What does it do? First, we get the whole desktop as image. From that image, we take the window using the coordinates and dimensions. With that we make a bitmap in memory and place it on the clipboard. Besides that, I converted the bitmap data in memory to a bitmap in a blob. Very handy if you want to save the bitmap to file.

d'après ce qui est dit la méthode est de faire un printscreen de tout le bureau puis de récupérer les coordonnées de la fenêtre courante pour réduire l'image

j'ai donc pensé à ce petit workaround :

tu connais la position et dimension de ta photo, donc tu modifies le script pour que le printscreen ne prenne que la photo
ensuite tu sauvegardes dans un fichier temporaire
puis tu affectes ce fichier à un controle picture de ta DW
et enfin tu imprimes ta DW et bingo !


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 

#24 10-10-2008 09:50:59

Nyphel  
Membre Power Geek
Lieu: Grenoble
Date d'inscription: 06-05-2008
Messages: 253
Pépites: 12
Banque: 529,705,333,097,693

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Ouais... Bingo... :D

Ca pourrait être une solution, oui... Il faudrait que je détermine la position de l'image en fonction :
- de la position du controle dans la DW,
- de la position de la DW dans la fenêtre,
- de la position de la fenêtre dans l'application (MDI),
- de la position de l'application (ou de la fenêtre principale) sur le bureau,
- et - bien entendu - de la résolution du bureau.

Oui, ça se tente !

Dès que j'ai quelques heures de libres, j'essaie ça
Merci pour l'idée Erasorz !

Hors ligne

 

#25 10-10-2008 09:59:10

erasorz  
Admin
Lieu: Babylone
Date d'inscription: 23-11-2006
Messages: 5121
Pépites: 97,197
Banque: 2,147,483,647

Re: Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Nyphel a écrit:

1- de la position du controle dans la DW,
2- de la position de la DW dans la fenêtre,
3- de la position de la fenêtre dans l'application (MDI),
4- de la position de l'application (ou de la fenêtre principale) sur le bureau,
5- et - bien entendu - de la résolution du bureau.

pour le 1 et le 2, je croyais que l'image n'était pas réellement affiché dans un DW mais au-dessus    (?)

le 3 : facile

le 4 et le 5 sont déjà codés dans l'exemple


N'envoyez jamais un humain faire le travail d'un programme.

Hors ligne

 
  • Index
  •  » Powerscripts
  •  » Impression d'une fenêtre en utilisant l'événement Windows : WM_PRINT

Pied de page des forums

Propulsé par FluxBB 1.2.22