This section presents information developers need to know when using character strings in 3ds Max. It discusses the meaning of the TSTR
, \_T
, and TCHAR
macros that are commonly seen in the source code examples. This section also covers important substitutes for the standard C str
* functions, and some general functions that are available for use with character strings.
When 3ds Max was designed there was originally the possibility of using UNICODE for the storage of character strings. During development it was decided that 3ds Max would use MBCS (multi-byte character sets) instead. To provide the flexibility to switch between the two (perhaps some day to make it possible to also support UNICODE once it is fully supported under Windows NT), a macro is used to substitute either wide character strings (UNICODE) or single character strings (MBCS). This macro is TSTR
. Its definition is shown below:
#ifdef _UNICODE
#defineTSTRWStr
#else
#defineTSTRCStr
#endif
If UNICODE is in use, the macro is defined to mean Class``WStr
. If UNICODE is not in use, Class``CStr
is used. As mentioned above, the decision was made to not go with UNICODE, and thus TSTR
is equivalent to CStr
.
Class
WStr
is used for wide character strings (16 bits per character). Class``CStr
is for single and double-byte character sets. DBCS may need 2 bytes to represent a single character, whereas UNICODE always uses two bytes per character. Note: Windows code often refers to "MBCS", but in reality, the only multi-byte type supported is "double-byte". I.e. Windows doesn't support any character sets that need 3 bytes for some characters.
Both Cstr
and WStr
provide methods and operators for calculating lengths, concatenation, sub-string operations, character searching, case conversion, comparison, and formatted writing. For additional information on these classes see Class CStr
andClass WStr
.
Developers are encouraged to use the TSTR
macro for string definitions, rather than going straight to CStr
. In this way if a future version of 3ds Max is developed that uses UNICODE, the text definitions will convert with a simple re-compile.
Developers will also encounter the \_T
macro in the source code examples. Literal string definitions use \_T
preceding the string, for example \_T
("Parameters"). This macro is defined in a Microsoft include file \\MSDEV
\INCLUDE\TCHAR.H. This macro will convert a string to the proper form for either UNICODE or non-UNICODE. In general, any code that is written for internationalization should use the \_T
macro for literal string definitions.
A developer may also encounter the TCHAR
macro in the source code. This macro will be either a char
(8 bit) or a wchar_t
(16 bit UNICODE char) depending if UNICODE is in use.
The proper way to deal with strings (other than the methods of the CStr
and WStr
classes) is to use the \_t
version of the standard string functions. Because 3ds Max uses MCBS (multi-byte character sets), the \_t
versions sometimes map to functions other than the traditional str
* ones (which are only guaranteed to work with single-byte character sets). Below is a list of several common mappings from the standard Microsoft VC++ include file (usually \\MSDEV
\INCLUDE\TCHAR.H).
strcat maps to _tcscat
strcpy maps to _tcscpy
strlen maps to _tcslen
sprintf maps to _stprintf
sscanf maps to _stscanf
For example, instead of using the standard C strcpy
function, use the one shown below:
TCHAR buf[64];
_tcscpy(buf, _T("[ 0, 0, 0 ]"));
Developers who need to use the standard C string functions in their 3ds Max code should refer to \\MSDEV
\INCLUDE\TCHAR.H to see if there is a \_t
version of the string function defined for use.
Developers may also see the GetString()
functions used in the sample source code. This function is simply used to return a string from a resource library. It is defined as follows:
TCHAR *GetString(int id)
{
static TCHAR buf[256];
if (hInstance)
return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL;
return NULL;
}
This function is used so that the 3ds Max program can be easily translated into other non-English languages. By loading the strings from a resource table, only the resource string table has to be updated to allow the user interface of 3ds Max to appear translated into another language. For more details on using resource libraries, see Facilitating Translation and Localization.
The following rules summarize what developers need to be aware of when working with characters strings.
Use the TSTR
string class as much as possible, since these strings automatically allocate the right amount of memory for their storage. (As an added bonus, they're also a lot easier to use than standard strings, because a lot of functionality is built into the string class.)
If you have to use static character arrays, make sure the array allocation is adequate. Also, make sure that system limits (like 259 for path+filename) are always met or exceeded.
Don't use char
or w_char
arrays: instead use TCHAR
as the character type.
Don't use any standard string manipulation functions (like strcat
, strcpy
, sprintf
, etc.) directly. Rather, use the character-set independent versions found in \\MSDEV
\INCLUDE\TCHAR.H. For example, use \_tcscat
instead of strcat
. Note that even routines like fopen()
that take a string have character-set independent versions in TCHAR
.H.
Put all literal strings inside the \_T
macro, as in \_T
("This is literal"). The \_T
macro will convert strings to Unicode automatically if we ever choose to compile with that enabled.
When comparing characters, use the same macro as for strings but with single quotes. Also, if for any reason you are comparing with a slash for directory separation, make sure to also check for forward slashes as they are valid in NT and used when mounting Unix drives. For example:
if (my_path[x] == _T('/') || my_path[x] == _T('\')) {
// do something...
}
For internationalization / localization consider the following when working with strings:
Try to avoid any string-specific manipulation (like keying off of the first letter in a string, or concatenating strings to form a longer token), since much of this won't translate easily into other languages.
Keep all literal strings in a resource string table. This allows the internationalization/localization process to consist of only editing resource files, not code.
The following functions are part of the 3ds Max SDK and are useful for breaking up filenames.
SplitFilename()
- Splits filename name
into its path, filename, and extension.SplitPathFile()
- Splits filename name
into its path and a filename.extension.MatchPattern()
- This method is used to check if a string matches a wildcard pattern.MaxAlphaNumComp()
- A "smart" alphanumeric compare that sorts things so that numerical suffixes come out in numerical order. This version is case sensetive.MaxAlphaNumCompI()
- A case insensitive "smart" alphanumeric compare that sorts things so that numerical suffixes come out in numerical order. This version is case insensitive.