Решение Реми (принятый ответ на связанный вопрос) будет нормально работать в 64-битном коде. Есть ли причина, по которой вы выбрали более хакерский ответ, опубликованный Космином, а не Реми?
- personKen White  schedule04.03.2016
comment
Поскольку у меня есть графика в потоке, мне нужен графический класс, чтобы загрузить ее правильно. Я не могу использовать трюк, загрузив файл и увидев, какой графический класс был использован... Я знаю, что FindRegisteredPictureFileFormats - это хак, но он отлично работает в 32-битной версии. Но если я смогу получить результат другим способом, я, конечно, смогу адаптировать свой код!
- personFrédéric SCHENCKEL  schedule05.03.2016
comment
Вы можете изменить код Remy для загрузки из потока, а не из файла, и использовать тот же метод, не прибегая к ассемблерному коду, который не является кросс-платформенным (включая 32/64-разрядную версию Windows).
- personKen White  schedule05.03.2016
comment
Откуда у тебя стрим? База данных, Ресурс, ...?
- personSir Rufo  schedule05.03.2016
comment
Вы не знаете, какие форматы поддерживаются? Или вы пишете код, который подключается к хост-приложению?
- personDavid Heffernan  schedule05.03.2016
comment
Вау, здесь много шумовых комментариев. Ответ Реми, похоже, решает проблему XY, указанную в удаленном комментарии.
- personFree Consulting  schedule05.03.2016
comment
Да, приложение состоит из плагинов, поэтому доступные форматы изображений могут различаться в зависимости от приложения, создавшего поток, и от того, которое его использует. Мне нужно выбрать доступный на платформе чтения, а не на платформе записи. Конечно, я мог бы изменить это поведение, но это означает, что я немного потеряю в гибкости, а платформа Win32 ведет себя иначе, чем Win64.
- personFrédéric SCHENCKEL  schedule05.03.2016
comment
@Ken, насколько я знаю, это LoadFromFile, который проверяет правильный класс, LoadFromStream нужен непосредственно правильный класс, или я ошибаюсь? Конечно, кроссплатформенная совместимость тоже не помешала бы!!!
- personFrédéric SCHENCKEL  schedule05.03.2016
comment
Изменение модуля Graphics.pas также не самое интересное решение, поскольку я использую пакеты, было бы несколько сложно заставить все пакеты полагаться на мой модифицированный Graphics.pas.
- personFrédéric SCHENCKEL  schedule05.03.2016
Я считаю, что этот блок делает то, что вы ищете. Я тестировал его на 32-битной и 64-битной Windows, с пакетами времени выполнения и без них. Я не тестировал его с распределением памяти сверху вниз, но я не верю, что есть ошибки усечения указателя.
unit FindRegisteredPictureFileFormats;
{$POINTERMATH ON}
interface
uses Classes, Contnrs;
// Extracts the file extension + the description; Returns True if the hack was successful,
// False if unsuccesful.
function GetListOfRegisteredPictureFileFormats(List: TStrings): Boolean;
// This returns the list of TGraphicClass registered; True for successful hack, false
// for unsuccesful hach
function GetListOfRegisteredPictureTypes(List: TClassList): Boolean;
implementation
uses Graphics;
type
TRelativeCallOpcode = packed record
OpCode: Byte;
Offset: Integer;
end;
PRelativeCallOpcode = ^TRelativeCallOpcode;
TLongAbsoluteJumpOpcode = packed record
OpCode: array [0 .. 1] of Byte;
Destination: Cardinal;
end;
PLongAbsoluteJumpOpcode = ^TLongAbsoluteJumpOpcode;
TReturnTList = function: TList;
// Structure copied from Graphics unit.
PFileFormat = ^TFileFormat;
TFileFormat = record
GraphicClass: TGraphicClass;
Extension: string;
Description: string;
DescResID: Integer;
end;
function FindFirstRelativeCallOpcode(StartOffset: NativeUInt): NativeUInt;
var
Ram: ^Byte;
i: Integer;
PLongJump: PLongAbsoluteJumpOpcode;
begin
Ram := nil;
PLongJump := PLongAbsoluteJumpOpcode(@Ram[StartOffset]);
if (PLongJump^.OpCode[0] = $FF) and (PLongJump^.OpCode[1] = $25) then
{$IF Defined(WIN32)}
Result := FindFirstRelativeCallOpcode(PNativeUInt(PLongJump^.Destination)^)
{$ELSEIF Defined(Win64)}
Result := FindFirstRelativeCallOpcode(PNativeUInt(PLongJump^.Destination + StartOffset + SizeOf(PLongJump^))^)
{$ELSE}
{$MESSAGE Fatal 'Architecture not supported'}
{$ENDIF}
else
begin
for i := 0 to 64 do
if PRelativeCallOpcode(@Ram[StartOffset + i])^.OpCode = $E8 then
Exit(StartOffset + i + PRelativeCallOpcode(@Ram[StartOffset + i])
^.Offset + 5);
Result := 0;
end;
end;
procedure FindGetFileFormatsFunc(out ProcAddr: TReturnTList);
var
Offset_from_RegisterFileFormat: NativeUInt;
Offset_from_RegisterFileFormatRes: NativeUInt;
begin
Offset_from_RegisterFileFormat := FindFirstRelativeCallOpcode(NativeUInt(@TPicture.RegisterFileFormat));
Offset_from_RegisterFileFormatRes := FindFirstRelativeCallOpcode(NativeUInt(@TPicture.RegisterFileFormatRes));
if (Offset_from_RegisterFileFormat = Offset_from_RegisterFileFormatRes) then
ProcAddr := TReturnTList(Pointer(Offset_from_RegisterFileFormat))
else
ProcAddr := nil;
end;
function GetListOfRegisteredPictureFileFormats(List: TStrings): Boolean;
var
GetListProc: TReturnTList;
L: TList;
i: Integer;
begin
FindGetFileFormatsFunc(GetListProc);
if Assigned(GetListProc) then
begin
Result := True;
L := GetListProc;
for i := 0 to L.Count - 1 do
List.Add(PFileFormat(L[i])^.Extension + '=' + PFileFormat(L[i])
^.Description);
end
else
Result := False;
end;
function GetListOfRegisteredPictureTypes(List: TClassList): Boolean;
var
GetListProc: TReturnTList;
L: TList;
i: Integer;
begin
FindGetFileFormatsFunc(GetListProc);
if Assigned(GetListProc) then
begin
Result := True;
L := GetListProc;
for i := 0 to L.Count - 1 do
List.Add(PFileFormat(L[i])^.GraphicClass);
end
else
Result := False;
end;
end.
personDavid Heffernanschedule05.03.2016
comment
Большое спасибо, это работает! Примечание. Проверка переполнения и отладка Dcu должны быть деактивированы. При активированном отладочном Dcus тест Offset_from_RegisterFileFormat = Offset_from_RegisterFileFormatRes становится ложным.
- personFrédéric SCHENCKEL; 07.03.2016