четверг, 19 мая 2011 г.

Как получить время сборки из .exe или .dll

Если приложение падает, то Windows 7 показывает такое окошко:
Тут ясно видно какие версии компонентов программы упали. Как же можно извлеч эту информацию?

Сначала я подумал, что надо использовать VERSIONINFO, но как выяснилось эти данные надо отдельно описывать в ресурсном файле (.rc) и отдельно вкомпилять в экзешник.

Затем мне объяснили что время сборки добавляется линкером в специальном заголовке. Все эти exe/dll являются файлами формата Portable Executable и в состав вижуал студии даже входит специальная утилита dumpbin, с помощью которой эти загаловки можно просмотреть:
> dumpbin /all lib.dll

------------------8-<-------------------------------------------

FILE HEADER VALUES
14C machine (x86)
5 number of sections
4DD3E95F time date stamp Wed May 18 19:44:31 2011 ← Вот оно!
0 file pointer to symbol table
0 number of symbols
E0 size of optional header

---------------8-<----------------------------------

Если это смог извлечь dumpbin, то сможем и мы. В файле windows.h описана структура
IMAGE_DOS_HEADERS и IMAGE_NT_HEADERS. В файле они расположены подряд, один за другим. Адрес следующего заголовка лежит в IMAGE_DOS_HEADERS::e_lfanew. Само же время сборки лежит тут: IMAGE_NT_HEADERS::IMAGE_FILE_HEADER::FileHeader.TimeDateStamp (в секундах с начала эпохи UNIX).

Получается такой код:

void print_timestamp(QString fpath)
{
IMAGE_NT_HEADERS header = {0};
IMAGE_DOS_HEADER dosHeader = {0};
QFile f(fpath);

if (!f.open(QIODevice::ReadOnly))
{
return;
}

f.read(reinterpret_cast<char*>(&dosHeader), sizeof(dosHeader));
if (dosHeader.e_magic == IMAGE_DOS_SIGNATURE
&& f.seek(dosHeader.e_lfanew)
&& f.read(reinterpret_cast<char*>(&header), sizeof(header)))
{
QDateTime dt;
dt.setTime_t(header.FileHeader.TimeDateStamp);
qDebug("Timestamp: 0x%0X (%s UTC)",
header.FileHeader.TimeDateStamp,
qPrintable(dt.toUTC().toString("dd.MM.yyyy hh:mm:ss")));
}

f.close();
}


Рекомендую изучить: хорошая статья о PE формате

Комментариев нет:

Отправить комментарий