Précédent   Forum des professionnels en informatique > Environnements de développement > Delphi > API, COM et SDKs
API, COM et SDKs Développement système ou spécifique
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
Vieux 10/03/2010, 01h31   #1
Invité de passage
 
Klaus Fischer
Inscription : mars 2010
Messages : 18
Détails du profil
Informations personnelles :
Nom : Klaus Fischer

Informations forums :
Inscription : mars 2010
Messages : 18
Points : 1
Points : 1
Par défaut PrintDlg dans une Unit - trouver le nom ?

Bonsoir,

Je suis nouveau sous Delphi. Je cherche à ouvrir la boite de dialogue de sélection d'imprimante par programmation, sans utiliser l'objet PrintDialog, car je dois le faire dans une Unit sans form, pour pouvoir placer mes fonctions dans une DLL plus tard.

J'ai d'abord tout fait dans une form avec PrintDialog: tout marche bien, je peux mémoriser l'imprimante par défaut actuelle, choisir mon imprimante, mémoriser l'imprimante choisie comme imprimante par défaut, restaurer l'imprimante par défaut initiale, ...

Je veux tout faire maintenant dans une unit en vue de la fabrication de ma DLL. Toutes les fonctions citées ci-dessus marchent, en utilisant certains API, sans problème. Sauf un point précis: pour choisir la nouvelle imprimante, j'utilise l'API PrintDlg comme ceci:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
function SelectDefaultPrinter(): integer;
 
var
   Pd: TPrintDlg;
   PrinterName: Pchar;
 
