├── .gitignore ├── CStdString.h ├── LICENSE ├── README.md ├── TODO.md ├── original ├── StdString_demo.zip ├── StdString_src.zip ├── TestString │ ├── Script2.rc │ ├── StdAfx.cpp │ ├── StdAfx.h │ ├── StdString.h │ ├── TestString.cpp │ ├── TestString.dsp │ ├── TestString.dsw │ └── resource.h └── stdstring.h └── test ├── TestString.cpp ├── build-test-gcc.cmd ├── build-test-gcc.sh ├── build-test-msvc.cmd ├── resource.h └── restest.rc /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled object and resource files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | *.res 10 | 11 | # Precompiled headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | # Misc. junk: 36 | tmp/ 37 | a.exe.stackdump 38 | -------------------------------------------------------------------------------- /CStdString.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xparq/CStdString/7faf556e132de65c0f7418dcb248c62041c472e0/CStdString.h -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | COPYRIGHT (copied verbatim from the original header): 2 | 3 | 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you 4 | want. Rewrite it, restructure it, whatever. If you can write software 5 | that makes money off of it, good for you. I kinda like capitalism. 6 | Please don't blame me if it causes your $30 billion dollar satellite 7 | explode in orbit. If you redistribute it in any form, I'd appreciate it 8 | if you would leave this notice here. 9 | 10 | 11 | More formally: 12 | ----------------------------------------------------------------------- 13 | This is free and unencumbered software released into the public domain. 14 | 15 | Anyone is free to copy, modify, publish, use, compile, sell, or 16 | distribute this software, either in source code form or as a compiled 17 | binary, for any purpose, commercial or non-commercial, and by any 18 | means. 19 | 20 | In jurisdictions that recognize copyright laws, the author or authors 21 | of this software dedicate any and all copyright interest in the 22 | software to the public domain. We make this dedication for the benefit 23 | of the public at large and to the detriment of our heirs and 24 | successors. We intend this dedication to be an overt act of 25 | relinquishment in perpetuity of all present and future rights to this 26 | software under copyright law. 27 | 28 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 31 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 32 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 33 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 34 | OTHER DEALINGS IN THE SOFTWARE. 35 | 36 | For more information, please refer to 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CStdString 2 | Joe O'Leary's excellent (20-year-old...) drop-in replacement for MFC's CString, facelifted for contemporary C++. 3 | 4 | ## USAGE: 5 | 6 | Just copy `CStdString.h` to a suitable place in your project, and: 7 | 8 | #include "CStdString.h" 9 | typedef CStdString CString; // CStdStringA, CStdStringW, CStdStringO are also available 10 | 11 | ## NOTE: 12 | 13 | * Based on std::basic_string. 14 | 15 | * The `original` folder is just the unpacked zip files published in Joe's 2011 [CodeProject article](https://www.codeproject.com/Articles/1146/CString-clone-Using-Standard-C) 16 | (see below), added for easier browsing. It no longer compiles with any recent compiler. 17 | (That's the reason of this facelifting project.) 18 | 19 | * The updated version of the original `stdstring.h` is renamed to `CStdString.h` here. 20 | 21 | * It has been test-compiled (building Joe's original simple test app) with MSVC 16.1 (Visual Studio 2019), 22 | both with and without `UNICODE` (and `_UNICODE`), both for `c++14` and `c++17`, even `c++latest` 23 | (c++20 preview), with/without debug, and with/wo. SS_NO_LOCALE. Compiles cleanly with `-W4`. 24 | 25 | * GCC support has also been restored: my 9.1.0 (MSYS2) compiles cleanly with `-Wall -pedantic -Wextra` 26 | in all the same cases as MSVC. (No other GCC setup was tested yet!) 27 | 28 | * It has been successfully integrated into [my fork of Notepad++](https://github.com/lunakid/notepad-plusplus-gilded), 29 | replacing the original `CString` class there. (Builds fine, but not explicitly tested for 30 | actually correct functionality!) 31 | 32 | * **WARNING:** NO OTHER TESTS have been performed, so there may very well be unfixed deprecations, 33 | subtle (or gross...) inconsistencies, and even brand new, exciting & adventurous regressions. 34 | 35 | - Indeed, I've actually spent a full day chasing a segfault with GCC, when forcing the `SS_WIN32` 36 | cfg. define on it. (The issue still remains, but can be easily avoided: just let `CStdString.h` 37 | define it as it sees fit.) 38 | 39 | - Also, there's a locale/codecvt-related assertion failure I saw (in the `StdCodeCvt` functions, 40 | due to `conv.in()` failing), which I haven't investigated. 41 | 42 | Fixes may come on-demand, but note: this is pretty much obsolete legacy code, kept alive only for 43 | replacing even more obsolete legacy code, and its primarily purpose is to aid transition/migration 44 | *away from* old code-bases to things that no longer need the CString class. 45 | 46 | * The links to Joe's old sites in the original header and the article are dead, so the unit tests 47 | he seems to refer to occasionally, could not be recovered. (Could find his site at the Wayback 48 | Machine (see link near EOF!), but, alas, the tests were nowhere to be found.) 49 | 50 | * He did have *yet another* `CString` replacement (`CW32String`), though, which is completely standalone, 51 | doesn't need anything from the C runtime, just the Win32 API. Wayback Machine link to the old 52 | Projects page: http://web.archive.org/web/20060203010951/http://home.earthlink.net/~jmoleary/projects.htm. 53 | 54 | 55 | ### A copy of Joe's CodeProject article: 56 | 57 | ----------------------------------------------------------------------------- 58 | # CString-clone Using Standard C++ 59 | Joe O'Leary, 7 Dec 2011 60 | 61 | A Drop-In replacement for CString that builds on the Standard C++ Library's basic_string template 62 | 63 | -> Download *[HIS ORIGINAL!]* [source files - 33.5 KB](https://raw.githubusercontent.com/lunakid/CStdString/master/original/StdString_src.zip) 64 | 65 | -> Download *[HIS ORIGINAL!]* [demo project - 27.8 KB](https://raw.githubusercontent.com/lunakid/CStdString/master/original/StdString_demo.zip) 66 | 67 | ## Introduction 68 | 69 | As much as I use and appreciate the Standard C++ Library, I've never liked its string template - basic_string<>. At times, it seems the designers went out of their way to make it difficult to use. 70 | 71 | On the other hand, I've always loved the ease of use of MFC's CString class. It checks for NULL pointers, implicitly converts to const TCHAR*, and has some very handy member functions (Format, Load, etc.) that make string programming a breeze. But of course, I don't want to use MFC anymore. In fact, I don't want to rely on any proprietary library because I want portability. 72 | 73 | Therefore I decided to combine the best of both worlds and create: 74 | 75 | ## CStdString 76 | 77 | This is a class (a template instantiation actually) that derives from from basic_string. To the basic_string it adds the entire CString API. You get CString ease of use with 100% basic_string compatibility. In short, a CStdString object is a basic_string that (with very few exceptions (noted below) it is also a drop-in replacement for CString. The best part of this is that both APIs (basic_string and CString) are well known and well documented. 78 | 79 | I originally submitted this article to another code site (which shall remain nameless :)) a few years ago. I like CodeProject so much I thought I'd submit it here too. I have used this class in almost every professional project I've done over the past 4 years. It has proven to be the single most useful piece of code I've ever written. It is also extensively debugged. I hope you like it. If you ever have any problems with it, please e-mail me. I'm happy to help. 80 | 81 | I provided a simple source application here to prove some of the CString functions work but it's really just a token. The list of sample projects out there that use CString and/or basic_string is massive. 82 | 83 | ## Features 84 | 85 | Drop in Replacement for CString (see below for exceptions) 86 | Two instantiations available at all times -- wchar_t-based version CStdStringW and char-based version CStdStringA. The name CStdString is just a typedef of one of these two. 87 | Safely checks for NULL string pointer inputs (like CString) in all functions 88 | Extra constructors and assignment operators to automatically convert between wide (wchar_t-based) and thin (char-based) strings for you. 89 | Implicit conversion to c_str(). The C++ committee doesn't like this but I sure do. 90 | Builds on several platforms, including Windows, Unix and Linux. Works with several implementations of the Standard C++ Library, including Dinkumware, GNU, CodeWarrior, and STLPort. 91 | Win32 builds give you some extra goodies like UNICODE/MBCS conversion macros (just like MFCs) as well as member functions for persisting CStdString objects to and from DCOM IStreams. 92 | Makes no use of any implementation details of the base class template (basic_string) 93 | The derived template adds no member data to basic_string and adds no virtual functions 94 | There are a couple of issues about this code of that I should point out. 95 | 96 | ## CString Compatibility 97 | 98 | I was unable to exactly reproduce the CString API. There are a two functions that both CString and basic_string; share, but implement differently. In these cases, I felt it best to make CStdString behave like basic_string (the base class) rather than CString. To be specific. 99 | 100 | CStdString::operator[] returns characters by value (unlike CString which returns them by reference) 101 | The constructor that takes a character and a count takes them in the order (count, value) which is the opposite of the order CString declares them. That's the order that basic_string<>; needs and it was impossible to implement both versions. 102 | There were also two CString functions I could not implement at all -- LockBuffer and UnlockBuffer. 103 | 104 | ## Deriving From basic_string<> 105 | 106 | The template I wrote derives from basic_string, a class template without a virtual destructor. Any introductory text to C++ will tell you that it is dangerous to derive from a class without a virtual destructor. It can lead to behavior that is undefined. So if you were to code the following (deleting a CStdStringA through a pointer to the base class), you would technically get undefined behavior: 107 | 108 | // assign DERIVED object to BASE pointer 109 | std::string* pstr = new CStdStringA("Hi"); 110 | 111 | // delete DERIVED through BASE class pointer -- UNDEFINED 112 | delete pstr; 113 | Personally, I don't think this is much of an issue. I mean really how often do you actually do this with string objects? I have rarely (if ever) needed to dynamically allocate a string object on the heap. And if I ever do, I won't using a base-class pointer. So if you don't do this, you'll never have to worry. In fact, even if you do code this way, I doubt you'll have any problems with CStdString. I can tell you that at least with Microsoft Visual C++, even the above code runs just fine with no errors or memory leaks. I doubt many other compilers would give you problems either. However my doubt does not impose reality on the C++ world. Caveat Emptor. 114 | 115 | -------------------- 116 | ## History 117 | 7 Dec 2011: Updated source code. 118 | 119 | -------------------- 120 | ## License 121 | This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) 122 | 123 | --------------------- 124 | ## About the Author 125 | 126 | Joe O'Leary - Web Developer, United States 127 | 128 | I've been a software developer since 1990. 129 | 130 | While my main page is out of date (and I have therefore blanked it), 131 | you can read about the CStdString pages here 132 | 133 | http://home.earthlink.net/~jmoleary/stdstring.htm [<-- *DEAD LINK!* But the Internet Archive has 134 | snapshots; this looks like the latest version: http://web.archive.org/web/20060207090333/http://home.earthlink.net/~jmoleary/stdstring.htm] 135 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ! GCC won't compile it, if Windows.h is not included before CStdString.h. 2 | Maybe that's OK, but MSVC does that without a hitch. 3 | 4 | !![SS_WIN32-gcc-crash] Segfault with gcc... 5 | 6 | (It's not the cout/wchar misuse, that's just the likely reason of garbled output. 7 | When commented out, it still crashed.) 8 | 9 | -> All these with Windows.h being included first (GCC currently won't compile otherwise.) 10 | "no SS_WIN32" means it's not *explicitly* defined before including SS: 11 | 12 | Explicitly defining SS_WIN32 seems to trigger the crash, EVEN IF Windows.h is 13 | *included BEFORE* CStdString.h, even though that should render SS_WIN32 redundant. 14 | (And the trivial suspicion that it may use something depending on SS_WIN32 *before* 15 | its auto-enbling logic kicks in, proved to be a dead-end.) 16 | 17 | 18 | no SS_WIN32, no SS_NO_LOCALE, UNICODE ASSERT fail: ~878, NO output 19 | no SS_WIN32, no SS_NO_LOCALE, no UNICODE OK! (output OK, no crash) 20 | no SS_WIN32, SS_NO_LOCALE, UNICODE debug-out: Format() GARBLED, cout: pointers, no crash 21 | no SS_WIN32, SS_NO_LOCALE, no UNICODE OK! (output OK, no crash) 22 | 23 | SS_WIN32, no SS_NO_LOCALE, UNICODE ASSERT fail: ~878 24 | SS_WIN32, no SS_NO_LOCALE, no UNICODE !!CRASH!! 25 | SS_WIN32, SS_NO_LOCALE, UNICODE !!CRASH!!, out: Format() GARBLED 26 | SS_WIN32, SS_NO_LOCALE, no UNICODE !!CRASH!!, output OK 27 | 28 | - "Garbled" output means that e.g. the Format()ed test output is wrong: 29 | Instead of: "This is a *FORMATTED* string, with a num. param: 123", 30 | it shows: "This is a * string, with a num. param: 123". 31 | 32 | - NO CRASH, if: 33 | 34 | 1. CStdString.h is included BEFORE Windows.h 35 | 36 | 2. SS_WIN32 is NOT defined! 37 | Note: if defined, albeit looks redundant, it DOES trigger the crash, 38 | BUT now the formatter output IS CORRECT!... 39 | 40 | Anyway, since I can't reproduce that crash with MSVC, or with SS_WIN32 *not* 41 | defined, I have to conclude for now, that the problem lies somewhere near the 42 | fact that my MSYS2/MinGW is not a proper Win32 env: GCC there doesn't even 43 | define __MINGW64__ or __MINGW64__ (why?! I only saw __MSYS__). 44 | 45 | ! Assertion fails in the VS build with locales (i.e. without SS_NO_LOCALE): 46 | line ~878: ASSERT(SSCodeCvt::ok == res); 47 | 48 | + GCC build falters spectacularly on SS_NO_LOCALE. (MSVC's happy.) 49 | Fixed. 50 | 51 | * No cout << op. support in unicode mode?! (It just dumps the pointer.) 52 | 53 | * The gcc build fails with SS_NO_LOCALE, without SS_WIN32 (i.e. when 54 | Windows.h is not included beforehand, or SS_WIN32 is not explicitly 55 | defined). 56 | -------------------------------------------------------------------------------- /original/StdString_demo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xparq/CStdString/7faf556e132de65c0f7418dcb248c62041c472e0/original/StdString_demo.zip -------------------------------------------------------------------------------- /original/StdString_src.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xparq/CStdString/7faf556e132de65c0f7418dcb248c62041c472e0/original/StdString_src.zip -------------------------------------------------------------------------------- /original/TestString/Script2.rc: -------------------------------------------------------------------------------- 1 | //Microsoft Developer Studio generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include "afxres.h" 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (U.S.) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 19 | #ifdef _WIN32 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | #pragma code_page(1252) 22 | #endif //_WIN32 23 | 24 | #ifdef APSTUDIO_INVOKED 25 | ///////////////////////////////////////////////////////////////////////////// 26 | // 27 | // TEXTINCLUDE 28 | // 29 | 30 | 1 TEXTINCLUDE DISCARDABLE 31 | BEGIN 32 | "resource.h\0" 33 | END 34 | 35 | 2 TEXTINCLUDE DISCARDABLE 36 | BEGIN 37 | "#include ""afxres.h""\r\n" 38 | "\0" 39 | END 40 | 41 | 3 TEXTINCLUDE DISCARDABLE 42 | BEGIN 43 | "\r\n" 44 | "\0" 45 | END 46 | 47 | #endif // APSTUDIO_INVOKED 48 | 49 | 50 | ///////////////////////////////////////////////////////////////////////////// 51 | // 52 | // String Table 53 | // 54 | 55 | STRINGTABLE DISCARDABLE 56 | BEGIN 57 | IDS_STRING1 "All your base are belong to us!" 58 | IDS_STRING2 "I see dead people" 59 | END 60 | 61 | #endif // English (U.S.) resources 62 | ///////////////////////////////////////////////////////////////////////////// 63 | 64 | 65 | 66 | #ifndef APSTUDIO_INVOKED 67 | ///////////////////////////////////////////////////////////////////////////// 68 | // 69 | // Generated from the TEXTINCLUDE 3 resource. 70 | // 71 | 72 | 73 | ///////////////////////////////////////////////////////////////////////////// 74 | #endif // not APSTUDIO_INVOKED 75 | 76 | -------------------------------------------------------------------------------- /original/TestString/StdAfx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // TestString.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /original/TestString/StdAfx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #if !defined(AFX_STDAFX_H__6A224A0B_7769_4B7A_AE2C_444918A23E26__INCLUDED_) 7 | #define AFX_STDAFX_H__6A224A0B_7769_4B7A_AE2C_444918A23E26__INCLUDED_ 8 | 9 | #if _MSC_VER > 1000 10 | #pragma once 11 | #endif // _MSC_VER > 1000 12 | 13 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 14 | 15 | // Turn off some common warnings that are generated en-masse 16 | // by the Microsoft STL implementation headers. 17 | 18 | #pragma warning ( disable : 4018 ) // signed/unsigned mismatch 19 | //#pragma warning ( disable : 4097 ) // typedef name used as synonym for class name 20 | #pragma warning ( disable : 4100 ) // unreferenced formal parameter 21 | //#pragma warning ( disable : C4146 ) // unary minus operator applied to unsigned type, result still unsigned 22 | #pragma warning ( disable : 4211 ) // nonstandard extension used : redefined extern as static 23 | #pragma warning ( disable : 4244 ) // conversion from A to B, possible loss of data 24 | #pragma warning ( disable : 4245 ) // initializing conversion signed/unsigned mismatch 25 | #pragma warning ( disable : 4251 ) // class needs to have dll-interface to be used by clients of class 26 | #pragma warning ( disable : 4310 ) // cast truncates constant value (comutil.h gives this one a lot). 27 | #pragma warning ( disable : 4511 ) // private constructors are OK 28 | #pragma warning ( disable : 4512 ) // private operator=() are OK 29 | #pragma warning ( disable : 4663 ) // C++ Language change -- new syntax for explicit specialization of templates. 30 | #pragma warning ( disable : 4786 ) // symbolic name too long : truncated to 255 characters 31 | #pragma warning ( disable : 4290 ) // C++ Exception Specification ignored 32 | 33 | 34 | // TODO: reference additional headers your program requires here 35 | 36 | //{{AFX_INSERT_LOCATION}} 37 | // Microsoft Visual C++ will insert additional declarations immediately before the previous line. 38 | 39 | #endif // !defined(AFX_STDAFX_H__6A224A0B_7769_4B7A_AE2C_444918A23E26__INCLUDED_) 40 | -------------------------------------------------------------------------------- /original/TestString/StdString.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xparq/CStdString/7faf556e132de65c0f7418dcb248c62041c472e0/original/TestString/StdString.h -------------------------------------------------------------------------------- /original/TestString/TestString.cpp: -------------------------------------------------------------------------------- 1 | // TestString.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "StdString.h" 6 | #include 7 | #include "resource.h" 8 | 9 | int main(int argc, char* argv[]) 10 | { 11 | // You can add just about any form of string to a CStdString 12 | // with operator+() 13 | CStdString strVal1(_T("THIS IS A STRING ")); 14 | OutputDebugString(strVal1 + _T("\n")); 15 | strVal1 += _bstr_t(" plus a BSTR string"); 16 | strVal1 += '.' ; 17 | 18 | // Some conversion functions can be chained together 19 | 20 | strVal1.ToLower().TrimRight(); 21 | 22 | // Case INsensitive comparison via Equals() or CompareNoCase() 23 | 24 | strVal1 = _T("THIS IS A STRING"); 25 | CStdString strVal2(_T("thIs Is a sTRing")); 26 | _ASSERTE(strVal1 != strVal2); 27 | _ASSERTE(strVal1.Equals(strVal2)); 28 | _ASSERTE(strVal1.CompareNoCase(strVal2) == 0); 29 | 30 | // Format() works just like CString's 31 | 32 | strVal1.Format(_T("This %s a string named strVal%d"), _T("IS"), 1); 33 | OutputDebugString(strVal1 + _T("\n")); 34 | 35 | // Declare an STL map class which maps strings to integers. The 36 | // keys are case insensitive, so an integer stored under the key 37 | // _T("MYKEY") could be retrieved with the value _T("mykey") 38 | 39 | typedef std::map CMyMap; 40 | CMyMap myMap; 41 | myMap[_T("MYKEY")] = 7; 42 | _ASSERTE(myMap.find(_T("mykey")) != myMap.end()); 43 | 44 | 45 | // If we were calling some windows function that fills out a 46 | // buffer for us we can use the GetBuffer() function. . 47 | 48 | CStdString strPath; 49 | ::GetTempPath( MAX_PATH, strPath.GetBuffer(MAX_PATH+1)); 50 | strPath.ReleaseBuffer(); 51 | 52 | // You can set the resource handle for loading string resources 53 | // and then load them via either the constructor or the Load() 54 | // function. 55 | 56 | CStdString::SetResourceHandle(::GetModuleHandle(NULL)); 57 | CStdString strString(MAKEINTRESOURCE(IDS_STRING1)); 58 | _ASSERTE(_T("All your base are belong to us!") == strString); 59 | 60 | strString.Load(IDS_STRING2); 61 | _ASSERTE(_T("I see dead people") == strString); 62 | return 0; 63 | } 64 | 65 | /* 66 | // If this were MFC code, we could serialize the strings to CArchives: 67 | 68 | void CMyObject::Serialize(CArchive& ar) 69 | { 70 | CStdString strVal3(_T("This is a string")); 71 | if ( ar.IsStoring() ) 72 | ar << strVal; 73 | else 74 | ar >> strVal; 75 | } 76 | 77 | // If we were implementing the IPersistStream interface on a COM 78 | // object which had a member CStdString variable named 'm_strVal', 79 | // we could take advantage of the CStdString stream functions to 80 | // greatly simplify the implementation as follows: 81 | 82 | HRESULT CMyComObject::GetSizeMax(ULARGE_INTEGER* pcbSizeMax) 83 | { 84 | pcbSizeMax->QuadPart = m_strVal.StreamSize(); 85 | return S_OK; 86 | } 87 | HRESULT CMyComObject::Save(IStream* pStream, BOOL bClearDirty) 88 | { 89 | return m_strVal.StreamSave(pStream); 90 | } 91 | HRESULT CMyComObject::Load(IStream* pStream) 92 | { 93 | return m_strVal.StreamLoad(pStream); 94 | } 95 | 96 | */ -------------------------------------------------------------------------------- /original/TestString/TestString.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="TestString" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=TestString - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "TestString.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "TestString.mak" CFG="TestString - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "TestString - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "TestString - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "TestString - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Target_Dir "" 43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c 44 | # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c 45 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 46 | # ADD RSC /l 0x409 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LINK32=link.exe 51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | 54 | !ELSEIF "$(CFG)" == "TestString - Win32 Debug" 55 | 56 | # PROP BASE Use_MFC 0 57 | # PROP BASE Use_Debug_Libraries 1 58 | # PROP BASE Output_Dir "Debug" 59 | # PROP BASE Intermediate_Dir "Debug" 60 | # PROP BASE Target_Dir "" 61 | # PROP Use_MFC 0 62 | # PROP Use_Debug_Libraries 1 63 | # PROP Output_Dir "Debug" 64 | # PROP Intermediate_Dir "Debug" 65 | # PROP Target_Dir "" 66 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c 67 | # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /Yu"stdafx.h" /FD /GZ /c 68 | # ADD BASE RSC /l 0x409 /d "_DEBUG" 69 | # ADD RSC /l 0x409 /d "_DEBUG" 70 | BSC32=bscmake.exe 71 | # ADD BASE BSC32 /nologo 72 | # ADD BSC32 /nologo 73 | LINK32=link.exe 74 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 75 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 76 | 77 | !ENDIF 78 | 79 | # Begin Target 80 | 81 | # Name "TestString - Win32 Release" 82 | # Name "TestString - Win32 Debug" 83 | # Begin Group "Source Files" 84 | 85 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 86 | # Begin Source File 87 | 88 | SOURCE=.\StdAfx.cpp 89 | # ADD CPP /Yc"stdafx.h" 90 | # End Source File 91 | # Begin Source File 92 | 93 | SOURCE=.\TestString.cpp 94 | # End Source File 95 | # End Group 96 | # Begin Group "Header Files" 97 | 98 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 99 | # Begin Source File 100 | 101 | SOURCE=.\StdAfx.h 102 | # End Source File 103 | # Begin Source File 104 | 105 | SOURCE=.\StdString.h 106 | # End Source File 107 | # End Group 108 | # Begin Group "Resource Files" 109 | 110 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 111 | # Begin Source File 112 | 113 | SOURCE=.\Script2.rc 114 | # End Source File 115 | # End Group 116 | # Begin Source File 117 | 118 | SOURCE=.\ReadMe.txt 119 | # End Source File 120 | # End Target 121 | # End Project 122 | -------------------------------------------------------------------------------- /original/TestString/TestString.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "TestString"=.\TestString.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /original/TestString/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Developer Studio generated include file. 3 | // Used by Script2.rc 4 | // 5 | #define IDS_STRING1 101 6 | #define IDS_STRING2 102 7 | 8 | // Next default values for new objects 9 | // 10 | #ifdef APSTUDIO_INVOKED 11 | #ifndef APSTUDIO_READONLY_SYMBOLS 12 | #define _APS_NEXT_RESOURCE_VALUE 103 13 | #define _APS_NEXT_COMMAND_VALUE 40001 14 | #define _APS_NEXT_CONTROL_VALUE 1000 15 | #define _APS_NEXT_SYMED_VALUE 103 16 | #endif 17 | #endif 18 | -------------------------------------------------------------------------------- /original/stdstring.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xparq/CStdString/7faf556e132de65c0f7418dcb248c62041c472e0/original/stdstring.h -------------------------------------------------------------------------------- /test/TestString.cpp: -------------------------------------------------------------------------------- 1 | //---------------------------------------------------------------------------- 2 | // Smoke-testing Joe's CStdString.h... 3 | // (Basically the same random stuff he left behind, but I've changed it quite 4 | // a bit, while debugging etc.) 5 | //---------------------------------------------------------------------------- 6 | 7 | //! Silence MSVC's infamous _vsnprintf warning... 8 | //! CStdString does it anyway, but it's too late if Windows.h is included first: 9 | //#define _CRT_SECURE_NO_WARNINGS 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | #include 12 | 13 | // For testing some win32-specific features (should be tested separately!) 14 | // BTW, this will be automatically enabled by CStdString.h if Windows.h 15 | // is included prior to it. 16 | //!! In fact, defining this here seems to trigger a segfault in GCC! :-o 17 | //!! See: [SS_WIN32-gcc-crash] 18 | //#define SS_WIN32 19 | #define SS_NO_LOCALE 20 | #include "../CStdString.h" 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | using std::cout; using std::wcout; // using ..., ...; would fail in c++14 27 | 28 | // Poor man's fallback _T() (see also: https://stackoverflow.com/a/15498147/1479945) 29 | #ifndef _T 30 | #ifdef TEXT 31 | #define _T(str) TEXT(str) 32 | #else 33 | #ifdef UNICODE 34 | #define _T(str) L ## str 35 | #else 36 | #define _T(str) TEXT(str) 37 | #endif 38 | #endif 39 | #endif 40 | 41 | #include "resource.h" 42 | 43 | //============================================================================ 44 | int main(int argc, char* argv[]) { argc, argv; // Silence pedantic warnings about these being unused... 45 | 46 | #ifdef __GNUC__ 47 | void segv_handler(int sig); 48 | signal(SIGSEGV, segv_handler); // https://stackoverflow.com/a/77336/1479945 49 | #endif 50 | 51 | // Just so I can check sometimes that the ASSERT macro really is on: 52 | //ASSERT(1 == 2); 53 | 54 | try { 55 | // You can add just about any form of string to a CStdString 56 | // with operator+() 57 | CStdString strVal1(_T("THIS IS A STRING ")); 58 | //!!Not available for my MSYS2/MinGW/gcc: 59 | //!!strVal1 += _bstr_t(" plus a BSTR string"); 60 | strVal1 += ' '; 61 | strVal1 += "And this is its tail."; 62 | OutputDebugString(strVal1 + _T(" [plus some temp. tail only for outputting it]\n")); 63 | cout << strVal1 + _T(" [plus some temp. tail only for outputting it]\n"); 64 | 65 | // Some conversion functions can be chained together 66 | 67 | strVal1.ToLower().TrimRight(); 68 | OutputDebugString(strVal1 + _T("\n")); 69 | cout << strVal1 + _T("\n"); 70 | 71 | // Case INsensitive comparison via Equals() or CompareNoCase() 72 | 73 | strVal1 = _T("THIS IS A STRING"); 74 | CStdString strVal2(_T("thIs Is a sTRing")); 75 | ASSERT(strVal1 != strVal2); 76 | ASSERT(strVal1.Equals(strVal2)); 77 | ASSERT(strVal1.CompareNoCase(strVal2) == 0); 78 | 79 | // Format() works just like CString's 80 | 81 | strVal1.Format(_T("This is a %s string, with a num. param: %d"), _T("*FORMATTED*"), 123); 82 | OutputDebugString(strVal1 + _T("\n")); 83 | cout << strVal1 + _T("\n"); 84 | 85 | // Declare an STL map class which maps strings to integers. The 86 | // keys are case insensitive, so an integer stored under the key 87 | // _T("MYKEY") could be retrieved with the value _T("mykey") 88 | 89 | typedef std::map CMyMap; 90 | CMyMap myMap; 91 | myMap[_T("MYKEY")] = 7; 92 | ASSERT(myMap.find(_T("mykey")) != myMap.end()); 93 | 94 | 95 | #ifdef SS_WIN32 96 | // If we were calling some windows function that fills out a 97 | // buffer for us we can use the GetBuffer() function. 98 | 99 | CStdString strPath; 100 | ::GetTempPath( MAX_PATH, strPath.GetBuffer(MAX_PATH+1)); 101 | strPath.ReleaseBuffer(); 102 | 103 | // You can set the resource handle for loading string resources 104 | // and then load them via either the constructor or the Load() 105 | // function. 106 | // These required SS_WIN32 to be #defined! 107 | CStdString::SetResourceHandle(::GetModuleHandle(NULL)); 108 | CStdString strString(MAKEINTRESOURCE(IDS_STRING1)); 109 | ASSERT(_T("All your base are belong to us!") == strString); 110 | 111 | strString.Load(IDS_STRING2); 112 | ASSERT(_T("I see dead people") == strString); 113 | #endif 114 | } catch (...) { 115 | cout << "OOPS!\n"; 116 | } 117 | 118 | } 119 | 120 | /* 121 | // If this were MFC code, we could serialize the strings to CArchives: 122 | 123 | void CMyObject::Serialize(CArchive& ar) 124 | { 125 | CStdString strVal3(_T("This is a string")); 126 | if ( ar.IsStoring() ) 127 | ar << strVal; 128 | else 129 | ar >> strVal; 130 | } 131 | 132 | // If we were implementing the IPersistStream interface on a COM 133 | // object which had a member CStdString variable named 'm_strVal', 134 | // we could take advantage of the CStdString stream functions to 135 | // greatly simplify the implementation as follows: 136 | 137 | HRESULT CMyComObject::GetSizeMax(ULARGE_INTEGER* pcbSizeMax) 138 | { 139 | pcbSizeMax->QuadPart = m_strVal.StreamSize(); 140 | return S_OK; 141 | } 142 | HRESULT CMyComObject::Save(IStream* pStream, BOOL bClearDirty) 143 | { 144 | return m_strVal.StreamSave(pStream); 145 | } 146 | HRESULT CMyComObject::Load(IStream* pStream) 147 | { 148 | return m_strVal.StreamLoad(pStream); 149 | } 150 | 151 | */ 152 | 153 | 154 | //------------------------------------------------------------------------------- 155 | //!! Aborted attempt to print a stack trace with MSYS2/MinGW... 156 | //!! (Found somewhere on SO, I guess, but couldn't adopt for the missing backtrace()) 157 | #ifdef __GNUC__ 158 | #include 159 | //#include //!!no backtrace() in MSYS2/MinGW?!... :-o :-/ 160 | #include 161 | #include 162 | #include 163 | void segv_handler(int sig) { 164 | //void *array[10]; 165 | // Get void*'s for all entries on the stack: 166 | //size_t size = backtrace(array, 10); 167 | // Print all the frames to stderr: 168 | fprintf(stderr, "Error: signal %d caught!\n", sig); 169 | //backtrace_symbols_fd(array, size, STDERR_FILENO); 170 | exit(-1); 171 | } 172 | #endif 173 | -------------------------------------------------------------------------------- /test/build-test-gcc.cmd: -------------------------------------------------------------------------------- 1 | :: Ignored with MSYS2: set CXXFLAGS=... 2 | 3 | if not x%1x==xx goto %1 4 | 5 | rem Disable warning "right/left operand of comma op. has no effect" for NDEBUG TRACE 6 | rem with -Wno-unused-value. 7 | 8 | :1 9 | g++ -std=c++14 -DUNICODE -D_UNICODE -Wall -pedantic -Wextra -Wno-unused-value TestString.cpp & if not x%1x==xx goto :eof 10 | :2 11 | g++ -std=c++17 -DUNICODE -g -D_UNICODE -Wall -pedantic -Wextra -Wno-unused-value TestString.cpp & if not x%1x==xx goto :eof 12 | 13 | :3 14 | g++ -std=c++14 -Wall -pedantic -Wextra -Wno-unused-value TestString.cpp & if not x%1x==xx goto :eof 15 | :4 16 | g++ -std=c++17 -Wall -g -pedantic -Wextra -Wno-unused-value TestString.cpp & if not x%1x==xx goto :eof 17 | -------------------------------------------------------------------------------- /test/build-test-gcc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Ignored with MSYS2: set CXXFLAGS=... 4 | 5 | # Disable warning "right/left operand of comma op. has no effect" for NDEBUG TRACE 6 | # with -Wno-unused-value! 7 | 8 | case "$1" in 9 | 10 | 1) 11 | g++ -std=c++14 -DUNICODE -D_UNICODE -Wall -pedantic -Wextra -Wno-unused-value TestString.cpp 12 | ;; 13 | 14 | 2) 15 | g++ -std=c++17 -DUNICODE -g -D_UNICODE -Wall -pedantic -Wextra -Wno-unused-value TestString.cpp 16 | ;; 17 | 18 | 3) 19 | g++ -std=c++14 -Wall -pedantic -Wextra -Wno-unused-value TestString.cpp 20 | ;; 21 | 22 | 4) 23 | g++ -std=c++17 -Wall -g -pedantic -Wextra -Wno-unused-value TestString.cpp 24 | ;; 25 | esac 26 | -------------------------------------------------------------------------------- /test/build-test-msvc.cmd: -------------------------------------------------------------------------------- 1 | rc restest.rc 2 | 3 | set CL=/nologo /EHsc /W4 4 | 5 | if not x%1x==xx goto %1 6 | 7 | rem Varying the /MT and /MD and ...d flags a bit, just to hopefully cover a wider base. :) 8 | 9 | :1 10 | cl /std:c++latest TestString.cpp restest.res & if not x%1x==xx goto :eof 11 | :2 12 | cl /std:c++latest /MD TestString.cpp restest.res & if not x%1x==xx goto :eof 13 | :3 14 | cl /std:c++latest /DUNICODE /D_UNICODE TestString.cpp restest.res & if not x%1x==xx goto :eof 15 | :4 16 | cl /std:c++latest /MT /DUNICODE /D_UNICODE TestString.cpp restest.res & if not x%1x==xx goto :eof 17 | 18 | :5 19 | cl /std:c++17 TestString.cpp restest.res & if not x%1x==xx goto :eof 20 | :6 21 | cl /std:c++17 /DUNICODE /D_UNICODE TestString.cpp restest.res & if not x%1x==xx goto :eof 22 | 23 | :7 24 | cl /std:c++14 /MDd TestString.cpp restest.res & if not x%1x==xx goto :eof 25 | :8 26 | cl /std:c++17 /MTd TestString.cpp restest.res & if not x%1x==xx goto :eof 27 | :9 28 | cl /std:c++latest /MDd TestString.cpp restest.res & if not x%1x==xx goto :eof 29 | 30 | :10 31 | cl /std:c++14 /MDd /DUNICODE /D_UNICODE TestString.cpp restest.res & if not x%1x==xx goto :eof 32 | :11 33 | cl /std:c++17 /MTd /DUNICODE /D_UNICODE TestString.cpp restest.res & if not x%1x==xx goto :eof 34 | :12 35 | cl /std:c++latest /MTd /DUNICODE /D_UNICODE TestString.cpp restest.res & if not x%1x==xx goto :eof 36 | -------------------------------------------------------------------------------- /test/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Developer Studio generated include file. 3 | // Used by Script2.rc 4 | // 5 | #define IDS_STRING1 101 6 | #define IDS_STRING2 102 7 | 8 | // Next default values for new objects 9 | // 10 | #ifdef APSTUDIO_INVOKED 11 | #ifndef APSTUDIO_READONLY_SYMBOLS 12 | #define _APS_NEXT_RESOURCE_VALUE 103 13 | #define _APS_NEXT_COMMAND_VALUE 40001 14 | #define _APS_NEXT_CONTROL_VALUE 1000 15 | #define _APS_NEXT_SYMED_VALUE 103 16 | #endif 17 | #endif 18 | -------------------------------------------------------------------------------- /test/restest.rc: -------------------------------------------------------------------------------- 1 | //Microsoft Developer Studio generated resource script. 2 | // 3 | #define WIN32_LEAN_AND_MEAN 4 | #include //!!https://mattshaw.org/news/fix-for-error-rc2144-primary-language-id-not-a-number/ 5 | #include "resource.h" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | //!!#include "afxres.h" 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | #undef APSTUDIO_READONLY_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | // English (U.S.) resources 19 | 20 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 21 | #ifdef _WIN32 22 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 23 | #pragma code_page(1252) 24 | #endif //_WIN32 25 | 26 | #ifdef APSTUDIO_INVOKED 27 | ///////////////////////////////////////////////////////////////////////////// 28 | // 29 | // TEXTINCLUDE 30 | // 31 | 32 | 1 TEXTINCLUDE DISCARDABLE 33 | BEGIN 34 | "resource.h\0" 35 | END 36 | 37 | //!!2 TEXTINCLUDE DISCARDABLE 38 | //!!BEGIN 39 | //!! "#include ""afxres.h""\r\n" 40 | //!! "\0" 41 | //!!END 42 | 43 | 2 TEXTINCLUDE DISCARDABLE 44 | BEGIN 45 | "\r\n" 46 | "\0" 47 | END 48 | 49 | #endif // APSTUDIO_INVOKED 50 | 51 | 52 | ///////////////////////////////////////////////////////////////////////////// 53 | // 54 | // String Table 55 | // 56 | 57 | STRINGTABLE DISCARDABLE 58 | BEGIN 59 | IDS_STRING1 "All your base are belong to us!" 60 | IDS_STRING2 "I see dead people" 61 | END 62 | 63 | #endif // English (U.S.) resources 64 | ///////////////////////////////////////////////////////////////////////////// 65 | 66 | 67 | 68 | #ifndef APSTUDIO_INVOKED 69 | ///////////////////////////////////////////////////////////////////////////// 70 | // 71 | // Generated from the TEXTINCLUDE 3 resource. 72 | // 73 | 74 | 75 | ///////////////////////////////////////////////////////////////////////////// 76 | #endif // not APSTUDIO_INVOKED 77 | --------------------------------------------------------------------------------