펌) http://psmon.x-y.net/maniwiki/doku.php
기타 파일 버전 관련 소스) http://www.codeproject.com/KB/install/VerPatch.aspx
MSDN)
http://msdn.microsoft.com/en-us/library/ms647003.aspx :: GetFileVersionInfo
http://msdn.microsoft.com/en-us/library/ms647005(VS.85).aspx :: GetFileVersionInfoSize
http://msdn.microsoft.com/en-us/library/ms647464(VS.85).aspx :: VerQueryValue
http://msdn.microsoft.com/en-us/library/ms646997.aspx :: VS_FIXEDFILEINFO
http://msdn.microsoft.com/en-us/library/ms647001(VS.85).aspx :: VS_VERSIONINFO
#pragma once
#include <Version.h>
#pragma comment(lib,"version")
struct VS_VERSIONINFO
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[1];
WORD wPadding1[1];
VS_FIXEDFILEINFO Value;
WORD wPadding2[1];
WORD wChildren[1];
};
struct
{
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
struct Vs_info
{
DWORD high;
DWORD low;
};
void CreschangerDlg::SetVersionInfo(char *cfilename,char *cfileversion,char *cproductversion,char *ccomment)
{
UpdateData(TRUE);
PS_PRJINFO edit_one;
edit_one.exefullname = cfilename;
edit_one.fileversion=cfileversion;
edit_one.productversion=cproductversion;
edit_one.comment=ccomment;
edit_one.filename=m_strFileName.GetBuffer(0);
m_prj.EditPrj(&edit_one);
//버젼 유효성검사
if(false == validversiondata(PVER_FILEVERSION,cfileversion) )
{
MessageBox(m_verLastError);
return;
}
if(false == validversiondata(PVER_PRODUCTVERSION,cproductversion) )
{
MessageBox(m_verLastError);
return;
}
if(false == validversiondata(PVER_COMMENT,ccomment) )
{
MessageBox(m_verLastError);
return;
}
VS_VERSIONINFO *pVerInfo;
LPBYTE pOffsetBytes;
VS_FIXEDFILEINFO *pFixedInfo;
LPCTSTR lpszFile = _T(cfilename);
DWORD dwHandle, dwSize, dwResult = 0 ;
LPBYTE lpBuffer;
// determine the size of the resource information
dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);
if (0 < dwSize)
{
lpBuffer = new BYTE[dwSize];
memset(lpBuffer,0,dwSize);
if (GetFileVersionInfo(lpszFile, 0, dwSize, lpBuffer) != FALSE)
{
// these macros help to align on r-byte boundaries (thanks Ted Peck)
#define roundoffs(a,b,r) (((BYTE *) (b) - (BYTE *) (a) + ((r) - 1)) & ~((r) - 1))
#define roundpos(a,b,r) (((BYTE *) (a)) + roundoffs(a,b,r))
// 'point to' the start of the version information block
pVerInfo = (VS_VERSIONINFO *) lpBuffer;
// the fixed section starts right after the 'VS_VERSION_INFO' string
pOffsetBytes = (BYTE *) &pVerInfo->szKey[16];
//int x = _tcslen((char*)pVerInfo->szKey);
pFixedInfo = (VS_FIXEDFILEINFO *) roundpos(pVerInfo, pOffsetBytes, 4);
// increment the numbers!
int left = 0;
int right = 0;
left = GetDigtFromVerString(cfileversion,0);
right = GetDigtFromVerString(cfileversion,1);
pFixedInfo->dwFileVersionMS = (0x00010000 * left) + (0x00000001 * right);
left = GetDigtFromVerString(cfileversion,2);
right = GetDigtFromVerString(cfileversion,3);
pFixedInfo->dwFileVersionLS = (0x00010000 * left) + (0x00000001 * right);
left = GetDigtFromVerString(cproductversion,0);
right = GetDigtFromVerString(cproductversion,1);
pFixedInfo->dwProductVersionMS = (0x00010000 * left) + (0x00000001 * right);
left = GetDigtFromVerString(cproductversion,2);
right = GetDigtFromVerString(cproductversion,3);
pFixedInfo->dwProductVersionLS = (0x00010000 * left) + (0x00000001 * right);
LPVOID lpInfo;
UINT unInfoLen;
if (VerQueryValue(lpBuffer, _T("\\"), &lpInfo, &unInfoLen))
{
//ASSERT(unInfoLen == sizeof(m_FileInfo));
//if (unInfoLen == sizeof(m_FileInfo))
// memcpy(&m_FileInfo, lpInfo, unInfoLen);
}
// find best matching language and codepage
VerQueryValue(lpBuffer, _T("\\VarFileInfo\\Translation"), &lpInfo, &unInfoLen);
DWORD dwLangCode = 0;
if (GetTranslationId(lpInfo, unInfoLen, MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL), dwLangCode, TRUE))
dwLangCode = *((DWORD*)lpInfo);
if(dwLangCode < 1 )
{
MessageBox("영문버젼정보가 있질않습니다. 리소스의 국가설정을 확인하세요!");
delete [] lpBuffer;
return;
}
CString m_strProductName;
CString strSubBlock;
HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);
if (NULL != hResource)
{
UINT uTemp;
wchar_t tt[128];
char xx[128];
char* w_version;
w_version= new char[dwSize];
for(int i=0;i<dwSize;i++)
{
w_version[i] = lpBuffer[i];
}
bool is_lenok = true;
LPVOID p_fileVer;
memset(&tt[0],0,sizeof(wchar_t) * 128 );
p_fileVer = SearchText(w_version,"FileVersion",dwSize);
strcpy(xx,cfileversion);
for(int i=0;i<strlen(xx);i++)
{
tt[i]=std::wcout.widen(xx[i]);
}
strSubBlock.Format(_T("\\StringFileInfo\\%04X%04X\\FileVersion"), dwLangCode&0x0000FFFF, (dwLangCode&0xFFFF0000)>>16);
if (VerQueryValue(lpBuffer, (LPTSTR)(LPCTSTR)(strSubBlock), (LPVOID *) &pValueBuffer, &unInfoLen))
{
m_strProductName = CString((LPCTSTR)pValueBuffer);
if(strlen(xx) <= m_strProductName.GetLength())
{
ZeroMemory(p_fileVer, m_strProductName.GetLength() * sizeof(wchar_t));
wcscpy((wchar_t*)p_fileVer, &tt[0] );
}
else
{
is_lenok =false;
}
}
else
{
is_lenok =false;
}
memset(&tt[0],0,sizeof(wchar_t) * 128 );
p_fileVer = SearchText(w_version,"ProductVersion",dwSize);
strcpy(xx,cproductversion);
for(int i=0;i<strlen(xx);i++)
{
tt[i]=std::wcout.widen(xx[i]);
}
strSubBlock.Format(_T("\\StringFileInfo\\%04X%04X\\ProductVersion"), dwLangCode&0x0000FFFF, (dwLangCode&0xFFFF0000)>>16);
if (VerQueryValue(lpBuffer, (LPTSTR)(LPCTSTR)(strSubBlock), (LPVOID *) &pValueBuffer, &unInfoLen))
{
m_strProductName = CString((LPCTSTR)pValueBuffer);
if(strlen(xx) <= m_strProductName.GetLength())
{
ZeroMemory(p_fileVer, m_strProductName.GetLength() * sizeof(wchar_t));
wcscpy((wchar_t*)p_fileVer, &tt[0] );
}
else
{
is_lenok =false;
}
}
else
{
is_lenok =false;
}
memset(&tt[0],0,sizeof(wchar_t) * 128 );
p_fileVer = SearchText(w_version,"Comments",dwSize);
strcpy(xx,ccomment);
for(int i=0;i<strlen(xx);i++)
{
tt[i]=std::wcout.widen(xx[i]);
}
strSubBlock.Format(_T("\\StringFileInfo\\%04X%04X\\Comments"), dwLangCode&0x0000FFFF, (dwLangCode&0xFFFF0000)>>16);
if (VerQueryValue(lpBuffer, (LPTSTR)(LPCTSTR)(strSubBlock), (LPVOID *) &pValueBuffer, &unInfoLen))
{
m_strProductName = CString((LPCTSTR)pValueBuffer);
if(strlen(xx) <= m_strProductName.GetLength())
{
ZeroMemory(p_fileVer, m_strProductName.GetLength() * sizeof(wchar_t));
wcscpy((wchar_t*)p_fileVer, &tt[0] );
}
else
{
is_lenok =false;
}
}
else
{
is_lenok =false;
}
memcpy(lpBuffer,w_version,dwSize);
delete [] w_version;
if(!is_lenok)
{
delete [] lpBuffer;
MessageBox("바꾸려는 버젼정보문자열이, Original버젼의 문자열길이를 초과하거나 없습니다..");
return;
}
// could probably just use LANG_NEUTRAL/SUBLANG_NEUTRAL
if (UpdateResource(hResource, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), dwLangCode&0x0000FFFF, lpBuffer, dwSize) != FALSE)
{
// 언어한글 강제..업데이트
//UpdateResource(hResource, RT_VERSION, MAKEINTRESOURCE(VS_VERSION_INFO), 1042, lpBuffer, dwSize);
if (EndUpdateResource(hResource, FALSE) == FALSE)
dwResult = GetLastError();
}
else
dwResult = GetLastError();
}
else
dwResult = GetLastError();
delete [] lpBuffer;
}
else
{
dwResult = GetLastError();
delete [] lpBuffer;
}
}
else
dwResult = GetLastError();
if(dwResult != 0)
{
sprintf(m_verLastError,"VerChanger Failed Reason:%d",dwResult);
MessageBox(m_verLastError);
}
else
{
MessageBox("버젼업이 성공했습니다.");
}
}
BOOL CreschangerDlg::GetTranslationId(LPVOID lpData, UINT unBlockSize, WORD wLangId, DWORD &dwId, BOOL bPrimaryEnough/*= FALSE*/)
{
for (LPWORD lpwData = (LPWORD)lpData; (LPBYTE)lpwData < ((LPBYTE)lpData)+unBlockSize; lpwData+=2)
{
if (*lpwData == wLangId)
{
dwId = *((DWORD*)lpwData);
return TRUE;
}
}
if (!bPrimaryEnough)
return FALSE;
for (lpwData = (LPWORD)lpData; (LPBYTE)lpwData < ((LPBYTE)lpData)+unBlockSize; lpwData+=2)
{
if (((*lpwData)&0x00FF) == (wLangId&0x00FF))
{
dwId = *((DWORD*)lpwData);
return TRUE;
}
}
return FALSE;
}
LPVOID CreschangerDlg::SearchText(char* Search,char* findstring,int maxlen)
{
int comlen = strlen(findstring);
bool b_ser=false;
int comcount=0;
for(int i=0;i<maxlen ; i++)
{
comcount=0;
for(int x=0;x<comlen;x++)
{
char cur = Search[i];
if(cur == findstring[x])
{
comcount++;
i = i + 2;
}
else
{
break;
}
if(comcount == comlen)
{
int xxx=999;
if(0 ==strcmp("ProductVersion",findstring))
{
return (LPVOID)(&Search[i+2]);
}
if(0 == strcmp("Comments",findstring))
{
return (LPVOID)(&Search[i+2]);
}
return (LPVOID)(&Search[i+4]);
}
}
}
return NULL;
}
bool CreschangerDlg::validversiondata(int ntype,char* verstring)
{
int i_verlen = strlen(verstring);
if( (COMMENT_MAX < i_verlen) && (i_verlen < 1) )
{
strcpy(m_verLastError,"Comment의 Rev이 지정된 길이를 초과했거나, 1보다 작습니다.");
return false;
}
if(ntype == PVER_COMMENT)
{
strcpy(m_verLastError,"Comment의 유효성 통과");
return true;
}
if( VERSION_MAX < i_verlen)
{
strcpy(m_verLastError,"Version정보가 제한된 길이를 초과했습니다.");
return false;
}
int comCount = 0;
for(int i=0 ;i<i_verlen;i++)
{
// ,의 개수를 카운팅한다.
if(verstring[i] == ',' || verstring[i] == '.')
{
if(i > 0)
{
if(verstring[i-1] == ',' || verstring[i-1] == '.')
{
strcpy(m_verLastError,"버젼 구분자사이에 값이 없습니다.");
return false;
}
}
comCount++;
continue;
}
//버젼정보에 해당하는 문자열값이 숫자인지 체크
if( (NUM_START < verstring[i]) && (NUM_END > verstring[i]) )
{
}
else
{
strcpy(m_verLastError,"Version정보에 ,를 제외한 문자가 들어올수 없습니다.");
return false;
}
}
if(COMA_COUNT != comCount )
{
strcpy(m_verLastError,"Version정보에 ,의 카운트는 3이어야합니다.");
return false;
}
strcpy(m_verLastError,"Version정보 유효성 통과");
return true;
}