You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1912 lines
61 KiB
1912 lines
61 KiB
/*****************************************************************************
|
|
|
|
Copyright (c) 2001, Microsoft Corporation All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
cmf.cpp
|
|
|
|
Abstract:
|
|
|
|
The implementation of CCompactMUIFile, CMUIFile
|
|
|
|
Revision History:
|
|
|
|
2001-11-01 sunggch created.
|
|
|
|
Revision.
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
#include "muirct.h"
|
|
#include "res.h"
|
|
#include "cmf.h"
|
|
|
|
|
|
#define DWORD_ALIGNMENT(dwValue) ( (dwValue+3) & ~3 )
|
|
|
|
#define TEMP_BUFFER 300
|
|
#define MUI_COMPACT L"CMF"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CCompactMUIFile Implementation
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CCompactMUIFile::CCompactMUIFile()
|
|
{
|
|
m_upCMFHeader.dwSignature = 0x1a1b;
|
|
m_upCMFHeader.dwHeaderSize = sizeof(UP_COMPACT_MUI_RESOURCE);
|
|
m_upCMFHeader.dwNumberofMui = 0;
|
|
|
|
m_pcmui = new CMUIFile;
|
|
if(!m_pcmui)
|
|
return;
|
|
|
|
m_strFileName = new TCHAR[MAX_FILENAME_LENGTH];
|
|
if(!m_strFileName)
|
|
return;
|
|
|
|
m_dwFileSize = m_upCMFHeader.dwHeaderSize;
|
|
|
|
}
|
|
|
|
CCompactMUIFile::CCompactMUIFile( CCompactMUIFile & ccmf)
|
|
{
|
|
m_hCMFFile = ccmf.m_hCMFFile;
|
|
m_upCMFHeader = ccmf.m_upCMFHeader;
|
|
m_pcmui = ccmf.m_pcmui;
|
|
m_strFileName = ccmf.m_strFileName;
|
|
|
|
}
|
|
|
|
CCompactMUIFile::~CCompactMUIFile()
|
|
{
|
|
if (m_strFileName)
|
|
delete []m_strFileName;
|
|
|
|
if (m_pcmui)
|
|
delete m_pcmui;
|
|
}
|
|
|
|
CCompactMUIFile & CCompactMUIFile::operator= (CCompactMUIFile & ccmf)
|
|
{
|
|
if(&ccmf == this)
|
|
return *this;
|
|
|
|
m_upCMFHeader = ccmf.m_upCMFHeader;
|
|
m_pcmui = ccmf.m_pcmui;
|
|
m_strFileName = ccmf.m_strFileName;
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
BOOL CCompactMUIFile::Create (LPCTSTR pszCMFFileName, PSTR * ppszMuiFiles, DWORD dwNumOfMUIFiles )
|
|
/*++
|
|
Abstract:
|
|
this is main creation part of CMF Files, we simply call CMUIFile::Create with each indivisual
|
|
mui file into specified CMF file.
|
|
|
|
Arguments:
|
|
pszCMFFileName - CMF file name
|
|
ppszMuiFiles - MUI files name array
|
|
dwNumOfMUIFiles - the number of MUI files, it is important to avoid adding "CMF" section into
|
|
DLL several times when this function is called from Adding MUI file to existing CMF file.
|
|
|
|
return:
|
|
true/false
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Loading MUI files and fill the headers and create CMFFile with this information.
|
|
// calling LoadAllMui [public]
|
|
//
|
|
if ( pszCMFFileName == NULL || ppszMuiFiles == NULL || * ppszMuiFiles == NULL)
|
|
return FALSE;
|
|
//
|
|
// sec; CreateFile (ascii version) only handle MAX_PATH for file name.
|
|
//
|
|
m_hCMFFile = CreateFile(pszCMFFileName, GENERIC_WRITE | GENERIC_READ, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
|
|
|
|
if ( INVALID_HANDLE_VALUE == m_hCMFFile)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::Create"),_T("Failure of CreateFile()"));
|
|
return FALSE;
|
|
}
|
|
// just in case, user want to use path for cmf file name. this value will be
|
|
// store in updated langNeu file.
|
|
|
|
LPCSTR pszFileName = m_pcmui->GetFileNameFromPath(pszCMFFileName);
|
|
|
|
if (strlen (pszFileName)+1 > MAX_FILENAME_LENGTH )
|
|
return FALSE; // overflow.
|
|
|
|
// strncpy(m_strFileName, pszFileName, strlen(pszFileName));
|
|
PTSTR * ppszDestEnd = NULL;
|
|
size_t * pbRem = NULL;
|
|
HRESULT hr;
|
|
hr = StringCchCopyEx(m_strFileName, MAX_FILENAME_LENGTH, pszFileName, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
|
|
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
return FALSE;
|
|
}
|
|
|
|
return LoadAllMui(ppszMuiFiles, dwNumOfMUIFiles);
|
|
|
|
}
|
|
|
|
|
|
BOOL CCompactMUIFile::Create( LPCTSTR pszCMFFileName )
|
|
/*++
|
|
Abstract:
|
|
simpley create CMFFile and set the handle member data.
|
|
|
|
Arguments:
|
|
pszCMFFileName - CMF file name
|
|
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
|
|
if (pszCMFFileName == NULL)
|
|
return FALSE;
|
|
|
|
m_hCMFFile = CreateFile(pszCMFFileName, GENERIC_WRITE | GENERIC_READ, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
|
|
// Can't use file mapping. we don't know the file size be created after all operation.
|
|
if ( INVALID_HANDLE_VALUE == m_hCMFFile)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::Create"),_T("Failure of CreateFile()") );
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
typedef struct _tagCOMPACT_MUI {
|
|
WORD wHeaderSize; // COMPACT_MUI size // [WORD]
|
|
DWORD dwFileVersionMS; // [DWORD * 2 ] /major version, minor version.
|
|
DWORD dwFileVersionLS;
|
|
BYTE Checksum[16]; // [DWORD * 4 ] MD5 checksum
|
|
WORD wReserved; // [DWORD ]
|
|
ULONG_PTR ulpOffset; //Offset to mui resource of this from COMPACT_MUI_RESOURCE signature. [DWORD]
|
|
DWORD dwFileSize;
|
|
WORD wFileNameLenWPad; // file name lenght + padding;
|
|
WCHAR wstrFieName[MAX_FILENAME_LENGTH]; // [WCHAR]
|
|
// WORD wPadding[1]; // [WORD] // does not calcualte in the tools, but shall be
|
|
// included specfication.
|
|
}COMPACT_MUI, *PCOMPACT_MUI;
|
|
|
|
|
|
|
|
BOOL CCompactMUIFile::OpenCMFWithMUI(LPCTSTR pszCMFFile)
|
|
/*++
|
|
Abstract:
|
|
Loading MUI files and fill the headers and create CMFFile with this information.
|
|
calling LoadAllMui [public]
|
|
|
|
Arguments:
|
|
pszCMFFile - CMF file name
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PSTR pszCMFBuffer = NULL;
|
|
|
|
if (pszCMFFile == NULL)
|
|
goto exit;
|
|
|
|
m_hCMFFile = CreateFile(pszCMFFile, GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
|
|
|
|
if ( INVALID_HANDLE_VALUE == m_hCMFFile)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of CreateFile()"));
|
|
goto exit;
|
|
}
|
|
//
|
|
// Loading CMF and MUI files inside, fill the header of CMF, MUI.
|
|
//
|
|
|
|
LPCSTR pszFileName = m_pcmui->GetFileNameFromPath(pszCMFFile);
|
|
|
|
if (strlen (pszFileName)+1 > MAX_FILENAME_LENGTH )
|
|
goto exit; // overflow.
|
|
|
|
strncpy(m_strFileName, pszFileName, strlen(pszFileName)+1 );
|
|
|
|
DWORD dwFileSize = GetFileSize(m_hCMFFile, NULL);
|
|
|
|
if( dwFileSize == INVALID_FILE_SIZE)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of GetFileSize()"));
|
|
goto exit;
|
|
}
|
|
|
|
pszCMFBuffer = new CHAR[dwFileSize]; // use char for possible byte operation of locating mui data.
|
|
|
|
if(!pszCMFBuffer)
|
|
goto exit;
|
|
|
|
DWORD dwWritten;
|
|
|
|
if(! ReadFile(m_hCMFFile, pszCMFBuffer, dwFileSize, &dwWritten, NULL))
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of read file"));
|
|
goto exit;
|
|
}
|
|
|
|
m_dwFileSize = GetFileSize(m_hCMFFile, NULL);
|
|
|
|
if( m_dwFileSize == INVALID_FILE_SIZE)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of GetFileSize()"));
|
|
goto exit;
|
|
}
|
|
|
|
m_upCMFHeader = *(UP_COMPACT_MUI_RESOURCE* ) pszCMFBuffer;
|
|
|
|
//
|
|
// Retrieve the each MUI header and files and fill the data to new CMUIFile.
|
|
//
|
|
|
|
|
|
DWORD dwUpCMFHeaderSize = sizeof UP_COMPACT_MUI_RESOURCE;
|
|
|
|
for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i ++ )
|
|
{
|
|
CMUIFile *pcmui = new CMUIFile();
|
|
|
|
// pc = (COMPACT_MUI*)((PBYTE)pszCMFBuffer + wUpCMFHeaderSize);
|
|
PCOMPACT_MUI pcm = NULL;
|
|
|
|
pcm = (PCOMPACT_MUI)((PBYTE)pszCMFBuffer + dwUpCMFHeaderSize);
|
|
// Copy the MUI header
|
|
memcpy((PVOID)(&pcmui->m_MUIHeader), (PVOID)pcm, pcm->wHeaderSize );
|
|
|
|
dwUpCMFHeaderSize += pcmui->m_MUIHeader.wHeaderSize;
|
|
// Copy the MUI image, because we are going to close file handle of ReadFile.
|
|
pcmui->m_pbImageBase = new TBYTE[pcmui->m_MUIHeader.dwFileSize]; // will be delete in destructor.
|
|
|
|
memcpy(pcmui->m_pbImageBase, (PBYTE)pszCMFBuffer + pcmui->m_MUIHeader.ulpOffset,
|
|
pcmui->m_MUIHeader.dwFileSize);
|
|
|
|
if(WideCharToMultiByte(CP_ACP, NULL, pcmui->m_MUIHeader.wstrFieName, wcslen(pcmui->m_MUIHeader.wstrFieName)+1,
|
|
pcmui->m_strFileName, wcslen(pcmui->m_MUIHeader.wstrFieName)+1, NULL, NULL) == 0) // REVISIT; Does MUI header include its filename for updating case.
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of WideCharToMultiByte()"));
|
|
delete pcmui;
|
|
goto exit;
|
|
}
|
|
|
|
pcmui->m_dwIndex = i;
|
|
|
|
m_pcvector.Push_back(pcmui);
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
exit:
|
|
if (pszCMFBuffer)
|
|
delete [] pszCMFBuffer;
|
|
|
|
if (m_hCMFFile)
|
|
CloseHandle(m_hCMFFile);
|
|
|
|
m_hCMFFile = NULL; // It still has value although it's freed, so we need to set it NULL.
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL CCompactMUIFile::LoadAllMui (PSTR *ppszMuiFiles, DWORD dwNumberofMuiFile)
|
|
/*++
|
|
Abstract:
|
|
Load MUI files and create/initialze CMUIFile with these loaded MUI file information.
|
|
|
|
Arguments:
|
|
ppszMuiFiles - MUI files array.
|
|
|
|
return:
|
|
dwNumberofMuiFile - Number of MUI files in the array.
|
|
--*/
|
|
{
|
|
//
|
|
// 1. Use FileMapping 2.
|
|
//
|
|
if (ppszMuiFiles == NULL)
|
|
return FALSE;
|
|
|
|
for (UINT i = 0; i < dwNumberofMuiFile; i++)
|
|
{
|
|
PSTR pszMUIFile = ppszMuiFiles[i];
|
|
if (pszMUIFile == NULL)
|
|
return FALSE;
|
|
|
|
CMUIFile *pcmui = new CMUIFile;
|
|
|
|
if(!pcmui)
|
|
return FALSE;
|
|
|
|
if (! pcmui->Create(pszMUIFile))
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::LoadAllMui"),_T("Failure of CMUIFile::Create") );
|
|
delete pcmui;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Add to the list.
|
|
//
|
|
|
|
m_upCMFHeader.dwHeaderSize += pcmui->m_MUIHeader.wHeaderSize;
|
|
m_upCMFHeader.dwNumberofMui++;
|
|
m_dwFileSize += pcmui->m_MUIHeader.wHeaderSize + pcmui->m_MUIHeader.dwFileSize;
|
|
// Add dwFileSize to the strucuture for sanity check inside Loader.
|
|
m_upCMFHeader.dwFileSize = m_dwFileSize;
|
|
pcmui->m_dwIndex = (WORD)i;
|
|
m_pcvector.Push_back(pcmui);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
// REVIST; adjust m_upCMFHeader.wHeaderSize as DWORD aligned.
|
|
}
|
|
|
|
|
|
// #define USE_WRITEFILE
|
|
BOOL CCompactMUIFile::WriteCMFFile()
|
|
/*++
|
|
Abstract:
|
|
Write a COMPACT_MUI_RESOURCE, COMPACT_MUI, MUI image files;
|
|
we need to fill the offset data in COMPACT_MUI header for each files.
|
|
|
|
Arguments:
|
|
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
//
|
|
// Write the file to real file.
|
|
//
|
|
|
|
if (! m_hCMFFile)
|
|
{
|
|
m_hCMFFile = CreateFile(m_strFileName, GENERIC_WRITE | GENERIC_READ, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
|
|
|
|
if ( INVALID_HANDLE_VALUE == m_hCMFFile)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile"),_T("Failure of CreateFile()"));
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
#ifndef USE_WRITEFILE
|
|
HANDLE hFileMapping = CreateFileMapping(m_hCMFFile, NULL, PAGE_READWRITE, NULL, m_dwFileSize, NULL);
|
|
|
|
if (hFileMapping == NULL)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile"),_T("Failure of CreateFileMapping()"));
|
|
_tprintf(_T("GetLastError : %d\n"), GetLastError());
|
|
return FALSE;
|
|
}
|
|
PVOID pCMFImageBase = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, NULL, NULL, NULL);
|
|
if (pCMFImageBase == NULL)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile"),_T("Failure of MapViewOfFile()"));
|
|
_tprintf(_T("GetLastError : %d\n"), GetLastError());
|
|
return FALSE;
|
|
|
|
}
|
|
DWORD dwTempImageBase = (DWORD)PtrToUlong(pCMFImageBase);
|
|
CloseHandle(hFileMapping);
|
|
|
|
//
|
|
// write offset to each MUI header.
|
|
//
|
|
DWORD dwUpCMFHeaderSize = m_upCMFHeader.dwHeaderSize;
|
|
|
|
DWORD_ALIGNMENT(dwUpCMFHeaderSize); // All MUI headers are already DWORD aligned.
|
|
|
|
memcpy(pCMFImageBase, (PVOID)&m_upCMFHeader, sizeof(UP_COMPACT_MUI_RESOURCE));
|
|
|
|
DWORD dwLowOffset = sizeof(UP_COMPACT_MUI_RESOURCE);
|
|
|
|
for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i++)
|
|
{
|
|
CMUIFile *pcmui = (CMUIFile *)m_pcvector.GetValue(i);
|
|
|
|
pcmui->m_MUIHeader.ulpOffset = dwUpCMFHeaderSize; // + header size. header size should be DWORD in Create()
|
|
|
|
dwUpCMFHeaderSize += pcmui->m_MUIHeader.dwFileSize; // + File size is next file offset
|
|
|
|
DWORD_ALIGNMENT(dwUpCMFHeaderSize); // need to adjust for DWORD.
|
|
// writing MUI header
|
|
memcpy((PBYTE)pCMFImageBase + dwLowOffset, (PVOID)&pcmui->m_MUIHeader, pcmui->m_MUIHeader.wHeaderSize);
|
|
|
|
dwLowOffset += pcmui->m_MUIHeader.wHeaderSize; // do not DWORD align.
|
|
|
|
// writing MUI image
|
|
|
|
memcpy((PBYTE)pCMFImageBase + pcmui->m_MUIHeader.ulpOffset, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize);
|
|
|
|
UnmapViewOfFile(pcmui->m_pbImageBase); // unmap MUI file at last.
|
|
};
|
|
|
|
if (! FlushViewOfFile(pCMFImageBase, NULL) )
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of FlushViewOfFile()") );
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
UnmapViewOfFile(pCMFImageBase);
|
|
|
|
#else
|
|
//
|
|
// Using WriteFile.
|
|
// create two buffer. 1. header part 2. data part. we fill this buffer with data, then
|
|
// write these buffer; we can save time by reducing I/O
|
|
//
|
|
|
|
PBYTE pCMFImageBase = (PBYTE)LocalAlloc(LMEM_ZEROINIT, m_dwFileSize);
|
|
|
|
if (pCMFImageBase == NULL)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of LocalAlloc()") );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// write offset to each MUI header.
|
|
//
|
|
DWORD dwUpCMFHeaderSize = m_upCMFHeader.dwHeaderSize;
|
|
|
|
DWORD_ALIGNMENT(dwUpCMFHeaderSize); // All MUI headers are already DWORD aligned.
|
|
|
|
memcpy(pCMFImageBase, (PVOID)&m_upCMFHeader, sizeof(UP_COMPACT_MUI_RESOURCE));
|
|
|
|
DWORD dwLowOffset = sizeof(UP_COMPACT_MUI_RESOURCE);
|
|
|
|
for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i++)
|
|
{
|
|
CMUIFile *pcmui = (CMUIFile *)m_pcvector.GetValue(i);
|
|
|
|
pcmui->m_MUIHeader.ulpOffset = wUpCMFHeaderSize; // + header size. header size should be DWORD in Create()
|
|
|
|
dwUpCMFHeaderSize += pcmui->m_MUIHeader.dwFileSize; // + File size is next file offset
|
|
|
|
DWORD_ALIGNMENT(dwUpCMFHeaderSize); // need to adjust for DWORD.
|
|
// writing MUI header
|
|
memcpy((PBYTE)pCMFImageBase + dwLowOffset, (PVOID)&pcmui->m_MUIHeader, pcmui->m_MUIHeader.wHeaderSize);
|
|
|
|
dwLowOffset += pcmui->m_MUIHeader.wHeaderSize; // do not DWORD align.
|
|
|
|
// writing MUI image
|
|
|
|
memcpy((PBYTE)pCMFImageBase + pcmui->m_MUIHeader.ulpOffset, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize);
|
|
|
|
UnmapViewOfFile(pcmui->m_pbImageBase); // unmap MUI file at last.
|
|
};
|
|
|
|
DWORD dwWritten;
|
|
if (!WriteFile(m_hCMFFile, pCMFImageBase, m_dwFileSize, &dwWritten, NULL))
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of WriteFile()") );
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
CloseHandle(m_hCMFFile);
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
#ifdef VARIALBE_MUI_STRUCTURE
|
|
|
|
BOOL CCompactMUIFile::WriteCMFFile()
|
|
/*++
|
|
Abstract:
|
|
Create mapped view of CMF file handle and write all information when MUI data structe is variable; MUI structure
|
|
would be variable if we dicide replace array of MUI file name with null terminated pointer.
|
|
currently, our structured can accomodate both of them. if we use null termated pointer, we can set file name size
|
|
for robust reason from client use.
|
|
|
|
Arguments:
|
|
|
|
|
|
return:
|
|
--*/
|
|
{
|
|
//
|
|
// Write the file to real file.
|
|
//
|
|
|
|
HANDLE hFileMapping = CreateFileMapping(m_hCMFFile, NULL, PAGE_READWRITE, NULL, NULL, NULL);
|
|
|
|
PVOID pCMFImageBase = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, NULL, NULL, NULL);
|
|
|
|
CloseHandle(hFileMapping);
|
|
|
|
//
|
|
// write offset to each MUI header.
|
|
//
|
|
DWORD dwUpCMFHeaderSize = m_upCMFHeader.dwHeaderSize;
|
|
|
|
// DWORD_ALIGNMENT(wUpCMFHeaderSize); All MUI headers are already DWORD aligned.
|
|
|
|
memcpy(pCMFImageBase, (PVOID)&m_upCMFHeader, sizeof(UP_COMPACT_MUI_RESOURCE));
|
|
|
|
DWORD dwLowOffset = sizeof(UP_COMPACT_MUI_RESOURCE);
|
|
|
|
for (UINT i = 0; i < m_upCMFHeader.dwNumberofMui; i++)
|
|
{
|
|
CMUIFile *pcmui = (CMUIFile *)m_pcvector->GetValue(i);
|
|
|
|
pcmui->m_MUIHeader.ulpOffset = dwUpCMFHeaderSize; // + header size
|
|
|
|
dwUpCMFHeaderSize += pcmui->m_MUIHeader.dwFileSize; // + File size is next file offset
|
|
|
|
DWORD_ALIGNMENT(dwUpCMFHeaderSize); // need to adjust for DWORD.
|
|
// writing MUI header
|
|
memcpy((PBYTE)pCMFImageBase + dwLowOffset, (PVOID)&pcmui->m_MUIHeader, pcmui->m_MUIHeader.wHeaderSize);
|
|
|
|
dwLowOffset += pcmui->m_MUIHeader.wHeaderSize; // do not DWORD align.
|
|
|
|
// writing MUI image
|
|
memcpy((PBYTE)pCMFImageBase + pcmui->m_MUIHeader.ulpOffset, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize);
|
|
|
|
};
|
|
|
|
if (! FlushViewOfFile(pCMFImageBase, NULL) )
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteCMFFile()"), _T("Failure of FlushViewOfFile()") );
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
UnmapViewOfFile(pCMFImageBase);
|
|
}
|
|
|
|
#endif
|
|
|
|
BOOL CCompactMUIFile::UpdateMuiFile( PSTR pszCMFFile, PSTR pszMuiFile)
|
|
{
|
|
// TBD
|
|
if ( pszCMFFile == NULL || pszMuiFile == NULL)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
//create CMUIFile and replace this data with same name inside //CMF file and fill new CMF file structure.
|
|
|
|
BOOL CCompactMUIFile::DisplayHeaders(PSTR pszCMFFile, WORD wLevel /*= NULL*/)
|
|
/*++
|
|
Abstract:
|
|
Dump CMF header information
|
|
|
|
Arguments:
|
|
pszCMFFile - CMF file
|
|
wLevel - dump level. not implemented yet.
|
|
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
if (pszCMFFile == NULL)
|
|
return FALSE;
|
|
|
|
if (OpenCMFWithMUI(pszCMFFile))
|
|
{
|
|
_tprintf(_T("\nCMF Headers %s\n"), pszCMFFile );
|
|
_tprintf(_T("------------------ ---------------- \n\n") );
|
|
|
|
_tprintf(_T("dwSignature :%16x \n"),m_upCMFHeader.dwSignature );
|
|
_tprintf(_T("dwHeaderSize :%16x \n"),m_upCMFHeader.dwHeaderSize );
|
|
_tprintf(_T("dwNumberofMui :%16x \n"),m_upCMFHeader.dwNumberofMui );
|
|
_tprintf(_T("dwFileSize :%16x \n\n\n"),m_upCMFHeader.dwFileSize );
|
|
|
|
for ( UINT i = 0; i < m_pcvector.Size(); i++)
|
|
{
|
|
CMUIFile *pcmui = m_pcvector.GetValue(i);
|
|
_tprintf(_T(" %d MUI Header \n"),i+1 );
|
|
_tprintf(_T("------------------ ---------------- \n\n") );
|
|
|
|
_tprintf(_T("wHeaderSize : %16x \n"),pcmui->m_MUIHeader.wHeaderSize );
|
|
_tprintf(_T("dwFileVersionMS : %16x \n"),pcmui->m_MUIHeader.dwFileVersionMS );
|
|
_tprintf(_T("dwFileVersionLS : %16x \n"),pcmui->m_MUIHeader.dwFileVersionLS );
|
|
_tprintf(_T("Checksum : "));
|
|
for (UINT j=0; j < 16; j++){
|
|
_tprintf(_T("%x "),pcmui->m_MUIHeader.Checksum[j] );
|
|
}
|
|
_tprintf(_T("\n"));
|
|
_tprintf(_T("wReserved : %16x \n"),pcmui->m_MUIHeader.wReserved );
|
|
_tprintf(_T("ulpOffset : %16x \n"),pcmui->m_MUIHeader.ulpOffset );
|
|
_tprintf(_T("dwFileSize : %16x \n"),pcmui->m_MUIHeader.dwFileSize );
|
|
_tprintf(_T("wFileNameLenWPad : %16x \n"),pcmui->m_MUIHeader.wFileNameLenWPad );
|
|
_tprintf(_T("wstrFieName : %16S \n\n\n"),pcmui->m_MUIHeader.wstrFieName );
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CCompactMUIFile::AddFile (PSTR pszCMFFile, PSTR *pszAddedMuiFile, DWORD dwNumOfMUIFiles)
|
|
/*++
|
|
Abstract:
|
|
Add a new mui file into existing cmf file, it does not create new file yet,
|
|
it just add mui into cmf's mui tree.
|
|
|
|
Arguments:
|
|
pszAddedMuiFile : MUI fil be added.
|
|
pszCMFFile : existing CMF file
|
|
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
if ( pszCMFFile == NULL || pszAddedMuiFile == NULL)
|
|
return FALSE;
|
|
//
|
|
// Open CMF file with MUI files
|
|
//
|
|
|
|
if (! OpenCMFWithMUI(pszCMFFile))
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::AddFile"),_T("Failure of OpenCMFWithMUI(pszCMFFile)"),pszCMFFile );
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create a new CMUIfile on the based on new added mui file
|
|
//
|
|
for (UINT i =0; i < dwNumOfMUIFiles; i++)
|
|
{
|
|
CMUIFile *pcmui = new CMUIFile();
|
|
|
|
if (!pcmui )
|
|
return FALSE;
|
|
|
|
if (! pcmui->Create(pszAddedMuiFile[i]))
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::AddFile"),_T("Failure of CMUIFile::Create"),pszAddedMuiFile[i] );
|
|
delete pcmui;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Add to the list.
|
|
//
|
|
|
|
m_upCMFHeader.dwHeaderSize += pcmui->m_MUIHeader.wHeaderSize;
|
|
m_upCMFHeader.dwNumberofMui++;
|
|
m_dwFileSize += pcmui->m_MUIHeader.wHeaderSize + pcmui->m_MUIHeader.dwFileSize;
|
|
// Add dwFileSize to the strucuture for sanity check inside Loader.
|
|
m_upCMFHeader.dwFileSize = m_dwFileSize;
|
|
pcmui->m_dwIndex = m_upCMFHeader.dwNumberofMui - 1;
|
|
m_pcvector.Push_back(pcmui);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CCompactMUIFile::SubtractFile ( PSTR pszSubtractedMuiFile , PSTR pszCMFFile /*= NULL*/ )//elete from the list,and create file for that.
|
|
/*++
|
|
Abstract:
|
|
subtract mui file from the CMF file. NOT implemented yet.
|
|
|
|
Arguments:
|
|
pszSubtractedMuiFile - MUI file, which would be removed from CMF file
|
|
pszCMFFile - CMF file
|
|
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
if (pszSubtractedMuiFile == NULL)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// add new CMUI file into existing CMF file
|
|
BOOL CCompactMUIFile::UnCompactCMF (PSTR pszCMFFile)
|
|
/*++
|
|
Abstract:
|
|
Create each MUI file from CMF file.
|
|
|
|
Arguments:
|
|
pszCMFFile - CMF file
|
|
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
if (pszCMFFile == NULL)
|
|
return FALSE;
|
|
|
|
if (OpenCMFWithMUI(pszCMFFile))
|
|
{
|
|
for (UINT i = 0; i < m_pcvector.Size(); i++)
|
|
{
|
|
CMUIFile *pcmui = m_pcvector.GetValue(i);
|
|
|
|
if (! pcmui->WriteMUIFile(pcmui))
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::UnCompactCMF"), _T("Failure of CMUIFile::writeMUIFile()") );
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
// REVIST ; how about uddating a binary files.
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
void CCompactMUIFile::SubtractFile(CMUIFile* pcmui)
|
|
/*++
|
|
Abstract:
|
|
|
|
Arguments:
|
|
|
|
return:
|
|
--*/
|
|
{
|
|
// TBD
|
|
|
|
}
|
|
|
|
|
|
BOOL CCompactMUIFile::UpdateCodeFiles(PSTR pszCodeFilePath, DWORD dwNumbOfFiles)
|
|
/*++
|
|
Abstract:
|
|
This rotine will be called when -m(create new cmf file) and -a(add mui file into
|
|
existing cmf file). in the -a case, we don't have to (shouldn't) update code files
|
|
because it alreay updated(include CMF name). The updated files are added at the end
|
|
cmf files so we update files reversly.
|
|
|
|
Arguments:
|
|
pszCodeFilePath - DLL (parent of MUI file) path
|
|
dwNumbOfFiles - number of added MUI files. this is called as a function of CompactMUI in main function.
|
|
|
|
return:
|
|
true/false
|
|
--*/
|
|
{
|
|
|
|
PTSTR * ppszDestEnd = NULL;
|
|
size_t * pbRem = NULL;
|
|
HRESULT hr;
|
|
|
|
if (pszCodeFilePath == NULL)
|
|
return FALSE;
|
|
|
|
// Update files from the last item until number of files end.
|
|
UINT i =m_pcvector.Size()-1;
|
|
|
|
for (UINT j = 0 ; j < dwNumbOfFiles ; i --, j++ )
|
|
{ // create temp codefilepath.
|
|
|
|
CHAR szTempCodeFilePath[MAX_PATH]; // = {0};
|
|
|
|
// szTempCodeFilePath[sizeof(szTempCodeFilePath)-1] = '\0';
|
|
|
|
// strncpy(szTempCodeFilePath, pszCodeFilePath, strlen(pszCodeFilePath)+1);
|
|
|
|
hr = StringCchCopyExA(szTempCodeFilePath, MAX_PATH ,pszCodeFilePath, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
return FALSE;
|
|
}
|
|
// Get CMUIFile
|
|
CMUIFile *pcmui = m_pcvector.GetValue(i);
|
|
|
|
LPCTSTR pcstrMuiFile = pcmui->m_strFileName;
|
|
|
|
if ( pcstrMuiFile == NULL)
|
|
return FALSE;
|
|
|
|
// Get the file name without ".mui"
|
|
DWORD dwLen = strlen(pcstrMuiFile);
|
|
TCHAR szCodeFileName[MAX_PATH]={0}; // new is used when initializing class.
|
|
|
|
if (dwLen > MAX_PATH) {
|
|
return FALSE;
|
|
}
|
|
|
|
while ( dwLen )
|
|
{
|
|
if ( *(pcstrMuiFile + ( --dwLen )) == '.')
|
|
{
|
|
_tcsncpy(szCodeFileName, pcstrMuiFile, dwLen);
|
|
// pcstrMuiFile[dwLen] = _T('\0');
|
|
|
|
// StringCchCopyEx(szCodeFileName, MAX_PATH ,pcstrMuiFile, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
|
|
// memcpy(szCodeFileName, pcstrMuiFile, dwLen);
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (dwLen == 0)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::UpdateCodeFiles"), _T("MUI File name is not a file name format (*.*)") );
|
|
return FALSE;
|
|
|
|
}
|
|
//
|
|
// Check if target file exist in the directory.
|
|
//
|
|
|
|
WIN32_FIND_DATA w32fd;
|
|
|
|
//_tcsncat(szTempCodeFilePath, "\\", 2);
|
|
|
|
hr = StringCchCatEx(szTempCodeFilePath, MAX_PATH, _T("\\"), ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
|
|
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// _tcsncat(szTempCodeFilePath, szCodeFileName, _tcslen(szCodeFileName)+1);
|
|
hr = StringCchCatEx(szTempCodeFilePath, MAX_PATH, szCodeFileName, ppszDestEnd, pbRem,MUIRCT_STRSAFE_NULL);
|
|
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
return FALSE;
|
|
}
|
|
|
|
//if (FindFirstFile("dll\\np2.exe", &w32fd) == INVALID_HANDLE_VALUE)
|
|
if (FindFirstFile(szTempCodeFilePath, &w32fd) == INVALID_HANDLE_VALUE)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::UpdateCodeFiles"), _T("FindFirstFile fail"), szCodeFileName );
|
|
return FALSE;
|
|
}
|
|
|
|
// Adding "CMF xxx.cmf" inside Version info.
|
|
updateCodeFile(szTempCodeFilePath, pcmui->m_dwIndex);
|
|
|
|
// update checksum data inside update Code.
|
|
CMUIResource cmui; // :: UpdateNtHeader
|
|
|
|
cmui.UpdateNtHeader(szTempCodeFilePath, cmui.CHECKSUM);
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CCompactMUIFile::updateCodeFile(PSTR pszCodeFilePath, DWORD dwIndex)
|
|
/*++
|
|
Abstract:
|
|
update DLL (parent of MUI file)'s version resource by adding "CMF" section, which
|
|
contain CMF file and its index inside CMF file. the index can improve searching speed inside MUI loader.
|
|
|
|
Arguments:
|
|
pszCodeFilePath - DLL file path
|
|
dwIndex - index of MUI inside CMF file
|
|
|
|
return:
|
|
--*/
|
|
{
|
|
|
|
|
|
typedef struct VS_VERSIONINFO
|
|
{
|
|
USHORT TotalSize;
|
|
USHORT DataSize;
|
|
USHORT Type;
|
|
WCHAR szKey[16]; // L"VS_VERSION_INFO" + unicode null terminator
|
|
// Note that the previous 4 members has 16*2 + 3*2 = 38 bytes.
|
|
// So that compiler will silently add a 2 bytes padding to make
|
|
// FixedFileInfo to align in DWORD boundary.
|
|
VS_FIXEDFILEINFO FixedFileInfo;
|
|
} VS_VERSIONINFO,* PVS_VERSIONINFO;
|
|
|
|
// using the same structure in ldrrsrc.c because this is smart way to get the exact structuree location.
|
|
typedef struct tagVERBLOCK
|
|
{
|
|
USHORT wTotalLen;
|
|
USHORT wValueLen;
|
|
USHORT wType;
|
|
WCHAR szKey[1];
|
|
// BYTE[] padding
|
|
// WORD value;
|
|
} VERBLOCK;
|
|
|
|
// this is the structure in the muibld.exe.
|
|
typedef struct VAR_SRC_COMPACT
|
|
{
|
|
WORD wLength;
|
|
WORD wValueLength;
|
|
WORD wType;
|
|
WCHAR szCompactMui[4]; // For storing "CompactMui\0" null-terminated string in Unicode.
|
|
// DWORD dwIndex; //
|
|
// WCHAR szCompactFileName[32];
|
|
} VAR_SRC_COMPACT; //VAR_SRC_CHECKSUM;
|
|
|
|
if ( pszCodeFilePath == NULL)
|
|
return FALSE;
|
|
//
|
|
// Get VersionInfo structure.
|
|
//
|
|
DWORD dwHandle;
|
|
LPVOID lpVerRes = NULL;
|
|
CMUIResource * pcmuir = NULL;
|
|
|
|
DWORD dwVerSize = GetFileVersionInfoSize( (LPTSTR) pszCodeFilePath, &dwHandle);
|
|
|
|
lpVerRes = new CHAR[dwVerSize + TEMP_BUFFER];
|
|
|
|
if (!lpVerRes)
|
|
goto exit;
|
|
|
|
if ( ! GetFileVersionInfo((LPTSTR)pszCodeFilePath, 0 ,dwVerSize, lpVerRes) ) {
|
|
_tprintf(_T("Fail to get file version: GetLastError() : %d \n"),GetLastError() ) ;
|
|
goto exit;
|
|
}
|
|
|
|
PVS_VERSIONINFO pVersionInfo = (VS_VERSIONINFO *) lpVerRes;
|
|
|
|
WORD wResVerSize = pVersionInfo ->TotalSize;
|
|
|
|
WORD wNewResVerSize = wResVerSize; // + sizeof (VAR_SRC_COMPACT);
|
|
|
|
VERBLOCK * pVerBlock = NULL;
|
|
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//
|
|
// Adding checksum Resource data into inside VarFileInfo
|
|
//
|
|
if ( wResVerSize > 0 ) {
|
|
|
|
if ( wcscmp(pVersionInfo ->szKey,L"VS_VERSION_INFO") ) {
|
|
|
|
_tprintf(_T("This is not correct Version resource") );
|
|
|
|
goto exit;
|
|
}
|
|
|
|
WORD wBlockSize = (WORD)DWORD_ALIGNMENT ( sizeof (VS_VERSIONINFO) );
|
|
|
|
wResVerSize -= wBlockSize;
|
|
|
|
pVerBlock = (VERBLOCK *) ( pVersionInfo + 1 );
|
|
|
|
while ( wResVerSize > 0 ) {
|
|
|
|
if ( ! wcscmp(pVerBlock ->szKey,L"VarFileInfo") ) {
|
|
|
|
VERBLOCK * pVarVerBlock = pVerBlock;
|
|
|
|
WORD wVarFileSize = pVerBlock->wTotalLen;
|
|
|
|
wResVerSize -= wVarFileSize;
|
|
|
|
WORD wVarBlockSize = (WORD) DWORD_ALIGNMENT (sizeof(*pVerBlock) -1 + sizeof(L"VarFileInfo"));
|
|
|
|
wVarFileSize -= wVarBlockSize;
|
|
|
|
pVerBlock = (VERBLOCK *)((PBYTE) pVerBlock + wVarBlockSize );
|
|
|
|
while ((LONG)wVarFileSize > 0 ) {
|
|
|
|
if ( ! wcscmp(pVerBlock ->szKey,L"Translation") ) {
|
|
|
|
VAR_SRC_COMPACT * pVarSrcCompMui = (VAR_SRC_COMPACT *)new BYTE[TEMP_BUFFER];
|
|
// VAR_SRC_COMPACT * pVarSrcCompMui = new VAR_SRC_COMPACT;
|
|
if ( !pVarSrcCompMui) {
|
|
_tprintf(_T("Memory Insufficient error in CCompactMUIFile::updateCodeFile"));
|
|
goto exit;
|
|
}
|
|
|
|
wVarBlockSize = (WORD)DWORD_ALIGNMENT ( pVerBlock ->wTotalLen );
|
|
|
|
PBYTE pStartCompMui = (PBYTE) pVerBlock + wVarBlockSize ;
|
|
|
|
// Fill the structure.
|
|
pVarSrcCompMui->wLength = sizeof (VAR_SRC_COMPACT);
|
|
pVarSrcCompMui->wValueLength = (strlen(m_strFileName)+1) * sizeof WCHAR + sizeof DWORD;
|
|
pVarSrcCompMui->wType = 0;
|
|
// wcsncpy(pVarSrcCompMui->szCompactMui, MUI_COMPACT, 4 );
|
|
HRESULT hr;
|
|
hr = StringCchCopyW(pVarSrcCompMui->szCompactMui, sizeof (pVarSrcCompMui->szCompactMui)/ sizeof(WCHAR),
|
|
L"CMF");
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
delete [] pVarSrcCompMui;
|
|
goto exit;
|
|
}
|
|
pVarSrcCompMui->wLength = (WORD)DWORD_ALIGNMENT((BYTE)pVarSrcCompMui->wLength); // + sizeof (L"CompactMui"));
|
|
// Add DWORD wIndex
|
|
memcpy((PBYTE)pVarSrcCompMui + pVarSrcCompMui->wLength, &dwIndex, sizeof DWORD );
|
|
pVarSrcCompMui->wLength += sizeof DWORD;
|
|
// Add WCHAR Compact file name
|
|
WCHAR wstrFileName[MAX_FILENAME_LENGTH];
|
|
if (MultiByteToWideChar(CP_ACP, NULL, m_strFileName,
|
|
strlen(m_strFileName)+1, wstrFileName, MAX_FILENAME_LENGTH ) == 0)
|
|
{
|
|
_tprintf("Error happen in updateCodeFile: MultiByteToWideChar; GetLastError() : %d\n", GetLastError() );
|
|
delete [] pVarSrcCompMui;
|
|
goto exit;
|
|
}
|
|
memcpy((PBYTE)pVarSrcCompMui + pVarSrcCompMui->wLength, wstrFileName, (wcslen(wstrFileName)+1) * sizeof WCHAR );
|
|
pVarSrcCompMui->wLength += (wcslen(wstrFileName) + 1) * sizeof WCHAR;
|
|
pVarSrcCompMui->wLength = DWORD_ALIGNMENT(pVarSrcCompMui->wLength);
|
|
// memcpy(pStartCompMui,pVarSrcCompMui,sizeof(VAR_SRC_COMPACT) );
|
|
|
|
pVarVerBlock->wTotalLen += pVarSrcCompMui->wLength; // update length of VarFileInfo
|
|
wNewResVerSize += pVarSrcCompMui->wLength;
|
|
pVersionInfo ->TotalSize = wNewResVerSize;
|
|
|
|
wVarFileSize -= wVarBlockSize;
|
|
// pVerBlock = (VERBLOCK* ) ( (PBYTE) pVerBlock + pVarSrcCompMui->wLength );
|
|
// Push the any block in VarInfo after new inserted block "CompactMui"
|
|
if ( wVarFileSize ) {
|
|
|
|
PBYTE pPushedBlock = new BYTE[wVarFileSize ];
|
|
if (pPushedBlock) {
|
|
memcpy(pPushedBlock, pStartCompMui, wVarFileSize );
|
|
memcpy(pStartCompMui + pVarSrcCompMui->wLength, pPushedBlock ,wVarFileSize );
|
|
}
|
|
else
|
|
{
|
|
_tprintf(_T("Memory Insufficient error in CCompactMUIFile::updateCodeFile"));
|
|
|
|
}
|
|
delete [] pPushedBlock;
|
|
|
|
}
|
|
|
|
memcpy(pStartCompMui, pVarSrcCompMui, pVarSrcCompMui->wLength );
|
|
|
|
fSuccess = TRUE;
|
|
delete [] pVarSrcCompMui;
|
|
break;
|
|
}
|
|
wVarBlockSize = (WORD)DWORD_ALIGNMENT ( pVerBlock ->wTotalLen );
|
|
wVarFileSize -= wVarBlockSize;
|
|
pVerBlock = (VERBLOCK* ) ( (PBYTE) pVerBlock + wVarBlockSize );
|
|
} // while (wVarFileSize > 0 ) {
|
|
pVerBlock = (VERBLOCK* ) ( (PBYTE) pVarVerBlock->wTotalLen );
|
|
|
|
}
|
|
else {
|
|
wBlockSize = (WORD) DWORD_ALIGNMENT ( pVerBlock ->wTotalLen );
|
|
wResVerSize -= wBlockSize;
|
|
pVerBlock = (VERBLOCK * ) ( (PBYTE) pVerBlock + wBlockSize );
|
|
}
|
|
if (fSuccess)
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Update file by using UpdateResource function
|
|
//
|
|
|
|
BOOL fVersionExist = FALSE;
|
|
BOOL fUpdateSuccess = FALSE;
|
|
BOOL fEndUpdate = FALSE;
|
|
|
|
if ( fSuccess ) {
|
|
|
|
|
|
pcmuir = new CMUIResource(); //(pszNewFile);
|
|
|
|
if(!pcmuir)
|
|
goto exit;
|
|
|
|
if (! pcmuir -> Create(pszCodeFilePath) )
|
|
{ // load the file .
|
|
goto exit;
|
|
}
|
|
|
|
HANDLE hUpdate = ::BeginUpdateResource(pszCodeFilePath, FALSE );
|
|
|
|
if (hUpdate == NULL)
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
cvcstring * cvName = pcmuir->EnumResNames(MAKEINTRESOURCE(RT_VERSION),reinterpret_cast <LONG_PTR> (pcmuir) );
|
|
|
|
for (UINT j = 0; j < cvName->Size();j ++ ) {
|
|
|
|
cvword * cvLang = pcmuir->EnumResLangID(MAKEINTRESOURCE(RT_VERSION), cvName->GetValue(j), reinterpret_cast <LONG_PTR> (pcmuir) );
|
|
|
|
for (UINT k = 0; k < cvLang->Size();k ++ ) {
|
|
|
|
fUpdateSuccess = ::UpdateResource(hUpdate, MAKEINTRESOURCE(RT_VERSION),cvName->GetValue(j),cvLang->GetValue(k),lpVerRes,wNewResVerSize);
|
|
|
|
fVersionExist = TRUE;
|
|
}
|
|
}
|
|
|
|
pcmuir->FreeLibrary();
|
|
|
|
fEndUpdate = ::EndUpdateResource(hUpdate, FALSE);
|
|
|
|
CloseHandle(hUpdate);
|
|
}
|
|
else
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
if( ! fVersionExist ){
|
|
_tprintf(_T("no RT_VERSION type exist in the file %s \n"), pszCodeFilePath);
|
|
}
|
|
|
|
|
|
exit:
|
|
if(lpVerRes)
|
|
delete []lpVerRes;
|
|
if(pcmuir)
|
|
delete pcmuir;
|
|
|
|
return ( fEndUpdate & fVersionExist & fUpdateSuccess );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CMUIFile implementation
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
CMUIFile::CMUIFile()
|
|
{
|
|
m_MUIHeader.wHeaderSize = sizeof COMPACT_MUI;
|
|
m_MUIHeader.dwFileVersionMS = 0;
|
|
m_MUIHeader.dwFileVersionLS = 0;
|
|
m_MUIHeader.Checksum[16] = 0; //new BYTE[16];
|
|
m_MUIHeader.wReserved = 0;
|
|
m_MUIHeader.ulpOffset = 0;
|
|
m_MUIHeader.dwFileSize = 0;
|
|
m_MUIHeader.wFileNameLenWPad =0;
|
|
m_MUIHeader.wstrFieName[MAX_FILENAME_LENGTH] = '\0';
|
|
|
|
m_pbImageBase = NULL;
|
|
m_dwIndex = 0xFFFF; // index start from 0.
|
|
m_strFileName = new TCHAR[MAX_FILENAME_LENGTH];
|
|
}
|
|
CMUIFile::CMUIFile(CMUIFile & cmf)
|
|
{
|
|
//REVISIT : initialize copy constructor
|
|
}
|
|
CMUIFile::~CMUIFile()
|
|
{
|
|
if (m_pbImageBase)
|
|
{
|
|
delete m_pbImageBase;
|
|
}
|
|
if (m_strFileName)
|
|
{
|
|
delete []m_strFileName;
|
|
}
|
|
|
|
}
|
|
CMUIFile & CMUIFile::operator=(CMUIFile &cmf)
|
|
{
|
|
if (&cmf == this)
|
|
return *this;
|
|
|
|
m_MUIHeader.wHeaderSize = cmf.m_MUIHeader.wHeaderSize;
|
|
m_MUIHeader.dwFileVersionMS = cmf.m_MUIHeader.dwFileVersionMS;
|
|
m_MUIHeader.dwFileVersionLS = cmf.m_MUIHeader.dwFileVersionLS;
|
|
m_MUIHeader.Checksum[16] = cmf.m_MUIHeader.Checksum[16];
|
|
m_MUIHeader.wReserved = cmf.m_MUIHeader.wReserved;
|
|
m_MUIHeader.ulpOffset = cmf.m_MUIHeader.ulpOffset;
|
|
m_MUIHeader.dwFileSize = cmf.m_MUIHeader.dwFileSize;
|
|
m_MUIHeader.wFileNameLenWPad = cmf.m_MUIHeader.wFileNameLenWPad;
|
|
m_MUIHeader.wstrFieName[MAX_FILENAME_LENGTH] = cmf.m_MUIHeader.wstrFieName[MAX_FILENAME_LENGTH];
|
|
return *this;
|
|
}
|
|
|
|
|
|
|
|
BOOL CMUIFile::Create (PSTR pszMuiFile)
|
|
/*++
|
|
Abstract:
|
|
load file and fill the structure block.
|
|
Arguments:
|
|
pszMuiFile -
|
|
Return:
|
|
--*/
|
|
//
|
|
{
|
|
HANDLE hFile = NULL;
|
|
HANDLE hMappedFile = NULL;
|
|
BOOL fStatus = TRUE;
|
|
|
|
if (pszMuiFile == NULL){
|
|
fStatus = FALSE;
|
|
goto Exit;
|
|
}
|
|
LPCTSTR pszFileName = GetFileNameFromPath(pszMuiFile);
|
|
|
|
if (strlen (pszMuiFile)+1 > MAX_FILENAME_LENGTH ){
|
|
fStatus = FALSE;
|
|
goto Exit;; //overflow
|
|
}
|
|
// strncpy(m_strFileName, pszFileName, strlen (pszFileName)+1 );
|
|
PTSTR * ppszDestEnd = NULL;
|
|
size_t * pbRem = NULL;
|
|
HRESULT hr;
|
|
hr = StringCchCopyEx(m_strFileName, MAX_FILENAME_LENGTH, pszFileName, ppszDestEnd, pbRem, MUIRCT_STRSAFE_NULL);
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
fStatus = FALSE;
|
|
goto Exit;;
|
|
}
|
|
//
|
|
// Get checksum and file version info.
|
|
//
|
|
// PBYTE pMD5Checksum = new BYTE[16];
|
|
PBYTE pMD5Checksum = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 20);
|
|
// version
|
|
|
|
DWORD dwFileVersionMS,dwFileVersionLS;
|
|
dwFileVersionMS = dwFileVersionLS =0;
|
|
|
|
if (pMD5Checksum)
|
|
{
|
|
if(! getChecksumAndVersion(pszMuiFile,&pMD5Checksum, &dwFileVersionMS, &dwFileVersionLS) )
|
|
{
|
|
//CError ce;
|
|
//ce.ErrorPrint(_T("CCompactMUIFile::Create"),_T("Failure of GetChecksum()") );
|
|
}
|
|
else
|
|
{
|
|
memcpy(m_MUIHeader.Checksum, pMD5Checksum, RESOURCE_CHECKSUM_SIZE);
|
|
}
|
|
|
|
LocalFree(pMD5Checksum);
|
|
}
|
|
|
|
|
|
//
|
|
// Load a file and map
|
|
//
|
|
|
|
hFile = CreateFile(pszMuiFile, GENERIC_WRITE | GENERIC_READ, NULL, NULL, OPEN_EXISTING, NULL, NULL);
|
|
|
|
if ( INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CMUIFile::Create (PSTR pszMuiFile)"),_T("Failure of CreateFile()"), pszMuiFile );
|
|
printf("GetLastError %d", GetLastError());
|
|
fStatus = FALSE;
|
|
return FALSE;
|
|
}
|
|
|
|
hMappedFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL);
|
|
|
|
if(hMappedFile == NULL)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CMUIFile::Create (PSTR pszMuiFile)"),_T("Failure of CreateFileMapping()"), pszMuiFile );
|
|
printf("GetLastError %d", GetLastError());
|
|
fStatus = FALSE;
|
|
goto Exit;;
|
|
}
|
|
PBYTE pbImageBase = (PBYTE)MapViewOfFile(hMappedFile, FILE_MAP_WRITE, NULL, NULL, NULL);
|
|
|
|
if (pbImageBase == NULL)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CMUIFile::Create (PSTR pszMuiFile)"),_T("Failure of MapViewOfFile()"), pszMuiFile );
|
|
printf("GetLastError %d", GetLastError());
|
|
fStatus = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
// Fill the CMUIFile member data
|
|
m_pbImageBase = pbImageBase;
|
|
|
|
//
|
|
// Fill the COMPACT_MUI data field.
|
|
//
|
|
|
|
m_MUIHeader.dwFileVersionMS = dwFileVersionMS;
|
|
m_MUIHeader.dwFileVersionLS = dwFileVersionLS;
|
|
|
|
//offset, reserver, filesize.
|
|
m_MUIHeader.ulpOffset = 0; // we can't set this now.
|
|
m_MUIHeader.wReserved = 0;
|
|
|
|
m_MUIHeader.dwFileSize = GetFileSize(hFile, NULL);
|
|
|
|
|
|
// File name, filelenwithpadding, mui header size
|
|
|
|
// LPWSTR pwstrBuffer = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, 256);
|
|
WCHAR wstrBuffer[MAX_FILENAME_LENGTH];
|
|
|
|
// REVISIT; only accept english file name.
|
|
// specify wcslen instead of tcslen becasuse of possible overrun.
|
|
if (MultiByteToWideChar(CP_ACP, NULL, m_strFileName,
|
|
strlen(m_strFileName)+1, wstrBuffer, MAX_FILENAME_LENGTH ) == 0)
|
|
{
|
|
_tprintf("Error happen in Create: MultiByteToWideChar; GetLastError() : %d\n", GetLastError() );
|
|
fStatus = FALSE;
|
|
goto Exit;;
|
|
}
|
|
// wcsncpy(m_MUIHeader.wstrFieName, pwstrBuffer, wcslen(pwstrBuffer)+1); //strlen does not return '\0'
|
|
|
|
hr = StringCchCopyW(m_MUIHeader.wstrFieName, sizeof (m_MUIHeader.wstrFieName)/ sizeof(WCHAR),
|
|
wstrBuffer);
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
fStatus = FALSE;
|
|
goto Exit;;
|
|
}
|
|
// This should be done in Constructor of CMUIFile
|
|
// pcmui->m_MUIHeader.wHeaderSize = sizeof UP_COMPACT_MUI;
|
|
WORD wTempHeaderSize = m_MUIHeader.wHeaderSize;
|
|
|
|
|
|
Exit:
|
|
if (hFile)
|
|
CloseHandle(hFile);
|
|
if (hMappedFile)
|
|
CloseHandle(hMappedFile);
|
|
|
|
return fStatus;
|
|
// add padding at end of file name as null character.
|
|
// file length include; file string + null character + padding (null character as well)
|
|
}
|
|
|
|
#ifdef VARIALBE_MUI_STRUCTURE
|
|
BOOL CMUIFile::Create (PSTR pszMuiFile) //
|
|
/*++
|
|
Abstract:
|
|
load file and fill the structure block for variable MUI structure.
|
|
|
|
Arguments:
|
|
|
|
Return:
|
|
--*/
|
|
{
|
|
if(pszMuiFile == NULL)
|
|
return FALSE;
|
|
//
|
|
// Get checksum and file version info.
|
|
//
|
|
|
|
PBYTE pMD5Checksum = (PBYTE)LocalAlloc(LMEM_ZEROINIT, 16);
|
|
if (pMD5Checksum)
|
|
{
|
|
|
|
DWORD FileVersionLS,FileVersionMS;
|
|
|
|
if(!getChecksumAndVersion(pszMUIFile,&pMD5Checksum) )
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of GetChecksum()") );
|
|
LocalFree(pMD5Checksum);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
memcpy(m_MUIHeader.Checksum, pMD5Checksum, RESOURCE_CHECKSUM_SIZE);
|
|
}
|
|
|
|
LocalFree(pMD5Checksum);
|
|
}
|
|
|
|
//
|
|
// Load a file and map
|
|
//
|
|
|
|
HANDLE hFile = CreateFile(pszMUIFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
|
|
|
|
if ( INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::OpenCMFWithMUI"),_T("Failure of CreateFile()"), _T("File : %s"), pszMUIFile );
|
|
return FALSE;
|
|
}
|
|
|
|
HANDLE hMappedFile = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, NULL, NULL, NULL);
|
|
|
|
PBYTE pbImageBase = NULL ; //(PBYTE)MapViewOfFile(hMappedFile, NULL, NULL, NULL, NULL);
|
|
|
|
// Fill the CMUIFile member data
|
|
m_pbImageBase = pbImageBase;
|
|
// pcmui->m_hMUIFile = hFile; // do we need file handle ?
|
|
// pcmui->m_wImageSize = GetFileSize(hFile);
|
|
|
|
|
|
//
|
|
// Fill the COMPACT_MUI data field.
|
|
//
|
|
|
|
|
|
|
|
m_MUIHeader.dwFileVersionMS = dwFileVersionMS;
|
|
m_MUIHeader.dwFileVersionLS = dwFileVersionLS;
|
|
|
|
//offset, reserver, filesize.
|
|
m_MUIHeader.ulpOffset = 0; // we can't set this now.
|
|
m_MUIHeader.wReserved = 0;
|
|
|
|
m_MUIHeader.dwFileSize = GetFileSize(hFile, NULL);
|
|
|
|
|
|
// File name, filelenwithpadding, mui header size
|
|
|
|
// LPWSTR pwstrBuffer = new WCHAR[MAX_FILENAME_LENGTH];
|
|
WCHAR wstrBuffer[MAX_FILENAME_LENGTH];
|
|
if ( MultiByteToWideChar(CP_ACP, NULL, pszMUIFile,
|
|
strlen(ppszMuiFiles[i]), wstrBuffer, MAX_FILENAME_LENGTH ) == 0)
|
|
{
|
|
_tprintf("Error happen in Create: MultiByteToWideChar; GetLastError() : %d\n", GetLastError() );
|
|
return FALSE;
|
|
}
|
|
//wcsncpy(m_MUIHeader.wstrFieName, pwstrBuffer, wcslen(pwstrBuffer)+1); //strlen does not return '\0'
|
|
HRESULT hr;
|
|
hr = StringCchCopyW(m_MUIHeader.wstrFieName, sizeof (m_MUIHeader.wstrFieName)/ sizeof(WCHAR),
|
|
pwstrBuffer);
|
|
if ( ! SUCCEEDED(hr)){
|
|
_tprintf("Safe string copy Error\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// This should be done in Constructor of CMUIFile
|
|
// pcmui->m_MUIHeader.wHeaderSize = sizeof UP_COMPACT_MUI;
|
|
WORD wTempHeaderSize = m_MUIHeader.wHeaderSize;
|
|
|
|
BYTE bPadding = DWORD_ALIGNMENT(wTempHeaderSize) - wTempHeaderSize;
|
|
// add padding at end of file name as null character.
|
|
memcpy(m_MUIHeader.wstrFieName + wcslen(m_MUIHeader.wstrFieName)
|
|
+ sizeof (WCHAR)/2 , "\0", bPadding);
|
|
|
|
// file length include; file string + null character + padding (null character as well)
|
|
m_MUIHeader.wFileNameLenWPad = wcslen(m_MUIHeader.wstrFieName) + (sizeof WCHAR)/2 + bPadding/2;
|
|
|
|
m_MUIHeader.wHeaderSize += m_MUIHeader.wFileNameLenWPad; // we have to adjust file name buffer.
|
|
|
|
CloseHandle(hFile);
|
|
CloseHandle(hMappedFile);
|
|
}
|
|
#endif
|
|
|
|
BOOL CMUIFile::getChecksumAndVersion (LPCTSTR pszMUIFile, unsigned char **ppMD5Checksum, DWORD *dwFileVersionMS, DWORD *dwFileVersionLS )
|
|
/*++
|
|
Abstract:
|
|
getChecksumAndVersion - Get the cehckesum data/version from the MUI file, which will be saved in the CMF header
|
|
as MUI informatio; this can improve MUI loader burden to search checksum/version infomatio of MUI file
|
|
|
|
Arguments:
|
|
pszMUIFile - MUI file
|
|
[OUT] ppMD5Checksum - checksum data will be stored in this
|
|
[OUT] dwFileVersionMS - FileversionMS will be stored in this
|
|
[OUT] dwFileVersionLS - FileversionSS will be stored in this
|
|
Return:
|
|
true/false
|
|
--*/
|
|
{
|
|
typedef struct tagVS_FIXEDFILEINFO
|
|
{
|
|
LONG dwSignature; /* e.g. 0xfeef04bd */
|
|
LONG dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
|
|
LONG dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
|
|
LONG dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
|
|
LONG dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
|
|
LONG dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
|
|
LONG dwFileFlagsMask; /* = 0x3F for version "0.42" */
|
|
LONG dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
|
|
LONG dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
|
|
LONG dwFileType; /* e.g. VFT_DRIVER */
|
|
LONG dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
|
|
LONG dwFileDateMS; /* e.g. 0 */
|
|
LONG dwFileDateLS; /* e.g. 0 */
|
|
} VS_FIXEDFILEINFO;
|
|
|
|
typedef struct
|
|
{
|
|
USHORT TotalSize;
|
|
USHORT DataSize;
|
|
USHORT Type;
|
|
WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode null terminator
|
|
// Note that the previous 4 members has 16*2 + 3*2 = 38 bytes.
|
|
// So that compiler will silently add a 2 bytes padding to make
|
|
// FixedFileInfo to align in DWORD boundary.
|
|
VS_FIXEDFILEINFO FixedFileInfo;
|
|
} RESOURCE, *PRESOURCE; //*Resource;
|
|
|
|
typedef struct tagVERBLOCK
|
|
{
|
|
USHORT wTotalLen;
|
|
USHORT wValueLen;
|
|
USHORT wType;
|
|
WCHAR szKey[1];
|
|
// BYTE[] padding
|
|
// WORD value;
|
|
} VERBLOCK,*pVerBlock;
|
|
|
|
if (pszMUIFile == NULL || ppMD5Checksum == NULL || dwFileVersionMS == NULL
|
|
|| dwFileVersionLS == NULL) {
|
|
return FALSE;
|
|
}
|
|
#ifdef NEVER
|
|
//
|
|
// Get VersionInfo structure.
|
|
//
|
|
DWORD dwHandle;
|
|
|
|
DWORD dwVerSize = GetFileVersionInfoSize( (LPTSTR)pszMUIFile, &dwHandle);
|
|
|
|
HLOCAL hLocal = LocalAlloc(LMEM_ZEROINIT, dwVerSize );
|
|
|
|
LPVOID lpVerRes = LocalLock(hLocal);
|
|
|
|
DWORD dwError = GetLastError();
|
|
|
|
if ( ! GetFileVersionInfo((LPTSTR)pszMUIFile, 0 ,dwVerSize, lpVerRes) ) {
|
|
_tprintf(_T("Fail to get file version: GetLastError() : %d \n"),GetLastError() ) ;
|
|
return TRUE;
|
|
}
|
|
|
|
if (lpVerRes)
|
|
{
|
|
PRESOURCE pResBase = (PRESOURCE) lpVerRes;
|
|
|
|
DWORD ResourceSize = dwVerSize;
|
|
|
|
if((ResourceSize < sizeof(RESOURCE))
|
|
|| _wcsicmp(pResBase->Name,L"VS_VERSION_INFO") != 0)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CMUIFile::GetCheckSum"), _T("Invalid Version resource") );
|
|
return FALSE;
|
|
}
|
|
ResourceSize -= sizeof (RESOURCE);
|
|
// //
|
|
// Get the beginning address of the children of the version information.
|
|
//
|
|
VERBLOCK* pVerBlock = (VERBLOCK*)(pResBase + 1);
|
|
DWORD BlockLen = 0;
|
|
DWORD VarFileInfoSize = 0;
|
|
|
|
while (ResourceSize > 0)
|
|
{
|
|
if (wcscmp(pVerBlock->szKey, L"VarFileInfo") == 0)
|
|
{
|
|
//
|
|
// Find VarFileInfo block. Search the ResourceChecksum block.
|
|
//
|
|
VarFileInfoSize = pVerBlock->wTotalLen;
|
|
BlockLen =DWORD_ALIGNMENT(sizeof(*pVerBlock) -1 + sizeof(L"VarFileInfo"));
|
|
VarFileInfoSize -= BlockLen;
|
|
pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
|
|
while (VarFileInfoSize > 0)
|
|
{
|
|
if (wcscmp(pVerBlock->szKey, L"ResourceChecksum") == 0)
|
|
{
|
|
memcpy(*ppMD5Checksum,(unsigned char*)DWORD_ALIGNMENT(PtrToLong(pVerBlock->szKey) + sizeof(L"ResourceChecksum"), 16);
|
|
|
|
return TRUE;
|
|
}
|
|
BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
|
|
pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
|
|
VarFileInfoSize -= BlockLen;
|
|
}
|
|
return FALSE;
|
|
}
|
|
BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
|
|
pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
|
|
ResourceSize -= BlockLen;
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|
|
//#ifdef NEVER
|
|
|
|
HMODULE hModule = LoadLibraryEx(pszMUIFile, NULL, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES );
|
|
DWORD dwError = GetLastError();
|
|
if ( hModule )
|
|
{
|
|
HRSRC hrSrc = FindResource(hModule, MAKEINTRESOURCE(1), RT_VERSION);
|
|
|
|
if (hrSrc)
|
|
{
|
|
HGLOBAL hgRes = LoadResource(hModule, hrSrc);
|
|
|
|
if (hgRes)
|
|
{
|
|
PRESOURCE pResBase = (PRESOURCE)LockResource(hgRes);
|
|
|
|
if (pResBase)
|
|
{
|
|
DWORD ResourceSize = SizeofResource(hModule, hrSrc);
|
|
|
|
if((ResourceSize < sizeof(RESOURCE))
|
|
|| _wcsicmp(pResBase->Name,L"VS_VERSION_INFO") != 0)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CMUIFile::GetCheckSum"), _T("Invalid Version resource") );
|
|
goto failure;
|
|
}
|
|
*dwFileVersionMS = pResBase->FixedFileInfo.dwFileVersionMS;
|
|
*dwFileVersionLS = pResBase->FixedFileInfo.dwFileVersionLS;
|
|
|
|
ResourceSize -= sizeof (RESOURCE);
|
|
// //
|
|
// Get the beginning address of the children of the version information.
|
|
//
|
|
VERBLOCK* pVerBlock = (VERBLOCK*)(pResBase + 1);
|
|
DWORD BlockLen = 0;
|
|
DWORD VarFileInfoSize = 0;
|
|
|
|
while (ResourceSize > 0)
|
|
{
|
|
if (wcscmp(pVerBlock->szKey, L"VarFileInfo") == 0)
|
|
{
|
|
//
|
|
// Find VarFileInfo block. Search the ResourceChecksum block.
|
|
//
|
|
VarFileInfoSize = pVerBlock->wTotalLen;
|
|
BlockLen =DWORD_ALIGNMENT(sizeof(*pVerBlock) -1 + sizeof(L"VarFileInfo"));
|
|
VarFileInfoSize -= BlockLen;
|
|
pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
|
|
while (VarFileInfoSize > 0)
|
|
{
|
|
if (wcscmp(pVerBlock->szKey, L"ResourceChecksum") == 0)
|
|
{
|
|
PBYTE pbTempChecksum = (unsigned char*)DWORD_ALIGNMENT(PtrToLong(pVerBlock->szKey) + sizeof(L"ResourceChecksum"));
|
|
memcpy(*ppMD5Checksum, pbTempChecksum, 16);
|
|
|
|
goto success;
|
|
|
|
}
|
|
BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
|
|
pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
|
|
VarFileInfoSize -= BlockLen;
|
|
}
|
|
goto failure;
|
|
|
|
}
|
|
BlockLen = DWORD_ALIGNMENT(pVerBlock->wTotalLen);
|
|
pVerBlock = (VERBLOCK*)((unsigned char*)pVerBlock + BlockLen);
|
|
ResourceSize -= BlockLen;
|
|
} // if (pResBase)
|
|
} // if (hgRes)
|
|
} // if (Resource)
|
|
} // if (hrSrc)
|
|
} // if ( hModule )
|
|
|
|
//#endif
|
|
|
|
failure:
|
|
FreeLibrary(hModule);
|
|
return FALSE;
|
|
|
|
success:
|
|
FreeLibrary(hModule);
|
|
return TRUE;
|
|
|
|
|
|
};
|
|
|
|
BOOL CMUIFile::WriteMUIFile(CMUIFile *pcmui)
|
|
/*++
|
|
Abstract:
|
|
Create and write a new MUI file with a data in CMUIFile.
|
|
|
|
Arguments:
|
|
pcmui - CMUIFile class,which should be filled by data
|
|
|
|
Return:
|
|
--*/
|
|
{
|
|
if (pcmui == NULL)
|
|
return FALSE;
|
|
|
|
HANDLE hFile = CreateFile(pcmui->m_strFileName, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE == hFile)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CCompactMUIFile::WriteMUIFile"),_T("Failure of CreateFile()"));
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwWritten;
|
|
|
|
if ( WriteFile(hFile, pcmui->m_pbImageBase, pcmui->m_MUIHeader.dwFileSize, &dwWritten, NULL) )
|
|
{
|
|
CloseHandle(hFile);
|
|
return TRUE;
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
return FALSE;
|
|
|
|
};
|
|
|
|
|
|
|
|
LPCTSTR CMUIFile::GetFileNameFromPath(LPCTSTR pszFilePath)
|
|
{
|
|
if ( pszFilePath == NULL)
|
|
return FALSE;
|
|
//
|
|
// Get file name from the path
|
|
//
|
|
|
|
DWORD dwLen = _tcslen(pszFilePath);
|
|
// d:\test\test.exe.mui //
|
|
while(dwLen--)
|
|
{
|
|
if (pszFilePath[dwLen] == '\\')
|
|
{
|
|
return pszFilePath+dwLen+1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pszFilePath;
|
|
}
|
|
|
|
#ifdef NEVER
|
|
BOOL CMUIFile::getFileVersion(LPCTSTR pszMuiFile, DWORD *dwFileVersionMS, DWORD *dwFileVersionLS)
|
|
/*++
|
|
Abstract:
|
|
get file version.
|
|
Arguments:
|
|
|
|
Return:
|
|
--*/
|
|
{
|
|
if ( pszMuiFile == NULL || dwFileVersionMS == NULL || dwFileVersionLS == NULL)
|
|
return FALSE;
|
|
|
|
typedef struct tagVS_FIXEDFILEINFO
|
|
{
|
|
LONG dwSignature; /* e.g. 0xfeef04bd */
|
|
LONG dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
|
|
LONG dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
|
|
LONG dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
|
|
LONG dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
|
|
LONG dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
|
|
LONG dwFileFlagsMask; /* = 0x3F for version "0.42" */
|
|
LONG dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
|
|
LONG dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
|
|
LONG dwFileType; /* e.g. VFT_DRIVER */
|
|
LONG dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
|
|
LONG dwFileDateMS; /* e.g. 0 */
|
|
LONG dwFileDateLS; /* e.g. 0 */
|
|
} VS_FIXEDFILEINFO;
|
|
|
|
typedef struct
|
|
{
|
|
USHORT TotalSize;
|
|
USHORT DataSize;
|
|
USHORT Type;
|
|
WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode null terminator
|
|
// Note that the previous 4 members has 16*2 + 3*2 = 38 bytes.
|
|
// So that compiler will silently add a 2 bytes padding to make
|
|
// FixedFileInfo to align in DWORD boundary.
|
|
VS_FIXEDFILEINFO FixedFileInfo;
|
|
} RESOURCE, *PRESOURCE; //*Resource;
|
|
|
|
HMODULE hModule = LoadLibraryEx(pszMuiFile, NULL, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES );
|
|
if ( hModule )
|
|
{
|
|
HRSRC hrSrc = FindResource(hModule, MAKEINTRESOURCE(1), RT_VERSION);
|
|
|
|
if (hrSrc)
|
|
{
|
|
HGLOBAL hgRes = LoadResource(hModule, hrSrc);
|
|
if (hgRes)
|
|
{
|
|
PRESOURCE pResBase = (PRESOURCE)LockResource(hrSrc);
|
|
|
|
if (pResBase)
|
|
{
|
|
DWORD ResourceSize = SizeofResource(hModule, hrSrc);
|
|
|
|
if((ResourceSize < sizeof(RESOURCE))
|
|
|| _wcsicmp(pResBase->Name,L"VS_VERSION_INFO") != 0)
|
|
{
|
|
CError ce;
|
|
ce.ErrorPrint(_T("CMUIFile::getFileVersion"), _T("Invalid Version resource") );
|
|
goto failure;
|
|
}
|
|
|
|
*dwFileVersionMS = pResBase->FixedFileInfo.dwFileVersionMS;
|
|
*dwFileVersionLS = pResBase->FixedFileInfo.dwFileVersionLS;
|
|
|
|
goto success;
|
|
} // if (Resource)
|
|
} // if (hgRes)
|
|
} //if (hrSrc)
|
|
}//if ( hModule )
|
|
|
|
success:
|
|
FreeLibrary(hModule);
|
|
return TRUE;
|
|
|
|
failure:
|
|
FreeLibrary(hModule);
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CError Class
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
void CError::ErrorPrint(PSTR pszErrorModule, PSTR pszErrorLocation, PSTR pszFile /* = NULL */)
|
|
/*++
|
|
Abstract:
|
|
print error information.
|
|
|
|
Arguments:
|
|
pszErrorModule - The function name of error taking place
|
|
pszErrorLocation - The location in the function of error taking place
|
|
pszFile - problematic file, which is used only by file related error such as CreateFile
|
|
|
|
Return:
|
|
--*/
|
|
{
|
|
// REVISIT; create Log file.
|
|
if (pszErrorModule == NULL || pszErrorLocation == NULL)
|
|
return ;
|
|
|
|
_tprintf(_T(" %s, %s, %s \n"), pszFile ? pszFile : _T(" "), pszErrorModule, pszErrorLocation);
|
|
|
|
}
|