Globalization
See Also: Character Strings.
3D Studio is sold in numerous countries outside the United States. To allow your plug-in to have the largest possible audience, it is a good practice to create a globalized application. This means the language-specific strings used in the plug-in can be easily translated to another language.
To accomplish this, you should separate out all your language specific strings into a separate resource-only DLL. In this way, only the resource DLL, and not the rest of the code, needs to be changed to move the application to another language.
The basic concepts involved in creating and using a resource-only DLL are simple:
Create a VC++ project that builds a separate DLL containing only the resources of the plug-in.
When your plug-in begins execution, in the DllMain() function, attempt to load the resource DLL. This is done by calling a function of the Windows API LoadLibraryEx(). This maps the specified executable module into the address space of the calling process, making the strings accessible to the plug-in.
After the resource DLL has been loaded and you need to use a string, use the Window function LoadString(). This loads the string from the resource DLL and copies it into a local string buffer. The local string is then used as usual.
Release the resource DLL when the plug-in is finished executing. This may be done using the Windows FreeLibrary() function. Call this from the DLL_PROCESS_DETACH case of the DllMain() function. This decrements the reference count of the loaded DLL module. When the reference count reaches zero, the module is unmapped from the address space of the calling process.
The sample code below demonstrates how this is done. It shows two functions from the EPS file format I/O module.
The first function is DLLMain(). Note the use of LoadLibraryEx() and FreeLibrary(). Also see how GetModuleFileName() is used to find the location of the DLL (placed in the same directory as the plug-in). For details on these functions see the Windows API on-line help.
#define MAX_PATH_LENGTH 257
#define MAX_STRING_LENGTH 256
int triedToLoad = FALSE;
int resourcesLoaded = FALSE;
HINSTANCE hResource = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL,
ULONG fdwReason,LPVOID lpvReserved)
{
// If we have already tried to load the resource
// file and failed just give up.
if (triedToLoad && ! resourcesLoaded)
return FALSE;
// Load our resources. We look for the file in the
// same directory where this DLL was found
if (! resourcesLoaded) {
// Where this DLL resides
char dirName[MAX_PATH_LENGTH];
// Full path name to resource DLL
char dllName[MAX_PATH_LENGTH];
char *chPtr;
GetModuleFileName (hinstDLL, dirName, MAX_PATH_LENGTH);
// Strip off the file name
chPtr = dirName + strlen (dirName);
while (*(--chPtr) != '\\')
;
*(chPtr+1) = 0;
// Add in "epsres.dll"
strcpy (dllName, dirName);
strcat (dllName, "epsres.dll");
// Load resource DLL
// Turn off error reporting
int errorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
hResource = LoadLibraryEx(dllName, NULL, 0);
SetErrorMode(errorMode);
// Be sure to check to see if we succeeded
// loading resource DLL
if (hResource) {
resourcesLoaded = TRUE;
InitCustomControls (hResource);
} else {
triedToLoad = TRUE;
MessageBox (NULL,
"EPS Plugin failed to load due to missing resource file EPSRES.DLL",
"EPS", MB_ICONINFORMATION);
return FALSE;
}
}
switch(fdwReason) {
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
if (hResource)
FreeLibrary (hResource);
break;
}
return(TRUE);
}
To load and use one of the strings from the resource DLL, follow the approach shown below:
const TCHAR *EPSClassDesc::ClassName () {
static int loaded = 0;
static TCHAR stringBuf[MAX_STRING_LENGTH];
if (! loaded) {
LoadString (hResource, IDS_CLASS_NAME, stringBuf,
MAX_STRING_LENGTH);
loaded = 1;
}
return stringBuf;
}
In summary, it is a good development practice to separate the literal strings of a plug-in into a separate resource-only DLL. This creates a globalized application with the potential to reach the largest possible audience. For additional information on the plug-in functions shown above (DLLMain() and ClassName()) see the Advanced Topics section DLL Functions and Class Descriptors.