Click here to Skip to main content
15,887,240 members
Articles / General Programming / String
Alternative
Tip/Trick

Load a Windows string resource into a std::string or std::wstring

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
10 Jun 2010CPOL2 min read 13.4K   2   3
Alain's (original, now much hacked) narrow character version, could leak if std::basic_string::asign threw. To make the function exception safe either use a local buffer (if the size is fixed) or a vector (if the size isn't known).In both cases it's usually more efficient (and readable) to...
Alain's (original, now much hacked) narrow character version, could leak if std::basic_string<>::asign threw. To make the function exception safe either use a local buffer (if the size is fixed) or a vector (if the size isn't known).

In both cases it's usually more efficient (and readable) to return a string by value than construct it outside the function and essentially reconstruct it within the function. This doesn't help too much if you want the semantics of the windows LoadString but there's not a lot of reason to return the size of the loaded string. This information isn't needed in the wide character case and is useless in the narrow character case (it's always going to be less than the size passed into the function).

I'd be tempted to use:

[When I first wrote this I was seduced into the idea that you could directly initialise a string from a pointer and a length. However the C++ standard doesn't specify which order parameters are evaluated prior to a function call so we need to stick a sequence point in between the read and the string construction.]

std::wstring load_wstring_from_resource( HINSTANCE instance_handle, unsigned resource_id )
{
    wchar_t *buffer = 0;
    std::size_t string_length = LoadStringW(
        instance_handle,
        resource_id,
        reinterpret_cast<wchar_t *>( &buffer ),
        0 );

    return std::wstring( buffer, string_length );
 );
}


or:

std::string load_string_from_resource( HINSTANCE instance_handle, unsigned resource_id )
{
    char buffer[ 1024 ] = { '\0' };
    std::size_t string_length = LoadStringA(
        instance_handle,
        resource_id,
        buffer,
        1024 );

    return std::string( buffer, string_length );
}


[Note that here you could get away with doing it all in one line as there's no way the location of buffer is going to change. However it leads more naturally onto the next one...]

And for those that really want big strings and dynamic memory allocation, you can get that by:

std::string load_string_from_resource( HINSTANCE instance_handle, unsigned resource_id, std::size_t max_size )
{
    std::vector<char> buffer( max_size );
    std::size_t string_length = LoadStringA(
        instance_handle,
        resource_id,
        &buffer[ 0 ],
        max_size );

    return std::string( &buffer[ 0 ], string_length );
}


No exception handling required and is still exception safe. And on VC++ 2010 it's faster using the vector than manually handling exceptions from new[].

Just remember folks - new and delete, there's usually a better way. Be exception safe out there!

Ash

PS: Edited to buggery as I'd forgotten to escape a couple of angle brackets.

PPS: Edited more to buggery as I'd been making assumptions about the order of evaluation of parameters to functions.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I've been programming since 1985 - starting with Fortran 77, then moving onto assembler, C and C++ in about 1991. I also know enough Java and Python to read code but you probably wouldn't want me writing it.

I've worked in a wide variety of application areas - defense, banking, games and security with the longest stints being in security. I also seem to end up programming devices far too often. This time I'm programming terahertz band body scanners.

Comments and Discussions

 
GeneralSee my last update :) Pin
Alain Rist10-Jun-10 10:31
Alain Rist10-Jun-10 10:31 
GeneralAnything in the standard library can throw unless it's docum... Pin
Aescleal8-Jun-10 11:29
Aescleal8-Jun-10 11:29 
Anything in the standard library can throw unless it's documented as no-throw (things like std::auto_ptr's copy constructor for example). On both compilers I use regularly anything that can change the size of a string can throw as they all call new.

The resource contents are only copied once but you've got the overhead of constructing a string outside the function and then you assign over the top of it. It's like using an initialiser list - why not do all your object construction in one place?

Passing a destination reference doesn't make your code anymore usable in MBCS or UNICODE builds than mine is, unless I'm missing something...
GeneralHi, std::basic_string<>::assign() does NOT throw (or it is u... Pin
Alain Rist8-Jun-10 11:16
Alain Rist8-Jun-10 11:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.