Introduction
Recently, I created a program and decided to store some literal string
s in its resources. I found the LoadString
function somewhat lacking. The main thing that bugged me is that you had to play a guessing game with the buffer size since there is no way from the function of knowing how long the string
actually is! I thought ok there has to be a better solution and of course there is. All of the Loadxxx
functions basically wrap raw access. So with a little research, I created rcgets.
You have a block of data called a string
table that holds your string
literals. This always stores 16 string
s. Itβs basically an array of wchar_t
elements that hold indexes and unicode string
data. An element in the array will be an index between 0 β 15 and the length of its following string
is contained inside the index. If the index is 0 then it has no associated string
in which case you just jump to the next element in the array for the following index. If the index is not zero, then it is followed by a string
of that length. The next index will follow immediately after the aforementioned string
until the last index in the array.
The Code
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define IDS_HELLO 1001
#define IDS_GOODBYE 1002
wchar_t* rcgets( unsigned int id );
wchar_t* rcgets( unsigned int id )
{
unsigned int block = 0, index = 0, i = 0;
HRSRC info = NULL;
HGLOBAL resc = NULL;
LPVOID data = NULL;
DWORD size = 0;
wchar_t *p = NULL;
wchar_t *s = NULL;
block = ((id >> 4) + 1);
index = (id & 0xF);
info = FindResourceEx( NULL, RT_STRING, MAKEINTRESOURCE(block),
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) );
if ( info == NULL ) { return NULL; }
size = SizeofResource( NULL, info );
if ( size == 0 ) { return NULL; }
resc = LoadResource( NULL, info );
if ( resc != NULL )
{
data = LockResource( resc );
if ( data != NULL )
{
p = (wchar_t*) data;
for ( unsigned int i = 0; i < 16; i++ )
{
if ( i == index )
{
s = new wchar_t[ *p + 1 ];
if ( s != 0 )
{
memcpy( s, &p[1], *p * sizeof(wchar_t) );
s[ *p ] = 0;
}
break;
}
p += *p;
p++;
}
}
UnlockResource( data );
FreeResource( resc );
}
return s;
}
int wmain()
{
wchar_t *s = NULL;
s = rcgets( IDS_GOODBYE );
if ( s != NULL )
{
_putws( s );
delete[] s;
s = NULL;
}
s = rcgets( IDS_HELLO );
if ( s != NULL )
{
_putws( s );
delete[] s;
s = NULL;
}
getchar();
return EXIT_SUCCESS;
}
Notes
The variable βp
β in the function could possibly run pass the end of the data block as it assumes the data in the block is correct. This scenario could lead to read errors or corruption. For example, if an index reports that its string
is 7845 in length but the data block is only 512. It might be wise to use the size variable returned by SizeOfResource
to test the pointers offset and prevent overrun errors.
I believe that literal string
s can be used to identify resources rather than numbered ids. I am still researching how to process these. I believe it is related to the top bits of the id string
.
The function can easily be modified to pass extra parameters to FindResourceEx
to for example access another module or use another language.
Anyway feedback on these points or any improvement of the code would be appreciated.