![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Получение названий продуктов запущенных приложений
Hint © (2007-11-17 11:14:00)Использую вот такой код:
function GetVersionString(pData: pointer; nDataSize: DWORD; sKey: string): string;
type
V_LIST = record
w1: DWORD;
w2: DWORD;
w3: PCHAR;
end;
LANGANDCODEPAGE = record
wLang, wCodePage: word;
end;
PLANGANDCODEPAGE = ^LANGANDCODEPAGE;
var
buf: PCHAR;
dwDummy: DWORD;
p: PLANGANDCODEPAGE;
c: array[0..1024] of char;
vl: V_LIST;
begin
VerQueryValue(pData, '\VarFileInfo\Translation', pointer(p), dwDummy);
vl.w1 := p^.wLang;
vl.w2 := p^.wCodePage;
vl.w3 := @sKey[1];
wvsprintf(c, '\StringFileInfo\%.4x%.4x\%s', PCHAR(@vl));
if VerQueryValue(pData, c, pointer(buf), dwDummy) then result := buf else result := '';
end;
function GetProductName(sFilename: string): string;
var
nDataSize, dwDummy: DWORD;
pData: pointer;
begin
result:='';
if sFilename='' then exit;
nDataSize := GetFileVersionInfoSize(@sFilename[1], dwDummy);
if nDataSize <= 0 then exit;
GetMem(pData, nDataSize);
GetFileVersionInfo(@sFilename[1], 0, nDataSize, pData);
result := GetVersionString(pData, nDataSize, 'ProductName');
FreeMem(pData);
end;
procedure TfrmMain.FormCreate(Sender: TObject);
var
i,j:integer;
ph: THandle;
mh: hmodule;
procs: array[0..$FFF] of dword;
count, cm: cardinal;
ModName: array[0..max_path] of char;
s1,s2: string;
begin
if EnumProcesses(@procs, sizeof(procs), count) then
begin
j:=count div 4 - 1;
for i:=0 to j do
begin
ph:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, procs[i]);
if ph > 0 then
begin
EnumProcessModules(ph, @mh, 4, cm);
GetModuleFileNameEx(ph, mh, ModName, sizeof(ModName));
s1:=string(ModName);
s2:=GetProductName(s1); //!!!
m.Lines.Add(ExtractFileName(s1)+' - '+s2);
CloseHandle(ph);
end;
end;
end;
end;
И почему-то у некоторых пользователей при вызове GetProductName происходит ошибка. Код находится в DLL, ошибка возникает у 1 человека из 50. Как найти причину - не знаю. Вроде все правильно, но что-то не так...
Leonid Troyanovsky (2007-11-17 16:26:00) [1]
> Leonid Troyanovsky © (17.11.07 16:03) [17]
> Ну, и для того, чтобы избежать подобного, нужно
> перед GetFileVersionInfo убедится можно ли файл читать.
Не, не так.
Нужно открыть на чтение, а после GFVI - закрыть(хендл).
Если на открытие - отлуп, то ресурсы не прочитать.
--
Regards, LVT.
Leonid Troyanovsky (2007-11-17 16:13:00) [2]
> Hint (17.11.07 16:08) [18]
> Кстати, может быть проблема из-за запущенного RAdmin?
Не знаю, у меня его нет.
Надо логировать имена процессов и смотреть.
Да и какая разница? Если файл локирован на чтение,
то никакой GetFileVersionInfo не получить.
--
Regards, LVT.
Hint (2007-11-17 16:08:00) [3]Кстати, может быть проблема из-за запущенного RAdmin?
Leonid Troyanovsky (2007-11-17 16:03:00) [4]
> Hint (17.11.07 15:33) [15]
> Вот нашел сообщение с похожей проблемой:
Вот, это понятней.
Т.е., исключения нет, а есть бесконечное ожидание.
Вполне возможно, что некоторые файлы локированы,
а GetFileVersionInfo требуется мапить файл для
определения размера ресурса.
Хотя, не очень понятно, почему это exe, а не длл.
Может, на той машине какой-нить терминальный сервис?
Ну, и для того, чтобы избежать подобного, нужно
перед GetFileVersionInfo убедится можно ли файл читать.
Неохота лезть в MSDN, но, кажется, что там д.б. об этом.
--
Regards, LVT.
Leonid Troyanovsky (2007-11-17 15:35:00) [5]
> Hint (17.11.07 15:15) [13]
> чтобы не было лишних вопросов про поток и DLL
Зря думаешь, что лишние.
Хотя, с другой стороны, как еще было узнать о
некорректности GetProductName :)
--
Regards, LVT.
Hint (2007-11-17 15:33:00) [6]Вот нашел сообщение с похожей проблемой:
http://t3stament01.name/08/visnet-getfileversioninfosize/
Leonid Troyanovsky (2007-11-17 15:27:00) [7]
> Hint (17.11.07 15:15) [13]
> это может быть за приложение? Функция GetProductName написана
> не корректна или я что-то не принимаю в учет?
Мне многое не нравится в оном написании, начиная со String,
который, видимо, попадает куда-то в exe.
А так - MSDN - в зубы, Win32Check - в руки - и вперед.
И никаких 1024.
--
Regards, LVT.
Hint (2007-11-17 15:15:00) [8]Дело в том, что исключение происходит в GetProductName, т.к. 'after' в логе уже не появляется.
ATL('before');
s2:=GetProductName(s1); //!!!
ATL('after');
if s2='xxx' then ...
В принципе я об этом написал в первом сообщении, только код упростил, чтобы не было лишних вопросов про поток и DLL =) Т.к. думаю в данном случае это не важно (есть before, нет after, значит ошибка в GetProductName). Но эта функция у меня, как и у многих других, работает нормально в данном контексте (совместно с EnumProcesses). Получается при запросе информации о каком-то приложении происходит ошибка. Что это может быть за приложение? Функция GetProductName написана не корректна или я что-то не принимаю в учет?
Leonid Troyanovsky (2007-11-17 14:45:00) [9]
> Hint (17.11.07 14:29) [11]
> Под инициализацией я ивел ввиду код между begin и end (BeginThread).
Это место весьма проблемное, я ж ссылку приводил.
Лучше взять за правило делать экспортируемые процедуры Init/Fin
> Приложение будет работать дальше, а записи в файл уже не
> произойдет.
Например, в том самом потоке возникло исключение, убившее поток
(немного странно, что не процесс). Т.е., то, что в then .. - важно,
скорее всего, неправильная/отсутствующая синхронизация.
--
Regards, LVT.
Hint (2007-11-17 14:29:00) [10]Под инициализацией я ивел ввиду код между begin и end (BeginThread).
while true do
begin
sleep(x);
if EnumProcesses(@procs, sizeof(procs), count) then
begin
j:=count div 4 - 1;
for i:=0 to j do
begin
ph:=OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, procs[i]);
if ph > 0 then
begin
EnumProcessModules(ph, @mh, 4, cm);
GetModuleFileNameEx(ph, mh, ModName, sizeof(ModName));
s1:=string(ModName);
ATL('before');
s2:=GetProductName(s1); //!!!
ATL('after');
m.Lines.Add(ExtractFileName(s1)+' - '+s2);
CloseHandle(ph);
end;
end;
end;
ATL('done');
end;
Если добавить в код вызов функции ATL, которая записывает передаваемую ей строку в текстовый файл, то у большинства пользователей в файле будут каждые N секунд появляться строки:
> before
> after
> ...
> before
> after
> done
> ...
А у одного человека из 50ти:
> before
> after
> ...
> before
Приложение будет работать дальше, а записи в файл уже не произойдет. При чем 'done' не появится ни разу.
Leonid Troyanovsky (2007-11-17 14:20:00) [11]
> Hint (17.11.07 14:09) [9]
> Мне нужно, чтобы код выполнялся пока приложение не будет
> закрыто, поэтому и использую 'while true do'. Есть какие-
> то другие варианты?
Например,
while (WaitForSingleObject(hEventStop, 10000) <> WAIT_OBJECT_0) do
Но, это лишь как пример, т.к. у WFSO есть и другие возвращаемые значения.
> If then - не важно.
Отнюдь.
> В любом случае этот код уже не выполняется, т.к. на GetProductName
> все прерывается.
Что значит "все прерывается"?
> Какая инициализация?
> DLL при инициализации создает один служебный поток.
--
Regards, LVT.
Hint (2007-11-17 14:09:00) [12]Спасибо, от CreateThread уже избавился (почитал справку в чем разница).
---
Мне нужно, чтобы код выполнялся пока приложение не будет закрыто, поэтому и использую 'while true do'. Есть какие-то другие варианты?
---
If then - не важно. Что-то вроде:
if s2='xxx' then MessageBox(0,'xxx','xxx',0);
В любом случае этот код уже не выполняется, т.к. на GetProductName все прерывается.
---
Какая инициализация?
Leonid Troyanovsky (2007-11-17 13:59:00) [13]
> Hint (17.11.07 13:45) [7]
Во-первых, BeginThread.
Во-вторых, while true do - в печь.
В-третьих, тема then .. - не раскрыта.
В-четвертых, как осуществлялась инициализация,
не показано.
--
Regards, LVT.
Hint (2007-11-17 13:45:00) [14]В DLL:
begin
createthread(nil, 0, @MyThread, nil, 0, mt);
end;
procedure MyThread;
begin
while true do
begin
sleep(10000);
search;
end;
end;
Где search - тоже самое, что и FormCreate, только вместо m.Lines.Add:
if s2='xxx' then ...
Leonid Troyanovsky (2007-11-17 13:34:00) [15]
> Hint (17.11.07 13:23) [4]
> Формы там нет. Код скопирован из DLL в пустой проект с формой,
> чтобы было проще искать ошибку.
Какой код работал в dll?
--
Regards, LVT.
Leonid Troyanovsky (2007-11-17 13:31:00) [16]
> Hint (17.11.07 13:23) [4]
> А DLL и поток - почему бы и нет? DLL при инициализации создает
> один служебный поток.
Показывай, как. И где завершается.
Впрочем, можно и почитать
http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx
--
Regards, LVT.
Hint (2007-11-17 13:23:00) [17]Формы там нет. Код скопирован из DLL в пустой проект с формой, чтобы было проще искать ошибку.
А DLL и поток - почему бы и нет? DLL при инициализации создает один служебный поток.
Leonid Troyanovsky (2007-11-17 12:08:00) [18]
> Hint (17.11.07 11:24) [2]
Боже мой, потоки, формы - и все свалено в dll.
Странно, что у 49 что-то работало.
--
Regards, LVT.
Hint (2007-11-17 11:24:00) [19]Поток, содержащий вызов GetProductName завершает свою работу
Kolan (2007-11-17 11:15:00) [20]> И почему-то у некоторых пользователей при вызове GetProductName
> происходит ошибка
Так и написано «Ошибка»?