begin
    FillChar(Pd, sizeof(Pd), #0);
    Pd.lStructSize := sizeof(Pd);
    pd.hDevNames := 0;
    Pd.Flags := PD_RETURNDC;
 
  if PrintDlg(Pd) then begin
    result := 1;
    showmessage('Validé');
{  C'est dans la ligne suivante que se trouve mon problème : }
    printername := globallock(pd.hDevNames);
{  l'instruction suivante affiche n'importe quoi: }
    showmessage('device=['+PrinterName+']');    
 
    globalunlock(pd.hDevNames);
{  l'instruction suivante ne marche évidemment pas:}
    SetDefaultPrinter(PrinterName);
  end
else
  begin
    result := 0;
    showmessage('Abandonné')
  end;
end;
 
procedure SetDefaultPrinter(PrinterName: String);
 
var
   I: Integer;
   Device : PChar;
   Driver : Pchar;
   Port : Pchar;
   HdeviceMode: Thandle;
   aPrinter : TPrinter;
   bFoundPrinter : Boolean;
   strPrinterName : string;
 
begin
  bFoundPrinter := False;
  Printer.PrinterIndex := -1;
  GetMem( device, 255);
  GetMem( Driver, 255);
  GetMem( Port, 255);
  aPrinter := TPrinter.create;
  for I := 0 to Printer.printers.Count-1 do
  begin
    strPrinterName := Printer.Printers[i];
    if strPrinterName = PrinterName then
    begin
      bFoundPrinter := True;
      aprinter.printerindex := i;
      aPrinter.getprinter( device, driver, port, HdeviceMode);
      StrCat(Device, ',');
      StrCat(Device, Driver );
      StrCat(Device, Port );
      WriteProfileString('windows', 'device', Device );
      StrCopy( Device, 'windows' );
      SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, Longint(@Device));
   end;
  end;
  FreeMem( Port, 255);
  FreeMem( Driver, 255);
  FreeMem( Devite, 255);
  aPrinter.free;
  if bFoundPrinter = False then
    MessageDlg('Unable to change default printer to ' + PrinterName, mtWarning, [mbOK], 0);
end ;
N.B. La fonction SetDefaultPrinter fonctionne parfaitement - elle est testée avec la version "form" de mon programme.

Je sais que hDeviceNames pointe sur une structure de 4 mots dont les 3 premiers contiennent des offsets dans une zone "extra" de 255 caractères suivant ces 4 mots, et le second offset doit pointer vers le début du nom long de l'imprimante sous forme d'un string terminé par un byte zéro.

Je veux récupérer ce nom sous forme de pchar dans PrinterName pour pouvoir l'utiliser après, mais je n'ai pas trouvé le moyen de le faire.

Je parcours les documentations, les forums et les sites d'info depuis des jours et je n'arrive pas à trouver comment faire. En fait, je ne sais pas comment suivre la chaine de pointeurs pd.hDevNames --> (wDeviceOffset) --> wExtra pour récupérer le nom en clair de l'imprimante.

Toute aide d'une âme indugente envers un débutant sera la bienvenue !

Merci à Evarisnea pour l'ajout des balises "code" - c'est évidemment beaucoup plus lisible ainsi et je tiendrai compte de votre conseil.

Dernière modification par KlausGunther ; 10/03/2010 à 09h10.
KlausGunther est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 16h28   #2
Membre régulier
 
Inscription : mai 2003
Messages : 119
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 119
Points : 80
Points : 80
Salut,
Tu fais F1 sur le nom du composant ou l'objet, en l'occurence TPrintDlg et tu tombes dans l'aide et là, tu trouveras le nom de l'unité.
Jeankiki est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 16h46   #3
Modérateur
 
Avatar de Rayek
 
Homme
Développeur informatique
Inscription : mars 2005
Messages : 4 665
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 38
Localisation : France, Haute Savoie (Rhône Alpes)

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : mars 2005
Messages : 4 665
Points : 6 080
Points : 6 080
Pour le composant PrintDialog tu as deux possibilité assez simple :

- Avoir un Datamodule dasn ton programme et poser le composants dedans
- Créer dynamiquement le PrintDialog (qui ne nécessite pas obligatoirement une form pour l'utiliser)
__________________
Modérateur Delphi Combattez la brute
Aucune réponse aux sollicitations techniques par MP

Le guide du bon forumeur :__________
[Projet en cours] Des unités pour faciliter l'utilisation d'indy : EasyIndy 1.3
Rayek est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 17h39   #4
Invité de passage
 
Klaus Fischer
Inscription : mars 2010
Messages : 18
Détails du profil
Informations personnelles :
Nom : Klaus Fischer

Informations forums :
Inscription : mars 2010
Messages : 18
Points : 1
Points : 1
Bonsoir,

Je vous remercie tous les deux pour vos réponses. Mais malgré mon post assez long, ma question n'a peut-être pas été assez précise. Je ne souhaite pas connaître le nom au niveau du développement. Ce que je cherche, c'est en cours d'exécution, le nom long de l'imprimante que l'utilisateur a chosi par l'API PrintDlg qui ouvre la boite de dialogue de configuration d'imprimante, tel que je le fais dans mon programme ci-dessus.

Je ne peux pas non plus utiliser ceci:
Code :
      printer.GetPrinter(FDevice,FDriver,FPort,FHandle);
car je n'ai pas de context "application" à l'intérieur d'une unit destinée à aller dans une DLL. Mon problème est simplement une question de technique de programmation pour laquelle ne ne suis pas assez solide en Delphi: récupérer le string adressé par un pointeur vers un pointeur avec decalage - voir le code source de mon post initial. Ce que je cherche, c'est une ligne permettant de faire:
Code :
1
2
 
PrinterName := .......... ;
en utilisant la structure Pd retourné par l'appel PrintDlg.
KlausGunther est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 19h13   #5
Membre chevronné
 
Inscription : mai 2003
Messages : 567
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 567
Points : 686
Points : 686
Citation:
Envoyé par KlausGunther
Je parcours les documentations, les forums et les sites d'info depuis des jours et je n'arrive pas à trouver comment faire. En fait, je ne sais pas comment suivre la chaine de pointeurs pd.hDevNames --> (wDeviceOffset) --> wExtra pour récupérer le nom en clair de l'imprimante.
pd.hDevNames pointe effectivement vers une structure de type DevNames
et non vers un pchar. On ne peut donc pas faire directement
PrinterName := globallock(pd.hDevNames);

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
Function SelectDefaultPrinter(): integer;
Var
  Pd: TPrintDlg;
  PrinterName: Pchar;
  DevNameStruct: PDevNames; //Ajout ici
Begin
  FillChar(Pd, sizeof(Pd), #0);
  Pd.lStructSize := sizeof(Pd);
  pd.hDevNames := 0;
  Pd.Flags := PD_RETURNDC;
 
  If PrintDlg(Pd) Then Begin
    result := 1;
    showmessage('Validé');
{  C'est dans la ligne suivante que se trouve mon problème : }
    DevNameStruct := GlobalLock(pd.hDevNames);
    PrinterName := PChar(integer(DevNameStruct) + DevNameStruct.wDeviceOffset);
 
{  l'instruction suivante affiche n'importe quoi: }
    showmessage('device=[' + PrinterName + ']');
 
{  l'instruction suivante ne marche évidemment pas:}
    SetDefaultPrinter(PrinterName);
 
    GlobalUnlock(pd.hDevNames); //<-Attention puisque PrinterName pointe
                                // pd.hDevNames, on set le Default Printer
                                // avant de faire le GlobalUnlock
  End
  Else
  Begin
    result := 0;
    showmessage('Abandonné')
  End;
End;
NOTE:
Attention de faire le GlobalUnlock seulement lorsqu'on a terminé avec le nom
du printer....
__________________
Comment dupliquer un disque...ça vous intéresse?
Tutoriel et code source delphi ici
Eric Boisvert est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 19h39   #6
Invité de passage
 
Klaus Fischer
Inscription : mars 2010
Messages : 18
Détails du profil
Informations personnelles :
Nom : Klaus Fischer

Informations forums :
Inscription : mars 2010
Messages : 18
Points : 1
Points : 1
OK, tu confirmes mon diagnostic. Alors, la vraie question: comment faire pour récupérer string représentant le nom de l'imprimante dans ma variable PrinterName: pchar; ? Car j'avais bien diagnistiqué tout cela, j'ai trouvé les structures, mais je ne sais pas comment récupérer ce string.

D'accord, je veillerai à l'emplacement du GlobalUnlock - j'en étais pas là...

Merci de ton aide !
KlausGunther est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 19h43   #7
Membre chevronné
 
Inscription : mai 2003
Messages : 567
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 567
Points : 686
Points : 686
Citation:
Envoyé par KlausGunther Voir le message
Alors, la vraie question: comment faire pour récupérer string représentant le nom de l'imprimante dans ma variable PrinterName: pchar;
Et bien le code que j'ai mis dans mon post précédent le fait non?
__________________
Comment dupliquer un disque...ça vous intéresse?
Tutoriel et code source delphi ici
Eric Boisvert est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 20h49   #8
Invité de passage
 
Klaus Fischer
Inscription : mars 2010
Messages : 18
Détails du profil
Informations personnelles :
Nom : Klaus Fischer

Informations forums :
Inscription : mars 2010
Messages : 18
Points : 1
Points : 1
Désolé, j'ai sûrement un problème pour me servir du forum, mais je ne vois pas du tout la solution permettant de récupérer le nom de l'imprimante à partir du pointeur pd.hdevicenames. Cela doit être possible mais je suis trop novice en delphi pour trouver.

J'ai essayé toutes sortes de constructions avec des "^", des globallock() pour récupérer des pointeurs, etc; je n'arrive pas non plus à additionner le décalage wDeviceOffset à mon pointeur pour pointer au bon endroit dans wExtra (qui se trouve 4 mots après le début de la structure DevNames pointée par hDeviceNames), etc.

Ce que j'aimerais trouver, c'est une instruction "verbalisée" comme suit:

PrinterName (en type pchar) := chaine de caractères à partir de (pd.hdecivenames + (pd.hdevicenames+2)) jusqu'au caractère <00> exclu


Je sais, ça paraît peu "programmeur" mais j'espère que le sens de mon problème est perceptible. En assembleur,je saurais comment faire mais je ne veux pas mélanger l'assembleur à mon code Delphi; en VisualBasic aussi, je saurais le faire, en Fortran aussi, etc, maisje ne sais pas le faire en Delphi que je pratique depuis 5 jours.
KlausGunther est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 20h52   #9
Membre chevronné
 
Inscription : mai 2003
Messages : 567
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 567
Points : 686
Points : 686
DevNameStruct := GlobalLock(pd.hDevNames);
PrinterName := PChar(integer(DevNameStruct) + DevNameStruct.wDeviceOffset);
__________________
Comment dupliquer un disque...ça vous intéresse?
Tutoriel et code source delphi ici
Eric Boisvert est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 20h58   #10
Invité de passage
 
Klaus Fischer
Inscription : mars 2010
Messages : 18
Détails du profil
Informations personnelles :
Nom : Klaus Fischer

Informations forums :
Inscription : mars 2010
Messages : 18
Points : 1
Points : 1
Ouah, tu as tiré plus vite que ton ombre ! J'ai vu ton dernier message après avoir posté le mien ! Je vais essayer de suite. Merci beaucoup !
KlausGunther est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/03/2010, 21h07   #11
Invité de passage
 
Klaus Fischer
Inscription : mars 2010
Messages : 18
Détails du profil
Informations personnelles :
Nom : Klaus Fischer

Informations forums :
Inscription : mars 2010
Messages : 18
Points : 1
Points : 1
Bon, j'ai essayé. Le compilateur n'aime pas.

Il faut sûrement définir DevNameStruct. J'avais l'impression que c'était un pointeur:
DevNameStruct: Pointer:

mais le compilateur rejette la ligne
Code :
PrinterName := PChar(integer(DevNameStruct) + DevNameStruct.|wDeviceOffset);
(j'ai mis le | à l'endroit où le curseur clignote)
avec le message
Code :
[Erreur] Test_Printer_Unit1_.pas(39): Type Record, Object ou Class requis
Comment dois-je déclarer DevNameStruct ?

Edit: j'ai modifié mon texte pour mettre la ligne en cause en entier, en marquant l'endroit du curseur (donc certainement de l'erreur).

Dernière modification par KlausGunther ; 10/03/2010 à 22h08.
KlausGunther est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/03/2010, 14h08   #12
Membre chevronné
 
Inscription : mai 2003
Messages : 567
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 567
Points : 686
Points : 686
Citation:
Envoyé par KlausGunther
Comment dois-je déclarer DevNameStruct ?
comme ça:
DevNameStruct: PDevNames;

Ici ta fonction SelectDefaultPrinter toute Fonctionnelle....
Comme dans le post précédent #5!
Je comprend pas pourquoi tu ne "copier/coller" pas la fonction dans
ton code?
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
Function SelectDefaultPrinter(): integer;
Var
  Pd: TPrintDlg;
  PrinterName: Pchar;
  DevNameStruct: PDevNames; //**** Ajout ici *****
Begin
  FillChar(Pd, sizeof(Pd), #0);
  Pd.lStructSize := sizeof(Pd);
  pd.hDevNames := 0;
  Pd.Flags := PD_RETURNDC;
 
  If PrintDlg(Pd) Then Begin
    result := 1;
    showmessage('Validé');
{  C'est dans la ligne suivante que se trouve mon problème : }
    DevNameStruct := GlobalLock(pd.hDevNames);
    PrinterName := PChar(integer(DevNameStruct) + DevNameStruct.wDeviceOffset);
 
{  l'instruction suivante affiche n'importe quoi: }
    showmessage('device=[' + PrinterName + ']');
 
{  l'instruction suivante ne marche évidemment pas:}
    SetDefaultPrinter(PrinterName);
 
    GlobalUnlock(pd.hDevNames); //<-Attention puisque PrinterName pointe
                                // pd.hDevNames, on set le Default Printer
                                // avant de faire le GlobalUnlock
  End
  Else
  Begin
    result := 0;
    showmessage('Abandonné')
  End;
End;
__________________
Comment dupliquer un disque...ça vous intéresse?
Tutoriel et code source delphi ici
Eric Boisvert est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 11/03/2010, 15h08   #13
Invité de passage
 
Klaus Fischer
Inscription : mars 2010
Messages : 18
Détails du profil
Informations personnelles :
Nom : Klaus Fischer

Informations forums :
Inscription : mars 2010
Messages : 18
Points : 1
Points : 1
MILLE MERCI !

Je n'avais pas vu la ligne
Code :
   DevNameStruct: PDevNames; //**** Ajout ici *****
Cette ligne combinée à la ligne
Code :
    PrinterName := PChar(integer(DevNameStruct) + DevNameStruct.wDeviceOffset);
résoud mon problème ! C'était bien la technique pour suivre les pointeurs sur pointeurs avec offset qui me manquait. J'ai appris quelque chose et je t'en suis reconnaissant !

Voici ma routine opérationnelle:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function SelectDefaultPrinter(): integer;
 
var
   Pd: TPrintDlg;
   PrinterName: Pchar;
   DevNameStruct: PDevNames;
 
begin
    FillChar(Pd, sizeof(Pd), #0);
    Pd.lStructSize := sizeof(Pd);
    pd.hDevNames := 0;
    Pd.Flags := PD_RETURNDC;
 
  if PrintDlg(Pd) then begin
    result := 1;
    DevNameStruct := GlobalLock(pd.hDevNames);
    PrinterName := PChar(integer(DevNameStruct) + DevNameStruct.wDeviceOffset);
    SetDefaultPrinter(PrinterName);
    GlobalUnlock(pd.hDevNames);
  end
else
  begin
    result := 0;
  end;
end;
Merci encore, et pardon pour mon manque de compréhension...
KlausGunther est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +1. Il est actuellement 02h54.


 
 
 
 
Partenaires

Hébergement Web