Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Funktion von PAnsiChar zu PWideChar ändern - wie? (https://www.delphipraxis.net/183132-funktion-von-pansichar-zu-pwidechar-aendern-wie.html)

bjoernga 14. Dez 2014 02:16

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:
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;
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?

Vielen Dank!

Lyan 14. Dez 2014 02:45

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;

bjoernga 14. Dez 2014 15:56

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!

Lyan 15. Dez 2014 03:43

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?

baumina 15. Dez 2014 06:20

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
 
Verwende statt
Delphi-Quellcode:
sizeof(WideChar)
->
Delphi-Quellcode:
length(WideChar)

DeddyH 15. Dez 2014 07:29

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.

baumina 15. Dez 2014 07:57

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?
 
Ah, falsch gelesen, dachte das SizeOf geht auf das Array of WideChar.

bjoernga 15. Dez 2014 22:11

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:
      with DevNames^ do
      begin
      //  wDriverOffset := (Longint(Offset) - Longint(DevNames)) div 2;
      //  usw ...
      end;
auskommentiere, tritt der Fehler nicht auf. In der aufrufenden Funktion sieht das so aus:
Delphi-Quellcode:
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;
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...

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 09:01 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz