Всем хорош Visual Studio (хоть и не все так думают), но порядка в нем нет. Нет порядка с номерами версий и билдов, вот и изгаляются несчастные программисты создавая папки типа 08_02_2004_12_47_56 или смотрят напрягая натруженные глаза на дату создания файла. А ведь иногда хочется, чтобы и в заголовке окна любимой программы было написано V2.0 Build 2600 SP2 или что-то типа того.
В этой статье я расскажу как это сделать. Мой способ не претендует на рулезность, но работает и я им давно пользуюсь.

Мы используем возможность сборщика Visual Studio выполнять так называемый Pre-Build step. Обычно такие вещи используются для регистрации COM компонентов, но мы вдохнем в него новую жизнь.
Идея такая: будем в тех местах, где нам нужен номер версии или билда, использовать макросы, определенные в специальном заголовочном файле, а этот файл у нас будет генерировать/обновлять специальная прога, которую мы сейчас напишем.

Итак, создаем новый проект, Win32 console project под названием version, ставим поддержку для ATL и MFC и редактируем файл чтобы получилось что-то типа (если не в лом, прочитайте комментарии – сразу все ясно станет):

#include «stdafx.h»
#include «version.h»
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// The one and only application object

CWinApp theApp;

using namespace std;

//Функция печатает синтаксис командной строки
void Usage()
{
//
Первый параметр — имя файла заголовка
//
Потом — название приложения
//
Номер версии (по умолчанию — 1.0.0.1)
std::cout<<"Usage: version header.h AppName [x.x.x.x]"< }

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
//
Если программе передано неверное количество параметров, показать синтаксис и выйти
if ((argc<3)||(argc>4))
{
Usage();
return -1;
}
//
Определить наличие файла заголовка
HANDLE hFile=CreateFile(argv[1],GENERIC_READ, 0,NULL, OPEN_EXISTING,0, NULL);
if (hFile==INVALID_HANDLE_VALUE)
{
//
Файла нет, создать новый
CFile file(argv[1], CFile::modeWrite|CFile::modeCreate);
CArchive arOut(&file,CArchive::store);
//
Добавить макрос APPNAME
CString sFormat;
sFormat.Format(«#define APPNAME \»%s\»\r\n»,argv[2]);
arOut.WriteString(sFormat);
//
Добавить макрос VERSION
//
Если не указан номер версии
if (argc==3)
//
Использовать версию по умолчанию
sFormat.Format(«#define VERSION \»%s\»\r\n»,»1.0.0.1″);
else
//
Использовать указанную версию
sFormat.Format(«#define VERSION \»%s\»\r\n»,argv[3]);
arOut.WriteString(sFormat);
//
добавить макрос BUILD
sFormat.Format(«#define BUILD \»%d\»\r\n»,1);
arOut.WriteString(sFormat);
//
Добавить макрос TIME
CTime time=CTime::GetCurrentTime();
sFormat.Format(«#define TIME \»%02d.%02d.%4d %02d:%02d:%02d\»»,
time.GetDay(),time.GetMonth(), time.GetYear(),time.GetHour(), time.GetMinute(),time.GetSecond());
arOut.WriteString(sFormat);
//
Закрыть файл
arOut.Close();
file.Close();
}
else
{
//
Файл существует
//
Прочитать и разобрать его
CloseHandle(hFile);
CFile fileIn(argv[1],CFile::modeRead);
CArchive arIn(&fileIn,CArchive::load);
CString sLine;
//
Разобрать макрос APPNAME
arIn.ReadString(sLine);
int i=0;
sLine.Tokenize(«\»»,i);
CString sAppName=sLine.Tokenize(«\»»,i);

//Разобрать макрос VERSION 
arIn.ReadString(sLine);
i=0;
sLine.Tokenize(«\»»,i);
int nVersion1=atoi(sLine.Tokenize(«.»,i));
int nVersion2=atoi(sLine.Tokenize(«.»,i));
int nVersion3=atoi(sLine.Tokenize(«.»,i));
int nVersion4=atoi(sLine.Tokenize(«\»»,i));

//Разобрать макрос BUILD 
arIn.ReadString(sLine);
i=0;
sLine.Tokenize(«\»»,i);
int nBuild=atoi(sLine.Tokenize(«\»»,i));

//Теперь обработка — увеличим номер билда
//
И младший номер версии

nVersion4++;
nBuild++;
//
Переоткроем файл на запись
arIn.Close();
fileIn.Close();

//И запишем то, что получилось в результате
CFile file(argv[1], CFile::modeWrite|CFile::modeCreate);
CArchive arOut(&file,CArchive::store);
CString sFormat;
//
Макрос APPNAME
sFormat.Format(«#define APPNAME \»%s\»\r\n»,argv[2]);
arOut.WriteString(sFormat);
//
Макрос VERSION
sFormat.Format(«#define VERSION \»%d.%d.%d.%d\»\r\n»,
nVersion1, nVersion2, nVersion3, nVersion4);
arOut.WriteString(sFormat);
//
Макрос BUILD
sFormat.Format(«#define BUILD \»%d\»\r\n»,nBuild); 
arOut.WriteString(sFormat);
//
Макрос TIME
CTime time=CTime::GetCurrentTime();
sFormat.Format(«#define TIME \»%02d.%02d.%4d %02d:%02d:%02d\»»,time.GetDay(),
time.GetMonth(),time.GetYear(), time.GetHour(),time.GetMinute(),
time.GetSecond());
arOut.WriteString(sFormat);
//
Закроем файл
arOut.Close();
file.Close();
}
}

Компилируем, полученный файл version.exe (9728 байт у меня) кладем в папку с бинарниками Visual Studio (у меня C:\Program Files\Microsoft Visual Studio.NET
2003\Vc7\bin). Теперь посмотрим как использовать эту вещь. Создаем новый проект, к примеру под названием test, Console application, поддержку ATL и MFC не надо. VS генерит файл типа

#include «stdafx.h»

int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}

Подписываем под stdafx.h что-то типа #include “versioninfo.h” и в свойствах проекта Build Events/Pre-Build Event/Command Line пишем version versioninfo.h Megacooltest. Теперь в теле функции _tmain пишем что-то типа 
std::cout<  
#include «stdafx.h»
#include «versioninfo.h»

int _tmain(int argc, _TCHAR* argv[])
{
std::cout< }

Компилируем, запускаем:

D:\andrew\Projects\test1\Debug>test1
Megacooltest Version 1.0.0.1 Build 1 compiled 07.09.2004 14:08:53

А теперь компилируем еще раз и опять запускаем, только выберем Rebuild solution, иначе VS подумает, что раз ничего не изменилось, то и делать ничего не надо:

D:\andrew\Projects\test1\Debug>test1
Megacooltest Version 1.0.0.2 Build 2 compiled 07.09.2004 14:10:29

Вуаля! Теперь заказчик будет видеть сколько раз вы компилировали несчастную прогу пока добились результата. А еще он увидит во сколько времени несчастный программист
этого добился. Если надо сбросить номер билда, то просто сотрите файл versioninfo.h и он будет создан заново с номером билда 1. Или измените в файле versioninfo.h номер билда, и нумерация пойдет дальше с этого номера.

Описанное выше не есть руководство к действию, а скорее метод. Экспериментируйте, улучшайте, затачивайте под себя. К примеру, можно изменять номер версии как-то по другому, или добавить имя юзера, скомпилировавшего файл. В общем, много еще чего можно делать под нашу музыку (©Масяня). Удачи.

Оставить мнение

Check Also

Omega 2. Проверяем, на что способен крошечный и дешевый компьютер с Linux

В жизни каждого мейкера наступает момент, когда обычных микроконтроллеров уже не хватает, …