음...
[개요]
RAD2010 의 About화면에서 "Version Info ..." 버튼을 클릭하면
다음과 같은 화면을 볼수 있다.
이 "Version Infomation" 폼에는
현재 process(bds.exe) 에 Load된 dll 들의 이름과 경로 버젼을 표시해 주고 있다.
[어플에 VersionInfo의 필요성 ]
그렇지 않는 프로그램도 많이 있지만
어플자체에 현재 사용중인 모듈의 버젼을 보여주는 화면이 있는경우가 상당히 많이 있다.
현재 회사에서 프로그램을 개발할때
회사 자체에서 만든 모듈(라이브러리)를 1개에서 최대 6~7가지 씩 사용한다
프로그램에 문제가 발생했을때 정확히 배포버젼을 알려면
exe뿐만 아니라 각모듈의 버젼정보도 필요하다.
문론 모듈(exe나 dll 또는 bpl 등)의 버젼 정보를 Windows탐색기에서 확인이 가능하지만..
한두개도 아닌 여러개의 모듈으 버젼을 일일이 확인하기는 쉽지 않는 일이다.
그래서 한번 Process의 모듈을 보여주는 dialog를 만들어 보았다.
[file의 Version정보 가져오는 함수]
//---------------------------------------------------------------------------
//filename을 이용해 , Version정보 , 회사명 , 설명 등을 구해주는 함수
//---------------------------------------------------------------------------
void __fastcall GetModuleVersionInfo(AnsiString filename,AnsiString &sVer,AnsiString &sCompN,AnsiString &sFDesc)
{
sVer="";
sCompN="";
sFDesc="";
AnsiString sFileVersion; // Return 될 Version 정보.
DWORD dwHandle = 0, dwVersionInfoSize;
UINT uLength;
LPVOID pFileInfo, ptr;
dwVersionInfoSize = GetFileVersionInfoSize(filename.c_str(), &dwHandle);
if (dwVersionInfoSize < 2) return ; // 실행화일에 버젼 정보 표시가 되어 있지 않을 경우
pFileInfo = (LPVOID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwVersionInfoSize);
GetFileVersionInfo(filename.c_str(), dwHandle, dwVersionInfoSize, pFileInfo);
VerQueryValue(pFileInfo, TEXT("\\VarFileInfo\\Translation"), &ptr, &uLength);
WORD *id = (WORD*)ptr;
AnsiString szString;
szString = "\\StringFileInfo\\" + IntToHex(id[0], 4) + IntToHex(id[1], 4) + "\\ProductVersion";
VerQueryValue(pFileInfo, szString.c_str(), &ptr, &uLength);
sVer = (char*)ptr;
szString = "\\StringFileInfo\\" + IntToHex(id[0], 4) + IntToHex(id[1], 4) + "\\CompanyName";
VerQueryValue(pFileInfo, szString.c_str(), &ptr, &uLength);
sCompN = (char*)ptr;
szString = "\\StringFileInfo\\" + IntToHex(id[0], 4) + IntToHex(id[1], 4) + "\\FileDescription";
VerQueryValue(pFileInfo, szString.c_str(), &ptr, &uLength);
sFDesc = (char*)ptr;
HeapFree(GetProcessHeap(), 0, pFileInfo);
}
//---------------------------------------------------------------------------
[Process의 모듈 정보를 가져오는 함수]
//---------------------------------------------------------------------------
// process의 모듈 정보를 모두 읽어서 ListView에 뿌려준다.
//---------------------------------------------------------------------------
void __fastcall TForm1::ResetModuleInfo()
{
ListView1->Items->BeginUpdate();
ListView1->Items->Clear();
char buf[256]={0};
HINSTANCE MODList[1000];
HWND ph=(HWND )GetCurrentProcess();
AnsiString sVer,sCompN,sDesc;
unsigned long modNeeded=0;
if(!EnumProcessModules(ph,MODList, 1000, &modNeeded))return;
for(int i=0;i< (modNeeded / 4 );i++)
{
if(GetModuleFileNameExA(ph,MODList[i],buf,256)>0)
{
AnsiString sFName=buf;
TListItem *Item=ListView1->Items->Add();
Item->Caption=IntToStr(Item->Index+1);
Item->SubItems->Add(ExtractFileName(sFName));
GetModuleVersionInfo(sFName,sVer,sCompN,sDesc);
Item->SubItems->Add(sVer);
Item->SubItems->Add(sCompN);
Item->SubItems->Add(sDesc);
Item->SubItems->Add(sFName);
}
}
ListView1->Items->EndUpdate();
}
[사용은?]
//---------------------------------------------------------------------------
// 폼 Show이벤트에서 모듈정보를 Reset해준다.
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
ResetModuleInfo();
}
//---------------------------------------------------------------------------
// Copy버튼을 클릭하면 TSV로 Clipboard에 복사해준다.
//---------------------------------------------------------------------------
void __fastcall TForm1::B_CopyClick(TObject *Sender)
{
TStringList *pLst=new TStringList;
for(int i=0 ; i < ListView1->Items->Count ; i++)
{
TListItem *item=ListView1->Items->Item[i];
item->SubItems->Delimiter='\t';
item->SubItems->StrictDelimiter=true;
pLst->Add(item->SubItems->DelimitedText );
}
Clipboard()->AsText = pLst->Text;
delete pLst;
}
위와같이 모든 모듈을 다 화면에 뿌려주는 것도 좋지만
RadStudio 사용자는 BPL만 뿌려주는것도 괜찮을것 같다.
그럼..