![]() |
Delphi-Version: 7
Funktion von PAnsiChar zu PWideChar ändern - wie?
Hallo,
ich habe im alten Borland C++Builder 6 ein Projekt mit Hilfe der Tnt Unicode Controls auf Unicode umgebaut. Anschließend hab ich festgestellt, das beim Drucken immer die Titel der Druckaufträge durch Fragezeichen ersetzt werden, was kein Wunder ist, da die Printers.pas ja immer noch mit AnsiString/AnsiChar arbeitet. Also die Klasse TPrinter in eine neue Unit kopiert und ebenfalls umgestrickt (heißt jetzt TPrinterW), was trotz meiner bescheidenen Delphi-Kenntnisse relativ problemlos war. Nicht problemlos ist allerdings eine Funktion aus TPrinterSetupDialog - ich hab kein Plan, was ich da falsch mache. Hier die originale Funktion aus der dialogs.pas vom BCB6 (PChar = PAnsiChar):
Delphi-Quellcode:
procedure GetPrinter(var DeviceMode, DeviceNames: THandle);
var Device, Driver, Port: array[0..1023] of char; DevNames: PDevNames; Offset: PChar; begin Printer.GetPrinter(Device, Driver, Port, DeviceMode); if DeviceMode <> 0 then begin DeviceNames := GlobalAlloc(GHND, SizeOf(TDevNames) + StrLen(Device) + StrLen(Driver) + StrLen(Port) + 3); DevNames := PDevNames(GlobalLock(DeviceNames)); try Offset := PChar(DevNames) + SizeOf(TDevnames); with DevNames^ do begin wDriverOffset := Longint(Offset) - Longint(DevNames); Offset := StrECopy(Offset, Driver) + 1; wDeviceOffset := Longint(Offset) - Longint(DevNames); Offset := StrECopy(Offset, Device) + 1; wOutputOffset := Longint(Offset) - Longint(DevNames);; StrCopy(Offset, Port); end; finally GlobalUnlock(DeviceNames); end; end; end; Und hier meine WideString-Variante (die W-Funktionen sind aus TntWideStrUtils):
Delphi-Quellcode:
Das wird anstandslos kompiliert, aber beim ausführen ploppt jedesmal das CPU-Fenster auf. Der Fehler liegt IMHO irgendwo nach dem "try". Kann mir da jemand helfen?
procedure TPrinterSetupDialogW.GetPrinter(var DeviceMode, DeviceNames: THandle);
var Device, Driver, Port: array[0..1023] of WideChar; DevNames: PDevNames; Offset: PWideChar; begin PrinterW.GetPrinter(Device, Driver, Port, DeviceMode); if DeviceMode <> 0 then begin DeviceNames := GlobalAlloc(GHND, SizeOf(TDevNames) + (WStrLen(Device) + WStrLen(Driver) + WStrLen(Port) + 3) * sizeof(WideChar)); DevNames := PDevNames(GlobalLock(DeviceNames)); try Offset := PWideChar(PByte(DevNames)) + SizeOf(TDevnames); with DevNames^ do begin wDriverOffset := (Longint(Offset) - Longint(DevNames)) div 2; Offset := WStrECopy(Offset, Driver) + 1; wDeviceOffset := (Longint(Offset) - Longint(DevNames)) div 2; Offset := WStrECopy(Offset, Device) + 1; wOutputOffset := (Longint(Offset) - Longint(DevNames)) div 2; WStrCopy(Offset, Port); end; finally GlobalUnlock(DeviceNames); end; end; end; Vielen Dank! |
AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
Delphi-Quellcode:
var
a: PAnsiChar; b: PWideChar; begin a := 'Hallo'; b:=StrAlloc (length(a)+1); StrPCopy(b,WideString(a)); showmessage(b); StrDispose(b); end; |
AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
Danke für die schnelle Antwort; sie hilft mir aber nicht wirklich weiter. Ich will ja nicht PAnsiChar nach PWideChar kopieren. Außerdem würde das im C++Builder 6 (entspricht etwa Delphi 7 - soweit ich weiß) gar nicht funktionieren, da StrPCopy() PAnsiChar als Parameter erwartet, und ShowMessage() einen AnsiString. Es gilt ja string = AnsiString bei Delphi-Versionen < 2009.
Ich hab wohl die Themen-Überschrift ziemlich unzutreffend formuliert... Das Problem ist, daß durch die Umstellung der Prozedur auf WideChar die Berechnung von Offset (für die DEVNAMES-Stucktur) nicht mehr stimmt. DEVNAMES erwartet die Anzahl der Zeichen, Offset ist PWideChar, Longint(Offset) - Longint(DevNames) müßte IMHO also zuviel (doppelt soviel) zurückgeben. Deswegen hab ich das ganze durch zwei geteilt. Funktioniert aber nicht. Oder ist schon die Zuweisung an Offset (die Zeile nach "try") falsch? Ich komme wie gesagt aus der C++ Ecke und kenne die Feinheiten von Delphi nicht so gut... Danke schonmal! |
AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
Achso,
hm, debug doch mal und schau in welcher Zeile es genau passiert. Ansonsten tippe ich einfach mal auf einen Fehler beim allocaten von DevNames. Also quasi, dass er in der Zeile: wDriverOffset := (Longint(Offset) - Longint(DevNames)) div 2; beim Versuch Devnames.wDriverOffset etwas zuzuweisen ne exception wirft? |
AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
Verwende statt
Delphi-Quellcode:
->
sizeof(WideChar)
Delphi-Quellcode:
length(WideChar)
|
AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
Wieso denn das? Length(WideChar) sollte doch immer 1 ergeben (im Gegensatz zum benötigten Speicher), da könnte man sich die Multiplikation auch sparen.
|
AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
Ah, falsch gelesen, dachte das SizeOf geht auf das Array of WideChar.
|
AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
Liste der Anhänge anzeigen (Anzahl: 1)
Ich bin mir inzwischen gar nicht mehr sicher, ob der Fehler wirklich in der obigen Prozedur (#1) liegt. Weil: wenn ich die Zeilen zwischen
Delphi-Quellcode:
auskommentiere, tritt der Fehler nicht auf. In der aufrufenden Funktion sieht das so aus:
with DevNames^ do
begin // wDriverOffset := (Longint(Offset) - Longint(DevNames)) div 2; // usw ... end;
Delphi-Quellcode:
Wenn ich mit F7/F8 durch den Code marschiere, gibts keine Exception, stattdessen ploppt das CPU-Fenster immer nach Result := TaskModalDialog() auf. Ich hab das mal als Screenshot angehängt, falls sich da jemand auskennt - für mich könnt da genausogut chinesisch drinstehen...
function TPrinterSetupDialogW.Execute: Boolean;
var PrintDlgRec: TPrintDlgW; DevHandle: THandle; begin FillChar(PrintDlgRec, SizeOf(PrintDlgRec), 0); with PrintDlgRec do begin lStructSize := SizeOf(PrintDlgRec); hInstance := SysInit.HInstance; GetPrinter(DevHandle, hDevNames); // <- Prozedur aus #1 hDevMode := CopyData(DevHandle); Flags := PD_ENABLESETUPHOOK or PD_PRINTSETUP; lpfnSetupHook := DialogHook; hWndOwner := Application.Handle; Result := TaskModalDialog(@PrintDlgW, PrintDlgRec); // <- Es knallt, wenn diese Funktion zurückkommt if Result then SetPrinter(hDevMode, hDevNames) else begin if hDevMode <> 0 then GlobalFree(hDevMode); if hDevNames <> 0 then GlobalFree(hDevNames); end; end Ich end; Möglicherweise kollidiert da irgendwas in den Tiefen der Ansi-VCL mit den Tnt-Controls: in TntForms und auch in TntDialogs werden ja die Windows Messages ganz schön umgebogen. Und der TPrinterSetupDialog klopft da ein Ansi-gekapseltes Fenster dazwischen - könnts das sein? (Oder andersrum: kann das gut gehen?) Ich werd das ganze wohl anders angehen: aus C++ heraus direkt die Win-API-Funktion PrintDlgW() aufrufen, dann hätt ich mich am Problem vorbeigemogelt... Falls aber doch noch jemand die Lösung findet, hätt ich natürlich nichts dagegen :wink: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:22 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz