Character Strings
See Also: Class CStr, Class WStr, Class FilterList.
This section presents information developers need to know when using character strings in 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.
The TSTR, _T and TCHAR Macros
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's 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
#define TSTR WStr
#else
#define TSTR CStr
#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 and Class 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.
Standard String Functions from C
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.
The GetString() Function
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 the Advanced Topics section Globalization.
Summary of Rules for Using Strings
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. If all goes well, the internationalization/localization process will consist of only editing resources, not code. In fact, the French, Italian, Spanish, German, and Kanji versions of 3ds max all use the same code.
Miscellaneous String Functions
The following two functions are part of the 3ds max API and are useful for breaking up filenames.
Prototype:
void SplitFilename(TSTR& name,TSTR* p, TSTR* f, TSTR* e);
Remarks:
Splits filename name into its path, filename, and extension.
Parameters:
TSTR& name
The filename to split apart.
TSTR* p
The path portion.
TSTR* f
The filename portion.
TSTR* e
The filename extension portion.
Prototype:
void SplitPathFile(TSTR& name,TSTR* p, TSTR* f);
Remarks:
Splits filename name into its path and a filename.extension.
Parameters:
TSTR& name
The filename to split apart.
TSTR* p
The path portion.
TSTR* f
The filename AND extension portion.
Prototype:
BOOL MatchPattern(TSTR &s, TSTR &ptrn, BOOL ignoreCase=TRUE);
Remarks:
This function is available in release 2.0 and later only.
This method is used to check if a string matches a wildcard pattern.
Parameters:
TSTR &s
The string to check.
TSTR &ptrn
The wildcard pattern. The * character matches 1 more characters. The ? character matches a single character.
BOOL ignoreCase=TRUE
If TRUE the check is not case sensitive; otherwise it is case sensitive.
Return Value:
TRUE if the string matches the pattern; otherwise FALSE.
Prototype:
int MaxAlphaNumComp(TCHAR *a, TCHAR *b);
Remarks:
This function is available in release 2.0 and later only.
A "smart" alphanumeric compare that sorts things so that numerical suffixes come out in numerical order. This version is case sensetive.
Parameters:
TCHAR *a
The first string to compare.
TCHAR *b
The second string to compare.
Return Value:
< 0 means string a is less than string b.
= 0 means that string a is identical to string b.
> 0 means that string a is greater than string b.
Prototype:
int MaxAlphaNumCompI(TCHAR *a, TCHAR *b);
Remarks:
This function is available in release 2.0 and later only.
A "smart" alphanumeric compare that sorts things so that numerical suffixes come out in numerical order. This version is case insensitive.
Parameters:
TCHAR *a
The first string to compare.
TCHAR *b
The second string to compare.
Return Value:
< 0 means string a is less than string b.
= 0 means that string a is identical to string b.
> 0 means that string a is greater than string b.