AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Funktion von PAnsiChar zu PWideChar ändern - wie?

Funktion von PAnsiChar zu PWideChar ändern - wie?

Offene Frage von "bjoernga"
Ein Thema von bjoernga · begonnen am 14. Dez 2014 · letzter Beitrag vom 15. Dez 2014
Antwort Antwort
bjoernga

Registriert seit: 26. Nov 2014
3 Beiträge
 
#1

Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 14. Dez 2014, 02:16
Delphi-Version: 7
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!
  Mit Zitat antworten Zitat
Lyan

Registriert seit: 5. Aug 2011
188 Beiträge
 
#2

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 14. Dez 2014, 02:45
Delphi-Quellcode:
var
  a: PAnsiChar;
  b: PWideChar;
begin
  a := 'Hallo';
  b:=StrAlloc (length(a)+1);
  StrPCopy(b,WideString(a));
  showmessage(b);
  StrDispose(b);
end;

Geändert von Lyan (14. Dez 2014 um 02:48 Uhr)
  Mit Zitat antworten Zitat
bjoernga

Registriert seit: 26. Nov 2014
3 Beiträge
 
#3

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 14. Dez 2014, 15:56
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!
  Mit Zitat antworten Zitat
Lyan

Registriert seit: 5. Aug 2011
188 Beiträge
 
#4

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 15. Dez 2014, 03:43
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?

Geändert von Lyan (15. Dez 2014 um 03:51 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von baumina
baumina

Registriert seit: 5. Mai 2008
Ort: Oberschwaben
1.275 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 15. Dez 2014, 06:20
Verwende statt
sizeof(WideChar) -> length(WideChar)
Hinter dir gehts abwärts und vor dir steil bergauf ! (Wolfgang Ambros)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.536 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 15. Dez 2014, 07:29
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.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
Benutzerbild von baumina
baumina

Registriert seit: 5. Mai 2008
Ort: Oberschwaben
1.275 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 15. Dez 2014, 07:57
Ah, falsch gelesen, dachte das SizeOf geht auf das Array of WideChar.
Hinter dir gehts abwärts und vor dir steil bergauf ! (Wolfgang Ambros)
  Mit Zitat antworten Zitat
bjoernga

Registriert seit: 26. Nov 2014
3 Beiträge
 
#8

AW: Funktion von PAnsiChar zu PWideChar ändern - wie?

  Alt 15. Dez 2014, 22:11
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
Miniaturansicht angehängter Grafiken
screenshot-cpu-fenster.jpg  
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:31 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