Wie nullterminierten String in einen Ansistring-Format konvertieren?
-
11-09-2019 - |
Frage
Ich habe einige Code, mit D7 fein kompiliert doch irgendwie D2010. Offensichtlich ist es eine Unicode-Ausgabe:
Der Compiler-Fehler ist: E2251 Doppeldeutiger überladener Aufruf von 'StrPas'
Hier ist die ganze Prozedur:
procedure GetVersionInfo;
type
PLangCharSetInfo = ^TLangCharSetInfo;
TLangCharSetInfo = record
Lang: Word;
CharSet: Word;
end;
var
FileName: array [0..260] of Char;
SubBlock: array [0..255] of Char;
VerHandle: Cardinal;
Size: Word;
Buffer: Pointer;
Data: Pointer;
DataLen: LongWord;
LangCharSetInfo: PLangCharSetInfo;
LangCharSetString: string;
begin
LabelComments.Caption := 'No version information for this program is available!';
{Get size and allocate buffer for VerInfo}
if GetModuleFileName(hInstance, FileName, SizeOf(FileName)) > 0 then
begin
Size := GetFileVersionInfoSize(FileName, VerHandle);
if Size > 0 then
begin
GetMem(Buffer, Size);
try
if GetFileVersionInfo(FileName, VerHandle, Size, Buffer) then
begin
{Query first language and that language blocks version info}
if VerQueryValue(Buffer, '\VarFileInfo\Translation', Pointer(LangCharSetInfo), DataLen) then
begin
LangCharSetString := IntToHex(LangCharSetInfo^.Lang, 4) +
IntToHex(LangCharSetInfo^.CharSet, 4);
if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\ProductName'), Data, DataLen) then
begin
LabelProductName.Caption := StrPas(Data);
Caption := LabelProductName.Caption;
end;
if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\FileVersion'), Data, DataLen) then
LabelVersion.Caption := StrPas(Data);
if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\LegalCopyright'), Data, DataLen) then
LabelCopyright.Caption := StrPas(Data);
if VerQueryValue(Buffer, StrPCopy(SubBlock, '\StringFileInfo\' + LangCharSetString + '\Comments'), Data, DataLen) then
LabelComments.Caption := StrPas(Data);
end;
end;
finally
FreeMem(Buffer, Size);
end;
end
end;
end;
Der Doc für StrPas sagt
function StrPas(const Str: PAnsiChar): AnsiString; overload;
Diese Funktion wird fasor Rückwärtskompatibilität zur Verfügung gestellt nur. Um einen nullterminierten String in einen Ansistring zu konvertieren oder native Delphi-String, verwenden Sie eine Typumwandlung oder ein signment.
Die Frage ist also sollte ich entfernen Sie alle Anrufe an StrPas? Die einzige Art, wie ich dies machen zu kompilieren ist ein Hardcast zu Pansi char zu tun:
LabelProductName.Caption := StrPas(PAnsiChar(Data));
Lösung
Sie bearbeiten Ihre Frage mit einer vollen Compilierung Probe. Gut!
Es ist wahrscheinlich die am einfachsten, wenn Sie die JCL für diese verwenden würden (Link unten). Dann könnten Sie TJclFileVersionInfo, das tut alles, was Sie wollen, und berücksichtigt einige esoterische Dinge, die die Version halten kann.
Dann ist Ihre Business-Logik würde so etwas wie dieses werden:
function GetStringFileInfo(
const Buffer: Pointer; const SubBlock: PChar;
const LangCharSetString: string; const Kind: string): string;
var
QueryString: string;
Data: Pointer;
DataCharacters: PChar absolute Data;
DataLen: LongWord;
begin
Result := '';
QueryString := Format('%s\StringFileInfo\%s\%s', [SubBlock, LangCharSetString, Kind]);
if VerQueryValue(Buffer, PChar(QueryString), Data, DataLen) then
Result := StrPas(DataCharacters);
end;
procedure GetVersionInfoStrings(var Comments: string; var ProductName: string;
var Caption: string; var Version: string; var Copyright: string);
type
PLangCharSetInfo = ^TLangCharSetInfo;
TLangCharSetInfo = record
Lang: Word;
CharSet: Word;
end;
var
FileName: array [0 .. 260] of Char;
SubBlock: array [0 .. 255] of Char;
VerHandle: Cardinal;
Size: Word;
Buffer: Pointer;
Data: Pointer;
DataCharacters: PChar absolute Data;
DataLen: LongWord;
LangCharSetInfo: PLangCharSetInfo;
LangCharSetString: string;
begin
Comments := 'No version information for this program is available!';
{ Get size and allocate buffer for VerInfo }
if GetModuleFileName(hInstance, FileName, SizeOf(FileName)) > 0 then
begin
Size := GetFileVersionInfoSize(FileName, VerHandle);
if Size > 0 then
begin
GetMem(Buffer, Size);
try
if GetFileVersionInfo(FileName, VerHandle, Size, Buffer) then
begin
{ Query first language and that language blocks version info }
if VerQueryValue(Buffer, '\VarFileInfo\Translation', Pointer
(LangCharSetInfo), DataLen) then
begin
LangCharSetString :=
IntToHex(LangCharSetInfo^.Lang, 4) +
IntToHex(LangCharSetInfo^.CharSet, 4);
ProductName := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'ProductName');
Version := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'FileVersion');
Copyright := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'LegalCopyright');
Comments := GetStringFileInfo(Buffer, SubBlock, LangCharSetString, 'Comments');
Caption := ProductName;
end;
end;
finally
FreeMem(Buffer, Size);
end;
end
end;
end;
Und in der Benutzeroberfläche, müssen Sie Ihre Business-Logik nennen, und setzen die Ergebnisse in die verschiedenen Kontrollen.
- jeroen
Antwort vor edit:
Ihr Code kompiliert nicht wie es ist, so ohne mehr Kontext, ist es schwer, Ihre Suche zu beantworten.
Was sind die Datentypen von Buffer, Subblock, LongCharSetString und DataLen? Wie haben Sie Buffer erhalten?
Sind Daten wirklich bedeuten ein Zeiger auf (Ansi oder Unicode) Zeichen zu sein? Sollte es nicht letztlich seinen Hinweis auf PVSFixedFileInfo?
(A-Seite Frage: warum innerhalb der Benutzeroberfläche Ihre Business-Logik ist, wenn Sie Ihre Logik in eine separate Funktion irgendwo geteilt hatte, dann würden Sie wahrscheinlich eine Kompilierung Routine haben, die als Basis für Ihre Frage gedient haben könnte, die Macht. hat die Frage an erster Stelle beantwortet).
Für Fragen wie das Ihre, ich nehme in der Regel einen Blick auf Einheiten in der JCL oder < a href = "http://jvcl.delphi-jedi.org/" rel = "nofollow noreferrer"> JVCL . Sie haben viel Mühe in denen gestellt werden Unicode-kompatibel.
Ihr Code, die VerQueryValue ist dies ein in Einheit JclFileUtils, Methode VersionFixedFileInfo verwenden:
// Fixed Version Info routines
function VersionFixedFileInfo(const FileName: string; var FixedInfo: TVSFixedFileInfo): Boolean;
var
Size, FixInfoLen: DWORD;
Handle: THandle;
Buffer: string;
FixInfoBuf: PVSFixedFileInfo;
begin
Result := False;
Size := GetFileVersionInfoSize(PChar(FileName), Handle);
if Size > 0 then
begin
SetLength(Buffer, Size);
if GetFileVersionInfo(PChar(FileName), Handle, Size, Pointer(Buffer)) and
VerQueryValue(Pointer(Buffer), DirDelimiter, Pointer(FixInfoBuf), FixInfoLen) and
(FixInfoLen = SizeOf(TVSFixedFileInfo)) then
begin
Result := True;
FixedInfo := FixInfoBuf^;
end;
end;
end;
Hope this wird gestartet Sie Ihre Lösung zu finden.
- jeroen
Andere Tipps
StrPas hat sich seit Delphi 1, erforderlich gewesen, da sie die Delphi-Compiler verändert die Zeichenfolge richtig ohne einen Funktionsaufruf zu konvertieren. Siehe: http: // coding.derkeiler.com/Archive/Delphi/borland.public.delphi.language.objectpascal/2004-01/1793.html
So weisen Sie einfach es wie folgt:
LabelProductName.Caption := PAnsiChar(Data);
Und ja, sollten Sie alle Anrufe an StrPas entfernen. Es kann nicht helfen, und können Sie nur in Schwierigkeiten in D2010 erhalten.
Ich denke, das Hauptproblem dabei ist, dass Daten, die als Pointer
eingegeben werden und keine PChar
.
Auf jeden Fall die Besetzung macht die ganze Arbeit für Sie also, wenn Sie den Code sowieso ändern müssen, die Besetzung nur so gut wie der Funktionsaufruf ist.
Lassen Sie mich anders formulieren. Wenn Sie die Zeichenfolge in einem PChar
oder PAnsiChar
haben, ist es zuweisungskompatibel mit String
. Der Grund, warum Sie benötigen ein gegossenes hier ist, dass man es als Pointer
eingegeben hat.
Konvertieren PAnsiChar zu Ansistring und dann auf Unicode-String:
LabelProductName.Caption := String(AnsiString(PAnsiChar(Data)));