|
|
|
/**************************************************************************
|
|
|
|
THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF
|
|
|
|
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
|
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
|
|
PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
Copyright 1998 Microsoft Corporation. All Rights Reserved.
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
|
|
|
File: strblock.c
|
|
|
|
|
|
|
|
Description: Implements the functions that manipulate a string block.
|
|
|
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include "strblock.h"
|
|
|
|
|
|
|
|
|
|
|
|
// The format of string resources is explained below.
|
|
|
|
//
|
|
|
|
// The smallest granularity of string resource that can be loaded/updated is a block.
|
|
|
|
// Each block is identified by an ID, starting with 1. You need to use the block ID
|
|
|
|
// when calling FindResource(), LoadResource(), UpdateResource().
|
|
|
|
//
|
|
|
|
// A string with ID, nStringID, is in the block with ID, nBlockID, given by the following
|
|
|
|
// formula:
|
|
|
|
// nBlockID = (nStringID / 16) + 1; // Note integer division.
|
|
|
|
//
|
|
|
|
// A block of string resource is laid out as follows:
|
|
|
|
// Each block has NO_OF_STRINGS_PER_BLOCK (= 16) strings. Each string is represented as
|
|
|
|
// an ordered pair, (LENGTH, TEXT). The LENGTH is a WORD that specifies the size, in terms
|
|
|
|
// of number of characters, of the string that follows. TEXT follows the LENGTH and is
|
|
|
|
// a sequence of UNICODE characters, NOT terminated by a NULL character.Any TEXT may be of
|
|
|
|
// zero-length, in which case, LENGTH is zero.
|
|
|
|
//
|
|
|
|
// An executable does not have a string table block with ID, nBlockID, if it does not have any
|
|
|
|
// strings with IDs - ((nBlockID - 1) * 16) thru' ((nBlockID * 16) - 1).
|
|
|
|
//
|
|
|
|
// This format is the same for Windows NT, Windows 95 & Windows 98. Yes, strings in a resource
|
|
|
|
// are internally stored in UNICODE format even in Windows 95 & Windows 98.
|
|
|
|
|
|
|
|
|
|
|
|
// Internal data structure format for a string block.
|
|
|
|
// Our block of strings has as an array of UNICODE string pointers.
|
|
|
|
|
|
|
|
typedef struct tagSTRINGBLOCK
|
|
|
|
{
|
|
|
|
UINT nBlockID; // The ID of the block.
|
|
|
|
WORD wLangID; // The language ID.
|
|
|
|
LPWSTR strArray[NO_OF_STRINGS_PER_BLOCK]; // We maintain the strings
|
|
|
|
// internally in UNICODE.
|
|
|
|
} STRINGBLOCK, * PSTRINGBLOCK;
|
|
|
|
|
|
|
|
|
|
|
|
// A thread-specific error number for the last block operation.
|
|
|
|
__declspec(thread) STRBLOCKERR g_strBlockErr = STRBLOCKERR_OK;
|
|
|
|
|
|
|
|
// Set the error code.
|
|
|
|
void SetBlockError( STRBLOCKERR err ) { g_strBlockErr = err; }
|
|
|
|
|
|
|
|
|
|
|
|
// Forward declarations.
|
|
|
|
|
|
|
|
// Create a string block & return the pointer to the block. Return NULL on failure.
|
|
|
|
// Sets the error code.
|
|
|
|
PSTRINGBLOCK CreateBlock( HINSTANCE hInstLib, UINT nBlockID, WORD wLangID );
|
|
|
|
|
|
|
|
// Parse the string block resource pointed at by, pParse, and fill the strings in pStrBlock.
|
|
|
|
BOOL ParseRes( LPVOID pRes, PSTRINGBLOCK pStrBlock );
|
|
|
|
|
|
|
|
// Get the size of the raw string block resource in the given block.
|
|
|
|
DWORD GetResSize( PSTRINGBLOCK pStrBlock );
|
|
|
|
|
|
|
|
// Update a block of string in the specified library.
|
|
|
|
// hUpdate specifies the update-file handle. This handle is returned by the BeginUpdateResource.
|
|
|
|
// pStrBlock contains the new strings.
|
|
|
|
// nBlockID specifies the ID of the block. Use the same block ID as of pStrBlock if this value is -1.
|
|
|
|
// wlangID specifies the language ID of the block. Use the same language ID as of pStrBlock, if this value is 0.
|
|
|
|
// Returns TRUE on success and FALSE on failure.
|
|
|
|
// Sets the error code.
|
|
|
|
BOOL UpdateBlock( HANDLE hUpdate, PSTRINGBLOCK pStrBlock, int nBlockID, WORD wLangID );
|
|
|
|
|
|
|
|
// Use the strings in the block, pStrBloc, and build a buffer whose format matches that of the
|
|
|
|
// string resource block that can be used to update string resource.
|
|
|
|
// pRes points to a buffer that gets filled. It must be large enough to hold the entire block.
|
|
|
|
// To figure out the size needed, call GetResSize().
|
|
|
|
VOID BuildRes( PSTRINGBLOCK pStrBlock, LPVOID pRes );
|
|
|
|
|
|
|
|
|
|
|
|
// Create a string block.
|
|
|
|
|
|
|
|
HSTRBLOCK WINAPI GetStringBlockA( LPCSTR strAppName, UINT nBlockID, WORD wLangID )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = NULL;
|
|
|
|
HINSTANCE hInstLib = NULL;
|
|
|
|
|
|
|
|
hInstLib = LoadLibraryExA(
|
|
|
|
strAppName,
|
|
|
|
NULL,
|
|
|
|
DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE
|
|
|
|
);
|
|
|
|
|
|
|
|
if( NULL == hInstLib )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_APPLOADFAILED);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the block of strings.
|
|
|
|
pStrBlock = CreateBlock(hInstLib, nBlockID, wLangID);
|
|
|
|
|
|
|
|
// Free the library.
|
|
|
|
FreeLibrary(hInstLib);
|
|
|
|
|
|
|
|
if( pStrBlock )
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return (HSTRBLOCK)pStrBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create a string block.
|
|
|
|
|
|
|
|
HSTRBLOCK WINAPI GetStringBlockW( LPCWSTR strAppName, UINT nBlockID, WORD wLangID )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = NULL;
|
|
|
|
HINSTANCE hInstLib = NULL;
|
|
|
|
|
|
|
|
hInstLib = LoadLibraryExW(
|
|
|
|
strAppName,
|
|
|
|
NULL,
|
|
|
|
DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE
|
|
|
|
);
|
|
|
|
|
|
|
|
if( NULL == hInstLib )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_APPLOADFAILED);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the block of strings.
|
|
|
|
pStrBlock = CreateBlock(hInstLib, nBlockID, wLangID);
|
|
|
|
|
|
|
|
// Free the library.
|
|
|
|
FreeLibrary(hInstLib);
|
|
|
|
|
|
|
|
if( pStrBlock )
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return (HSTRBLOCK)pStrBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI DeleteStringBlock( HSTRBLOCK hStrBlock )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( i = 0; i < NO_OF_STRINGS_PER_BLOCK; i++ )
|
|
|
|
{
|
|
|
|
if( pStrBlock->strArray[i] )
|
|
|
|
free(pStrBlock->strArray[i]);
|
|
|
|
}
|
|
|
|
free( pStrBlock);
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int WINAPI GetStringLength( HSTRBLOCK hStrBlock, UINT nIndex )
|
|
|
|
{
|
|
|
|
int nLen;
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if( (nIndex < 0) || (nIndex >= NO_OF_STRINGS_PER_BLOCK) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDINDEX);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nLen = wcslen(pStrBlock->strArray[nIndex]);
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return nLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI GetStringA( HSTRBLOCK hStrBlock, UINT nIndex, LPSTR pszText )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if( (nIndex < 0) || (nIndex >= NO_OF_STRINGS_PER_BLOCK) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDINDEX);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if( NULL == pszText )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_STRINVALID);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !WideCharToMultiByte(CP_ACP, 0, pStrBlock->strArray[nIndex], -1, pszText,
|
|
|
|
wcslen(pStrBlock->strArray[nIndex]) + 1, NULL, NULL) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_UNKNOWN);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI GetStringW( HSTRBLOCK hStrBlock, UINT nIndex, LPWSTR pszText )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if( (nIndex < 0) || (nIndex >= NO_OF_STRINGS_PER_BLOCK) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDINDEX);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if( NULL == pszText )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_STRINVALID);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
wcscpy(pszText, pStrBlock->strArray[nIndex]);
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI SetStringA( HSTRBLOCK hStrBlock, UINT nIndex, LPCSTR pszText )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
int nLen;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if( (nIndex < 0) || (nIndex >= NO_OF_STRINGS_PER_BLOCK) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDINDEX);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the current string & reallocate a new one..
|
|
|
|
free(pStrBlock->strArray[nIndex]);
|
|
|
|
|
|
|
|
nLen = strlen(pszText) + 1;
|
|
|
|
pStrBlock->strArray[nIndex] = (LPWSTR)malloc( sizeof(WCHAR) * nLen);
|
|
|
|
|
|
|
|
if( NULL == pStrBlock->strArray[nIndex] )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_NOMEMORY);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !MultiByteToWideChar(CP_ACP, 0, pszText, -1, pStrBlock->strArray[nIndex], nLen) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_UNKNOWN);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI SetStringW( HSTRBLOCK hStrBlock, UINT nIndex, LPCWSTR pszText )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
int nLen;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if( (nIndex < 0) || (nIndex >= NO_OF_STRINGS_PER_BLOCK) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDINDEX);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the current string & reallocate a new one..
|
|
|
|
free(pStrBlock->strArray[nIndex]);
|
|
|
|
nLen = wcslen(pszText) + 1;
|
|
|
|
|
|
|
|
pStrBlock->strArray[nIndex] = (LPWSTR)malloc( sizeof(WCHAR) * nLen);
|
|
|
|
|
|
|
|
if( NULL == pStrBlock->strArray[nIndex] )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_NOMEMORY);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
wcscpy(pStrBlock->strArray[nIndex], pszText);
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int WINAPI GetFirstStringID( HSTRBLOCK hStrBlock )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return (pStrBlock->nBlockID - 1) * NO_OF_STRINGS_PER_BLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int WINAPI GetBlockID( HSTRBLOCK hStrBlock )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return pStrBlock->nBlockID;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
WORD WINAPI GetBlockLanguage( HSTRBLOCK hStrBlock )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
return pStrBlock->wLangID;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI UpdateStringBlockA( LPCSTR strAppName, HSTRBLOCK hStrBlock, int nBlockID, WORD wLangID )
|
|
|
|
{
|
|
|
|
HANDLE hUpdate;
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
hUpdate = BeginUpdateResourceA(strAppName, FALSE);
|
|
|
|
|
|
|
|
if( NULL == hUpdate )
|
|
|
|
{
|
|
|
|
DWORD dwError = GetLastError();
|
|
|
|
|
|
|
|
switch( dwError )
|
|
|
|
{
|
|
|
|
case ERROR_CALL_NOT_IMPLEMENTED:
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATENOTIMPLEMENTED);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATEFAILED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the resource.
|
|
|
|
if( !UpdateBlock(hUpdate, pStrBlock, nBlockID, wLangID) )
|
|
|
|
{
|
|
|
|
EndUpdateResource(hUpdate, FALSE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !EndUpdateResource(hUpdate, FALSE) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATEFAILED);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL WINAPI UpdateStringBlockW( LPCWSTR strAppName, HSTRBLOCK hStrBlock, int nBlockID, WORD wLangID )
|
|
|
|
{
|
|
|
|
HANDLE hUpdate;
|
|
|
|
PSTRINGBLOCK pStrBlock = (PSTRINGBLOCK)hStrBlock;
|
|
|
|
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_INVALIDBLOCK);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
hUpdate = BeginUpdateResourceW(strAppName, FALSE);
|
|
|
|
|
|
|
|
if( NULL == hUpdate )
|
|
|
|
{
|
|
|
|
DWORD dwError = GetLastError();
|
|
|
|
|
|
|
|
switch( dwError )
|
|
|
|
{
|
|
|
|
case ERROR_CALL_NOT_IMPLEMENTED:
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATENOTIMPLEMENTED);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATEFAILED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the resource.
|
|
|
|
if( !UpdateBlock(hUpdate, pStrBlock, nBlockID, wLangID) )
|
|
|
|
{
|
|
|
|
EndUpdateResource(hUpdate, FALSE);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !EndUpdateResource(hUpdate, FALSE) )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATEFAILED);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
STRBLOCKERR WINAPI GetStringBlockError()
|
|
|
|
{
|
|
|
|
return g_strBlockErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Create a string block & return the pointer to the block. Return NULL on failure.
|
|
|
|
|
|
|
|
PSTRINGBLOCK CreateBlock( HINSTANCE hInstLib, UINT nBlockID, WORD wLangID )
|
|
|
|
{
|
|
|
|
PSTRINGBLOCK pStrBlock;
|
|
|
|
HRSRC hFindRes;
|
|
|
|
HGLOBAL hLoadRes;
|
|
|
|
LPVOID pRes;
|
|
|
|
|
|
|
|
hFindRes = FindResourceEx(hInstLib, RT_STRING, MAKEINTRESOURCE(nBlockID), wLangID);
|
|
|
|
if( NULL == hFindRes )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_RESNOTFOUND);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hLoadRes = LoadResource(hInstLib, hFindRes);
|
|
|
|
if( NULL == hLoadRes )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_LOADRESFAILED);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pRes = LockResource(hLoadRes);
|
|
|
|
if( NULL == pRes )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_LOADRESFAILED);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new string block, fill the strings based on the resource contents.
|
|
|
|
pStrBlock = (PSTRINGBLOCK)malloc(sizeof(STRINGBLOCK));
|
|
|
|
if( NULL == pStrBlock )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_NOMEMORY);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pStrBlock->nBlockID = nBlockID;
|
|
|
|
pStrBlock->wLangID = wLangID;
|
|
|
|
|
|
|
|
if( !ParseRes(pRes, pStrBlock) )
|
|
|
|
{
|
|
|
|
free(pStrBlock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pStrBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Parse the raw string resource, pRes, and build up the string block, pStrBlock.
|
|
|
|
// The parsing illustrates the format of a string block in an executable.
|
|
|
|
|
|
|
|
BOOL ParseRes( LPVOID pRes, PSTRINGBLOCK pStrBlock )
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
int nLen;
|
|
|
|
WCHAR* pParse = (WCHAR *)pRes;
|
|
|
|
|
|
|
|
// There are NO_OF_STRINGS_PER_BLOCK(=16) strings per block.
|
|
|
|
for( i = 0; i < NO_OF_STRINGS_PER_BLOCK; i++ )
|
|
|
|
{
|
|
|
|
nLen = (int)*pParse++; // The length of the string.
|
|
|
|
pStrBlock->strArray[i] = (LPWSTR)malloc((nLen + 1) * sizeof(WCHAR));
|
|
|
|
|
|
|
|
if( NULL == pStrBlock->strArray[i] )
|
|
|
|
{
|
|
|
|
int k;
|
|
|
|
|
|
|
|
for( k = 0; k < i; k++ ) // Free up the memory allocated so far.
|
|
|
|
free(pStrBlock->strArray[k]);
|
|
|
|
SetBlockError(STRBLOCKERR_NOMEMORY);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( j = 0; j < nLen; j++ ) // Copy the string.
|
|
|
|
pStrBlock->strArray[i][j] = *pParse++;
|
|
|
|
pStrBlock->strArray[i][j] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DWORD GetResSize( PSTRINGBLOCK pStrBlock )
|
|
|
|
{
|
|
|
|
DWORD dwResSize = 0;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for( i = 0; i < NO_OF_STRINGS_PER_BLOCK; i++ )
|
|
|
|
dwResSize += (wcslen(pStrBlock->strArray[i]) + 1);
|
|
|
|
|
|
|
|
return dwResSize * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Build a raw resource block, pRes, based on our string block, pStrBlock.
|
|
|
|
// The raw resource block may be used to update a string resource.
|
|
|
|
|
|
|
|
VOID BuildRes( PSTRINGBLOCK pStrBlock, LPVOID pRes )
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
int nLen;
|
|
|
|
WCHAR* pParse = (WCHAR *)pRes;
|
|
|
|
|
|
|
|
// There are NO_OF_STRINGS_PER_BLOCK (= 16) strings per block.
|
|
|
|
for( i = 0; i < NO_OF_STRINGS_PER_BLOCK; i++ )
|
|
|
|
{
|
|
|
|
*pParse++ = nLen = wcslen(pStrBlock->strArray[i]);
|
|
|
|
for( j = 0; j < nLen; j++ )
|
|
|
|
*pParse++ = pStrBlock->strArray[i][j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL UpdateBlock( HANDLE hUpdate, PSTRINGBLOCK pStrBlock, int nBlockID, WORD wLangID )
|
|
|
|
{
|
|
|
|
DWORD dwResSize;
|
|
|
|
LPVOID pRes;
|
|
|
|
DWORD dwRet = 0;
|
|
|
|
WORD wLanguageID = (0 == wLangID) ? pStrBlock->wLangID : wLangID;
|
|
|
|
|
|
|
|
// Get the resource length as required by a raw string resource block.
|
|
|
|
dwResSize = GetResSize(pStrBlock);
|
|
|
|
pRes = malloc(dwResSize);
|
|
|
|
if( NULL == pRes )
|
|
|
|
{
|
|
|
|
SetBlockError(STRBLOCKERR_NOMEMORY);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BuildRes(pStrBlock, pRes);
|
|
|
|
|
|
|
|
if( !UpdateResource(
|
|
|
|
hUpdate,
|
|
|
|
RT_STRING,
|
|
|
|
MAKEINTRESOURCE(((-1 == nBlockID) ? pStrBlock->nBlockID : nBlockID)),
|
|
|
|
wLanguageID,
|
|
|
|
pRes,
|
|
|
|
dwResSize
|
|
|
|
) )
|
|
|
|
{
|
|
|
|
DWORD dwError = GetLastError();
|
|
|
|
|
|
|
|
switch( dwError )
|
|
|
|
{
|
|
|
|
case ERROR_CALL_NOT_IMPLEMENTED:
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATENOTIMPLEMENTED);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_UPDATEFAILED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pRes);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(pRes);
|
|
|
|
|
|
|
|
SetBlockError(STRBLOCKERR_OK);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|