Из documentation:
Вы должны инициализировать Component Object Model (COM) с CoInitialize или OleInitialize до вызова SHGetFileInfo.
В графическом приложении COM инициализируется в основном потоке. Но из других потоков, которые не происходят автоматически. Вам нужно будет сделать это явно.
Кроме того, вы неправильно обрабатываете ошибки. Помните, что в функциях Windows API не возникают исключения. Поэтому ваш обработчик исключений бессмыслен и должен быть удален. Вместо этого вам нужно проверить возвращаемое значение вашего звонка на SHGetFileInfo
, как описано в документации.
Beyond, что ваш код работает, как показывает эта программа:
{$APPTYPE CONSOLE}
uses
Classes, Windows, ActiveX, ShellAPI;
var
hThread: THandle;
ThreadId: Cardinal;
function ThreadFunc(Parameter: Pointer): Integer;
var
shfi: TSHFileInfo;
begin
CoInitialize(nil);
Try
if ShGetFileInfo('C:\windows\explorer.exe', 0, shfi, SizeOf(shfi), SHGFI_ICON or SHGFI_LARGEICON)=0 then
begin
Writeln('ShGetFileInfo Failed');
Result := 1;
exit;
end;
Writeln(shfi.hIcon);
Finally
CoUninitialize;
End;
Result := 0;
end;
begin
hThread := BeginThread(nil, 0, ThreadFunc, nil, 0, ThreadId);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
Readln;
end.
Я ожидаю, что любая неудача вы замечаете на самом деле связано с конкретным файлом, который вы пытаетесь осмотреть.
Update: Кажется ShGetFileInfo
не поточно. При одновременном вызове нескольких потоков он терпит неудачу. Я считаю, что вам нужно будет сериализовать вызовы на ShGetFileInfo
с блокировкой. Например, TCriticalSection
.
Следующая программа, основанный на SSCCE предоставленных вами в комментариях, демонстрирует это:
{$APPTYPE CONSOLE}
uses
SysUtils,
Classes,
SyncObjs,
Windows,
ActiveX,
ShellAPI;
var
hThreads: TWOHandleArray;
ThreadId: Cardinal;
Lock: TCriticalSection;
function ThreadFunc(Parameter: Pointer): Integer;
var
shfi: TSHFileInfo;
randomnumber: integer;
fname: string;
begin
CoInitialize(nil);
Try
fname := 'c:\desktop\file'+IntToStr(Integer(Parameter))+'.exe';
Lock.Acquire;
try
if ShGetFileInfo(pchar(fname), 0, shfi, SizeOf(shfi), SHGFI_ICON or SHGFI_LARGEICON)=0 then
begin
Writeln('ShGetFileInfo Failed');
Result := 1;
exit;
end;
Writeln(shfi.hIcon);
finally
Lock.Release;
end;
Finally
CoUninitialize;
End;
Result := 0;
end;
var
i: integer;
begin
Lock := TCriticalSection.Create;
for i := 0 to 9 do
hThreads[i] := BeginThread(nil, 0, ThreadFunc, Pointer(i), 0, ThreadId);
WaitForMultipleObjects(10, @hThreads,true, INFINITE);
Readln;
end.
Снимите критическую секцию, и призывы к ShGetFileInfo
успеху, но вернуть 0
за значок ручки. С критической секцией возвращаются правильные значки.
Бьюсь об заклад, вы забыли инициализировать COM. – TLama
как это сделать? – user1238784
['This way'] (http://pastebin.com/iQs2YYTb). – TLama