Seite 1 von 2

Verfasst: 14.05.2007 17:05
von Shardik
shadow hat geschrieben: Aber irgendwie klappt das nicht, d. h. es wird kein Drucker mit dem Attribut PRINTER_ATTRIBUTE_DEFAULT gefunden.
Die Konstante PRINTER_ATTRIBUTE_DEFAULT wird nur von Win9x/ME entsprechend gesetzt und der Code funktioniert daher nur unter diesen Beitriebssystemen (aber auch nur dann, wenn man in SelectDefaultPrinter() auf Gleichheit (nicht Ungleichheit!) mit #PRINTER_ATTRIBUTE_DEFAULT prüft :wink: ):
MSDN hat geschrieben: PRINTER_ATTRIBUTE_DEFAULT Windows 95/98/Me: Indicates the printer is the default printer in the system.
http://msdn2.microsoft.com/en-us/library/ms536023.aspx

Aber warum alles so kompliziert machen? gnozal hat im englischen Forum bereits 2004 ein Beispiel veröffentlicht, das sowohl alle installierten Drucker als auch den Default-Drucker unter allen Windows-Betriebssystemen ermittelt:
http://www.purebasic.fr/english/viewtop ... 83&start=2

Hier ist sein an PB 4 angepaßter Code (LinkedList als global definiert):

Code: Alles auswählen

Global NewList Imprimantes.s() 

Procedure.l GetInstalledPrinters() ; in linked list Imprimantes() 
  ClearList(Imprimantes()) 
  Buffersize.l  = 8102 
  *Buffer = GlobalAlloc_(#GMEM_FIXED | #GMEM_ZEROINIT, Buffersize) 
  TempPrinter.s = Space(1024) 
  If GetProfileString_("devices", 0, "", *Buffer, Buffersize) 
    TempString.s = PeekS(*Buffer) 
    Length.l = Len(TempString) 
    While TempString <> "" 
      GetPrivateProfileString_("devices", TempString, "", TempPrinter, 1024, "Win.Ini") 
      ; Debug "Device  : " + TempString 
      ; Debug "Driver  : " + StringField(TempPrinter,1,",") 
      ; Debug "Port    : " + StringField(TempPrinter,2,",") 
      AddElement(Imprimantes()) 
      Imprimantes() = TempString 
      TempString = PeekS(*Buffer + Length + 1) 
      Length = Length + Len(TempString) + 1 
    Wend 
  EndIf 
  GlobalFree_(*Buffer) 
  ProcedureReturn CountList(Imprimantes()) 
EndProcedure 
; 
Procedure.s GetDefaultPrinter() 
  STDPrinterName$ = Space(260) 
  If GetPrivateProfileString_("WINDOWS","DEVICE","", @STDPrinterName$, 260, "Win.Ini") 
    ImprimanteParDefaut.s = StringField(STDPrinterName$, 1,",") 
  EndIf 
  ProcedureReturn ImprimanteParDefaut 
EndProcedure

Debug "Anzahl Drucker: " + Str(GetInstalledPrinters())

ForEach Imprimantes()
  Debug Imprimantes()
Next

Debug "-----"

Debug "Default-Drucker: " + GetDefaultPrinter()
Auch der Code für den Default-Drucker ist kürzer als der von ts-soft zitierte aus der PBOSL. :wink:

Verfasst: 14.05.2007 17:33
von ts-soft
Shardik hat geschrieben: Auch der Code für den Default-Drucker ist kürzer als der von ts-soft zitierte aus der PBOSL. :wink:
Das auslesen der nur aus kompatibilitätsgründen vorhandenen Win.ini halte
ich nicht für praktikabel. Die Werte müssen dort nicht stehen, bzw. die Ini
muß garnicht existieren :wink:

Es gibt soviele Win3.11 überbleibsel, die meist noch funktionieren, aber die
sind in meinen Augen nicht empfehlenswert. Haste den Code mal unter
Vista getestet?

Verfasst: 15.05.2007 09:57
von shadow
@Shardik Hi,
...wenn man in SelectDefaultPrinter() auf Gleichheit (nicht Ungleichheit!)...
Ja, die Zeile habe ich ohne zu testen direkt im Forum auf den Ursprungszustand zurückversetzen wollen. Hab es dann da wohl übersehen :oops: Aber wie du gesagt hast, das funktioniert eh nur unter Win9x/ME.

Ich verwende die API genau aus dem Grund, den ts-soft beschrieben hat. Sollte sich jemals was am Speicherort oder -art der Einstellungen ändern, so muss ich nichts anpassen :wink:

Außerdem ist die Funktion gar nicht so umfangreich:

Code: Alles auswählen

Procedure.s EP_GetDefaultPrinter()
	Protected id.l, name$, buflen.l
	id = OpenLibrary(#PB_Any, "winspool.drv")
	If Not id : ProcedureReturn "" : EndIf
	
	name$ = Space(255)
	buflen = 255
	CallFunction(id, "GetDefaultPrinterA", @name$, @buflen)
	
	CloseLibrary(id)
	ProcedureReturn name$
EndProcedure
Aber danke für deine konstruktive Kritik Shardik :allright:

Verfasst: 15.05.2007 11:16
von Shardik
ts-soft hat geschrieben: Das auslesen der nur aus kompatibilitätsgründen vorhandenen Win.ini halte ich nicht für praktikabel. Die Werte müssen dort nicht stehen, bzw. die Ini muß garnicht existieren
Die Kompatibilität ist zumindest bis Windows XP gegeben. Microsoft selbst geht im Knowledge Base Artikel 266767 (http://support.microsoft.com/kb/266767), der am 23.8.06 zuletzt überarbeitet wurde, in einem Visual BASIC-Beispiel diesen Weg, um den Default-Drucker zu ändern:

Code: Alles auswählen

Private Sub SetDefaultPrinter(ByVal PrinterName As String, _
    ByVal DriverName As String, ByVal PrinterPort As String)
    Dim DeviceLine As String
    Dim r As Long
    Dim l As Long
    DeviceLine = PrinterName & "," & DriverName & "," & PrinterPort
    ' Store the new printer information in the [WINDOWS] section of
    ' the WIN.INI file for the DEVICE= item
    r = WriteProfileString("windows", "Device", DeviceLine)
    ' Cause all applications to reload the INI file:
    l = SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, "windows")
End Sub
Dabei wird der neue Drucker-Name in der Win.Ini eingetragen (sollte diese Datei - warum auch immer - nicht existieren, wird sie erstellt) und dann alle Anwendungen über ein SendMessage() darüber informiert. Deine obigen Argumente sind daher nicht zutreffend... :wink:
Haste den Code mal unter Vista getestet?
Ich kenne bisher keine Firma/öffentliche Verwaltung/Kunden, die auf Vista umgestiegen sind. Die am häufigsten anzutreffende Aussage im professionellen Bereich ist:
"Wir setzen Vista erst ein, wenn das erste Service-Pack erschienen ist und der Großteil der Treiber in vernünftiger Qualität für Vista verfügbar ist..."

Trotzdem wäre ich natürlich dankbar über ein Feedback von jemandem, der dies auch unter Vista getestet hat.

Mein zuerst veröffentlichtes Beispiel hat den Vorteil, von Windows 95 bis Windows XP einsetzbar zu sein (Win98, WinNT und WinXP getestet). Dein PBOSL-Beispiel läuft zum Beispiel nicht unter Windows NT... /:->

Verfasst: 15.05.2007 12:20
von ts-soft
Dann sollte man wohl, je nach OSVersion() den passenden Code ausführen.
Die Codelänge sollte wohl keine Rolle spielen, und INI-auslesen ist sowie
eine sehr langsame API-Funktion.

Warum MS für VB programmierer solche Beispiele postet, behalte ich lieber
für mich :mrgreen:

Verfasst: 15.05.2007 12:43
von Shardik
ts-soft hat geschrieben: Dann sollte man wohl, je nach OSVersion() den passenden Code ausführen. Die Codelänge sollte wohl keine Rolle spielen, und INI-auslesen ist sowie eine sehr langsame API-Funktion.
Die Code-Länge spielt insofern eine Rolle, als daß ein kurzer übersichtlicher Code meist leichter wartbar ist (die Ausführungsgeschwindigkeit ist bei diesen Problemstellungen meist zu vernachlässigen). Aber wenn man langen, unübersichtlichen Code mit vielen Extra-Abfragen für jede mögliche Betriebssystem-Variante kodieren muß, dient dies nicht gerade der leichten Wartbarkeit und Übersicht... :wink:

Außerdem habe ich irgendwo von Microsoft gelesen (leider finde ich die Quelle nicht mehr), daß die Win.Ini zumindest bis WinXP offiziell in Form eines Mapping unterstützt wird, d.h. selbst bei Nichtvorhandensein der Win.Ini wird aus Registry-Einträgen eine "virtuelle" Win.Ini erstellt, sodaß man zumindest im Drucker-Bereich hier auf der sicheren Seite ist. Ansonsten bin ich in den meisten Fällen auch Deiner Meinung, daß man die Finger von altem (und nicht mehr offiziell unterstütztem) Win16-Kram lassen sollte... :)

Verfasst: 15.05.2007 13:08
von shadow
Es gibt immer Vor- und Nachteile - es gibt keinen optimalen Lösungsweg in der Softwareentwicklung. Ich meine eine simple "Hallo Welt!"-Demo kann man auf unterschiedliche Arten realisieren.
Mag sein, dass dieser Code irgendwann Probleme mit sich bringen wird. Aber bis dahin hat man vielleicht eine andere Lösung oder PureBasic hat diese Funktionalität bereits integriert :mrgreen: