From 1191bcaf03ae005332f92a9f3b2665fc2fc631c4 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Thu, 20 Jul 2023 07:54:11 +0900 Subject: [PATCH] [ATL][ATL_APITEST] Add and atlconv testcase (#5449) - Add header file. - Add atlconv testcase to atl_apitest.exe. CORE-16668 --- modules/rostests/apitests/atl/CMakeLists.txt | 1 + modules/rostests/apitests/atl/atlconv.cpp | 218 +++++++++++ modules/rostests/apitests/atl/atltest.h | 2 +- .../rostests/apitests/atl/devenv/.gitignore | 4 + .../rostests/apitests/atl/devenv/ATLTest.sln | 10 + .../apitests/atl/devenv/atlconv.vcxproj | 154 ++++++++ modules/rostests/apitests/atl/testlist.c | 2 + sdk/lib/atl/atlconv.h | 348 ++++++++++++++++++ 8 files changed, 738 insertions(+), 1 deletion(-) create mode 100644 modules/rostests/apitests/atl/atlconv.cpp create mode 100644 modules/rostests/apitests/atl/devenv/atlconv.vcxproj create mode 100644 sdk/lib/atl/atlconv.h diff --git a/modules/rostests/apitests/atl/CMakeLists.txt b/modules/rostests/apitests/atl/CMakeLists.txt index dfaddd62b61..411c5ad068c 100644 --- a/modules/rostests/apitests/atl/CMakeLists.txt +++ b/modules/rostests/apitests/atl/CMakeLists.txt @@ -3,6 +3,7 @@ add_definitions(-DINITGUID -DWINETEST_USE_DBGSTR_LONGLONG) list(APPEND SOURCE AtlObjMap.cpp + atlconv.cpp atltypes.cpp CAtlFileMapping.cpp CAtlArray.cpp diff --git a/modules/rostests/apitests/atl/atlconv.cpp b/modules/rostests/apitests/atl/atlconv.cpp new file mode 100644 index 00000000000..96cbac21790 --- /dev/null +++ b/modules/rostests/apitests/atl/atlconv.cpp @@ -0,0 +1,218 @@ +/* + * PROJECT: ReactOS api tests + * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) + * PURPOSE: Test for + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#ifdef HAVE_APITEST + #include +#else + #include "atltest.h" +#endif +#include +#include + +START_TEST(atlconv) +{ + char dataA[MAX_PATH]; + wchar_t dataW[MAX_PATH]; + const char *dataAX = "test12345"; + const wchar_t *dataWX = L"test12345"; + using namespace ATL; + + // + // Initialize long data + // + FillMemory(dataA, sizeof(dataA), 'A'); + dataA[_countof(dataA) - 1] = 0; + + for (size_t i = 0; i < _countof(dataW); ++i) + dataW[i] = L'A'; + dataW[_countof(dataW) - 1] = 0; + + // + // The NULL strings + // + { + CA2A a2a(NULL); + ok_ptr((LPSTR)a2a, NULL); + ok_ptr(a2a.m_psz, NULL); + ok_int(a2a.m_szBuffer[0], 0); + + CW2A w2a(NULL); + ok_ptr((LPSTR)w2a, NULL); + ok_ptr(w2a.m_psz, NULL); + ok_int(w2a.m_szBuffer[0], 0); + + CA2W a2w(NULL); + ok_ptr((LPWSTR)a2w, NULL); + ok_ptr(a2w.m_psz, NULL); + ok_int(a2w.m_szBuffer[0], 0); + + CW2W w2w(NULL); + ok_ptr((LPWSTR)w2w, NULL); + ok_ptr(w2w.m_psz, NULL); + ok_int(w2w.m_szBuffer[0], 0); + } + + // + // The zero-length strings + // + { + CA2A a2a(""); + ok_str((LPSTR)a2a, ""); + ok_str(a2a.m_psz, ""); + ok_int(a2a.m_szBuffer[0], 0); + ok_ptr(a2a.m_psz, a2a.m_szBuffer); + + CW2A w2a(L""); + ok_str((LPSTR)w2a, ""); + ok_str(w2a.m_psz, ""); + ok_int(w2a.m_szBuffer[0], 0); + ok_ptr(w2a.m_psz, w2a.m_szBuffer); + + CA2W a2w(""); + ok_wstr((LPWSTR)a2w, L""); + ok_wstr(a2w.m_psz, L""); + ok_int(a2w.m_szBuffer[0], 0); + ok_ptr(a2w.m_psz, a2w.m_szBuffer); + + CW2W w2w(L""); + ok_wstr((LPWSTR)w2w, L""); + ok_wstr(w2w.m_psz, L""); + ok_int(w2w.m_szBuffer[0], 0); + ok_ptr(w2w.m_psz, w2w.m_szBuffer); + } + + // + // The short strings + // + { + CA2A a2a("TEST123"); + ok_str((LPSTR)a2a, "TEST123"); + ok_str(a2a.m_psz, "TEST123"); + ok_ptr(a2a.m_psz, a2a.m_szBuffer); + + CW2A w2a(L"TEST123"); + ok_str((LPSTR)w2a, "TEST123"); + ok_str(w2a.m_psz, "TEST123"); + ok_ptr(w2a.m_psz, w2a.m_szBuffer); + + CA2W a2w("TEST123"); + ok_wstr((LPWSTR)a2w, L"TEST123"); + ok_wstr(a2w.m_psz, L"TEST123"); + ok_ptr(a2w.m_psz, a2w.m_szBuffer); + + CW2W w2w(L"TEST123"); + ok_wstr((LPWSTR)w2w, L"TEST123"); + ok_wstr(w2w.m_psz, L"TEST123"); + ok_ptr(w2w.m_psz, w2w.m_szBuffer); + } + + // + // The short strings (EX) + // + { + CA2AEX<5> a2ax("123"); + ok_str((LPSTR)a2ax, "123"); + ok_str(a2ax.m_psz, "123"); + ok_ptr(a2ax.m_psz, a2ax.m_szBuffer); + + CW2AEX<5> w2ax(L"123"); + ok_str((LPSTR)w2ax, "123"); + ok_str(w2ax.m_psz, "123"); + ok(w2ax.m_psz != w2ax.m_szBuffer, "w2ax.m_psz == w2ax.m_szBuffer\n"); // corner case + + CA2WEX<5> a2wx("123"); + ok_wstr((LPWSTR)a2wx, L"123"); + ok_wstr(a2wx.m_psz, L"123"); + ok_ptr(a2wx.m_psz, a2wx.m_szBuffer); + + CW2WEX<5> w2wx(L"123"); + ok_wstr((LPWSTR)w2wx, L"123"); + ok_wstr(w2wx.m_psz, L"123"); + ok_ptr(w2wx.m_psz, w2wx.m_szBuffer); + } + + // + // The long strings + // + { + CA2A a2a2(dataA); + ok_str((LPSTR)a2a2, dataA); + ok_str(a2a2.m_psz, dataA); + ok_str(a2a2.m_szBuffer, ""); + ok(a2a2.m_psz != dataA, "a2a2.m_psz == dataA\n"); + ok(a2a2.m_psz != a2a2.m_szBuffer, "a2a2.m_psz == a2a2.m_szBuffer\n"); + + CW2A w2a2(dataW); + ok_str((LPSTR)w2a2, dataA); + ok_str(w2a2.m_psz, dataA); + ok_str(w2a2.m_szBuffer, ""); + ok(w2a2.m_psz != dataA, "w2a2.m_psz == dataA\n"); + ok(w2a2.m_psz != w2a2.m_szBuffer, "w2a2.m_psz == w2a2.m_szBuffer\n"); + + CA2W a2w2(dataA); + ok_wstr((LPWSTR)a2w2, dataW); + ok_wstr(a2w2.m_psz, dataW); + ok_wstr(a2w2.m_szBuffer, L""); + ok(a2w2.m_psz != dataW, "a2w2.m_psz == dataW\n"); + ok(a2w2.m_psz != a2w2.m_szBuffer, "a2w2.m_psz == a2w2.m_szBuffer\n"); + + CW2W w2w2(dataW); + ok_wstr((LPWSTR)w2w2, dataW); + ok_wstr(w2w2.m_psz, dataW); + ok_wstr(w2w2.m_szBuffer, L""); + ok(w2w2.m_psz != dataW, "w2w2.m_psz == dataW\n"); + ok(w2w2.m_psz != w2w2.m_szBuffer, "w2w2.m_psz == w2w2.m_szBuffer\n"); + } + + // + // The long strings (EX) + // + { + CA2AEX<5> a2a2x(dataAX); + ok_str((LPSTR)a2a2x, dataAX); + ok_str(a2a2x.m_psz, dataAX); + ok_str(a2a2x.m_szBuffer, ""); + ok(a2a2x.m_psz != dataAX, "a2a2x.m_psz == dataAX\n"); + ok(a2a2x.m_psz != a2a2x.m_szBuffer, "a2a2x.m_psz == a2a2x.m_szBuffer\n"); + + CW2AEX<5> w2a2x(dataWX); + ok_str((LPSTR)w2a2x, dataAX); + ok_str(w2a2x.m_psz, dataAX); + ok_str(w2a2x.m_szBuffer, ""); + ok(w2a2x.m_psz != dataAX, "w2a2x.m_psz == dataAX\n"); + ok(w2a2x.m_psz != w2a2x.m_szBuffer, "w2a2x.m_psz == w2a2x.m_szBuffer\n"); + + CA2WEX<5> a2w2x(dataAX); + ok_wstr((LPWSTR)a2w2x, dataWX); + ok_wstr(a2w2x.m_psz, dataWX); + ok_wstr(a2w2x.m_szBuffer, L""); + ok(a2w2x.m_psz != dataWX, "a2w2x.m_psz == dataWX\n"); + ok(a2w2x.m_psz != a2w2x.m_szBuffer, "a2w2x.m_psz == a2w2x.m_szBuffer\n"); + + CW2WEX<5> w2w2x(dataWX); + ok_wstr((LPWSTR)w2w2x, dataWX); + ok_wstr(w2w2x.m_psz, dataWX); + ok_wstr(w2w2x.m_szBuffer, L""); + ok(w2w2x.m_psz != dataWX, "w2w2x.m_psz == dataWX\n"); + ok(w2w2x.m_psz != w2w2x.m_szBuffer, "w2w2x.m_psz == w2w2x.m_szBuffer\n"); + } + + // + // The const strings + // + { + CA2CA a2ca(dataA); + ok_str((LPCSTR)a2ca, dataA); + ok_str(a2ca.m_psz, dataA); + ok_ptr(a2ca.m_psz, dataA); + + CW2CW w2cw(dataW); + ok_wstr((LPCWSTR)w2cw, dataW); + ok_wstr(w2cw.m_psz, dataW); + ok_ptr(w2cw.m_psz, dataW); + } +} diff --git a/modules/rostests/apitests/atl/atltest.h b/modules/rostests/apitests/atl/atltest.h index 9fb1ede6ac5..42740868814 100644 --- a/modules/rostests/apitests/atl/atltest.h +++ b/modules/rostests/apitests/atl/atltest.h @@ -107,7 +107,7 @@ char *wine_dbgstr_w(const wchar_t *wstr) #define ok_ptr(expression, result) \ do { \ - void *_value = (expression); \ + const void *_value = (expression); \ ok(_value == (result), "Wrong value for '%s', expected: " #result " (%p), got: %p\n", \ #expression, (void*)(result), _value); \ } while (0) diff --git a/modules/rostests/apitests/atl/devenv/.gitignore b/modules/rostests/apitests/atl/devenv/.gitignore index 15eeeeb1607..442c28bde1d 100644 --- a/modules/rostests/apitests/atl/devenv/.gitignore +++ b/modules/rostests/apitests/atl/devenv/.gitignore @@ -1,7 +1,11 @@ *.opendb *.db +*.user +*.filters x64/ .vs/ +ipch/ +atlconv/ CAtlArray/ CAtlFileMapping/ CAtlList/ diff --git a/modules/rostests/apitests/atl/devenv/ATLTest.sln b/modules/rostests/apitests/atl/devenv/ATLTest.sln index 5b3cc7d4247..128101222af 100644 --- a/modules/rostests/apitests/atl/devenv/ATLTest.sln +++ b/modules/rostests/apitests/atl/devenv/ATLTest.sln @@ -31,6 +31,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CPath", "CPath.vcxproj", "{ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtlObjMap", "AtlObjMap.vcxproj", "{B628C42A-A38E-488E-8512-2B997B75E95C}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "atlconv", "atlconv.vcxproj", "{85194CA3-A828-4270-962A-333743E2BF83}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -151,6 +153,14 @@ Global {B628C42A-A38E-488E-8512-2B997B75E95C}.Release|x64.Build.0 = Release|x64 {B628C42A-A38E-488E-8512-2B997B75E95C}.Release|x86.ActiveCfg = Release|Win32 {B628C42A-A38E-488E-8512-2B997B75E95C}.Release|x86.Build.0 = Release|Win32 + {85194CA3-A828-4270-962A-333743E2BF83}.Debug|x64.ActiveCfg = Debug|x64 + {85194CA3-A828-4270-962A-333743E2BF83}.Debug|x64.Build.0 = Debug|x64 + {85194CA3-A828-4270-962A-333743E2BF83}.Debug|x86.ActiveCfg = Debug|Win32 + {85194CA3-A828-4270-962A-333743E2BF83}.Debug|x86.Build.0 = Debug|Win32 + {85194CA3-A828-4270-962A-333743E2BF83}.Release|x64.ActiveCfg = Release|x64 + {85194CA3-A828-4270-962A-333743E2BF83}.Release|x64.Build.0 = Release|x64 + {85194CA3-A828-4270-962A-333743E2BF83}.Release|x86.ActiveCfg = Release|Win32 + {85194CA3-A828-4270-962A-333743E2BF83}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/modules/rostests/apitests/atl/devenv/atlconv.vcxproj b/modules/rostests/apitests/atl/devenv/atlconv.vcxproj new file mode 100644 index 00000000000..606a5db9987 --- /dev/null +++ b/modules/rostests/apitests/atl/devenv/atlconv.vcxproj @@ -0,0 +1,154 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + {85194CA3-A828-4270-962A-333743E2BF83} + Win32Proj + atlconv + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140_xp + Unicode + false + + + Application + false + v140_xp + true + Unicode + false + + + + + + + + + + + + + + + + + + + + + true + + + true + $(ProjectName)\$(Platform)\$(Configuration)\ + + + false + + + false + $(ProjectName)\$(Platform)\$(Configuration)\ + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + NotUsing + Level3 + Disabled + _DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + \ No newline at end of file diff --git a/modules/rostests/apitests/atl/testlist.c b/modules/rostests/apitests/atl/testlist.c index 2309a421512..c56b2024d53 100644 --- a/modules/rostests/apitests/atl/testlist.c +++ b/modules/rostests/apitests/atl/testlist.c @@ -2,6 +2,7 @@ #include extern void func_AtlObjMap(void); +extern void func_atlconv(void); extern void func_atltypes(void); extern void func_CAtlFileMapping(void); extern void func_CAtlArray(void); @@ -23,6 +24,7 @@ extern void func_SubclassWindow(void); const struct test winetest_testlist[] = { { "AtlObjMap", func_AtlObjMap }, + { "atlconv", func_atlconv }, { "atltypes", func_atltypes }, { "CAtlFileMapping", func_CAtlFileMapping }, { "CAtlArray", func_CAtlArray }, diff --git a/sdk/lib/atl/atlconv.h b/sdk/lib/atl/atlconv.h new file mode 100644 index 00000000000..7ba62045575 --- /dev/null +++ b/sdk/lib/atl/atlconv.h @@ -0,0 +1,348 @@ +/* + * PROJECT: ReactOS ATL + * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) + * PURPOSE: String conversion + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +#ifndef __ATLCONV_H__ +#define __ATLCONV_H__ + +#pragma once + +#include "atlbase.h" + +namespace ATL +{ + +// This class does not own the string +template +class CA2CAEX +{ +public: + LPCSTR m_psz; + + CA2CAEX(_In_z_ LPCSTR psz) : m_psz(psz) { } + + CA2CAEX(_In_z_ LPCSTR psz, _In_ UINT nCodePage) : m_psz(psz) + { + UNREFERENCED_PARAMETER(nCodePage); + } + + ~CA2CAEX() throw() { } // There is nothing to free here + + _Ret_z_ operator LPCSTR() const throw() { return m_psz; } + +private: + // CA2CAEX is not copyable + CA2CAEX(_In_ const CA2CAEX&) throw() = delete; + CA2CAEX& operator=(_In_ const CA2CAEX&) throw() = delete; +}; + +// This class does not own the string +template +class CW2CWEX +{ +public: + LPCWSTR m_psz; + + CW2CWEX(_In_z_ LPCWSTR psz) : m_psz(psz) { } + + CW2CWEX(_In_z_ LPCWSTR psz, _In_ UINT nCodePage) : m_psz(psz) + { + UNREFERENCED_PARAMETER(nCodePage); + } + + ~CW2CWEX() throw() { } // There is nothing to free here + + _Ret_z_ operator LPCWSTR() const throw() { return m_psz; } + +private: + // CW2CWEX is not copyable + CW2CWEX(_In_ const CW2CWEX&) throw() = delete; + CW2CWEX& operator=(_In_ const CW2CWEX&) throw() = delete; +}; + +template +class CA2AEX +{ +public: + LPSTR m_psz; + char m_szBuffer[t_nBufferLength]; + + CA2AEX(_In_z_ LPCSTR psz) + { + Init(psz); + } + + CA2AEX(_In_z_ LPCSTR psz, _In_ UINT nCodePage) + { + UNREFERENCED_PARAMETER(nCodePage); + Init(psz); + } + + ~CA2AEX() throw() + { + if (m_psz != m_szBuffer) + free(m_psz); + } + + _Ret_z_ operator LPSTR() const throw() + { + return m_psz; + } + +private: + // CA2AEX is not copyable + CA2AEX(_In_ const CA2AEX &) throw() = delete; + CA2AEX& operator=(_In_ const CA2AEX &) throw() = delete; + + void Init(_In_z_ LPCSTR psz) + { + if (!psz) + { + m_psz = NULL; + m_szBuffer[0] = 0; + return; + } + int cchMax = lstrlenA(psz) + 1; + if (cchMax <= t_nBufferLength) + { +#ifdef _STRSAFE_H_INCLUDED_ + StringCchCopyA(m_szBuffer, _countof(m_szBuffer), psz); +#else + lstrcpynA(m_szBuffer, psz, _countof(m_szBuffer)); +#endif + m_psz = m_szBuffer; + return; + } + + m_szBuffer[0] = 0; + m_psz = _strdup(psz); + if (!m_psz) + AtlThrow(E_OUTOFMEMORY); + } +}; + +template +class CW2WEX +{ +public: + LPWSTR m_psz; + wchar_t m_szBuffer[t_nBufferLength]; + + CW2WEX(_In_z_ LPCWSTR psz) + { + Init(psz); + } + + CW2WEX(_In_z_ LPCWSTR psz, _In_ UINT nCodePage) + { + UNREFERENCED_PARAMETER(nCodePage); + Init(psz); + } + + ~CW2WEX() throw() + { + if (m_psz != m_szBuffer) + free(m_psz); + } + + _Ret_z_ operator LPWSTR() const throw() + { + return m_psz; + } + +private: + // CW2WEX is not copyable + CW2WEX(_In_ const CW2WEX&) throw() = delete; + CW2WEX& operator=(_In_ const CW2WEX&) throw() = delete; + + void Init(_In_z_ LPCWSTR psz) + { + if (!psz) + { + m_psz = NULL; + m_szBuffer[0] = 0; + return; + } + int cchMax = lstrlenW(psz); + if (cchMax <= t_nBufferLength) + { +#ifdef _STRSAFE_H_INCLUDED_ + StringCchCopyW(m_szBuffer, _countof(m_szBuffer), psz); +#else + lstrcpynW(m_szBuffer, psz, _countof(m_szBuffer)); +#endif + m_psz = m_szBuffer; + return; + } + + m_szBuffer[0] = 0; + m_psz = _wcsdup(psz); + if (!m_psz) + AtlThrow(E_OUTOFMEMORY); + } +}; + +template +class CA2WEX +{ +public: + LPWSTR m_psz; + wchar_t m_szBuffer[t_nBufferLength]; + + CA2WEX(_In_z_ LPCSTR psz) + { + Init(psz, CP_ACP); + } + + CA2WEX(_In_z_ LPCSTR psz, _In_ UINT nCodePage) + { + Init(psz, nCodePage); + } + + ~CA2WEX() throw() + { + if (m_psz != m_szBuffer) + free(m_psz); + } + + _Ret_z_ operator LPWSTR() const throw() + { + return m_psz; + } + +private: + // CA2WEX is not copyable + CA2WEX(_In_ const CA2WEX&) throw() = delete; + CA2WEX& operator=(_In_ const CA2WEX&) throw() = delete; + + void Init(_In_z_ LPCSTR psz, _In_ UINT nCodePage) + { + if (!psz) + { + m_psz = NULL; + m_szBuffer[0] = 0; + return; + } + +#if 1 + int cchMax = lstrlenA(psz) + 1; // This is 3 times faster +#else + int cchMax = MultiByteToWideChar(nCodePage, 0, psz, -1, NULL, 0); // It's slow +#endif + if (cchMax <= (int)_countof(m_szBuffer)) + { + // Use the static buffer + m_psz = m_szBuffer; + cchMax = _countof(m_szBuffer); + } + else + { + // Allocate a new buffer + m_szBuffer[0] = 0; + m_psz = (LPWSTR)malloc(cchMax * sizeof(WCHAR)); + if (!m_psz) + AtlThrow(E_OUTOFMEMORY); + } + + MultiByteToWideChar(nCodePage, 0, psz, -1, m_psz, cchMax); + m_psz[cchMax - 1] = 0; + } +}; + +template +class CW2AEX +{ +public: + LPSTR m_psz; + char m_szBuffer[t_nBufferLength]; + + CW2AEX(_In_z_ LPCWSTR psz) + { + Init(psz, CP_ACP); + } + + CW2AEX(_In_z_ LPCWSTR psz, _In_ UINT nCodePage) + { + Init(psz, nCodePage); + } + + ~CW2AEX() throw() + { + if (m_psz != m_szBuffer) + free(m_psz); + } + + _Ret_z_ operator LPSTR() const throw() + { + return m_psz; + } + +private: + // CW2AEX is not copyable + CW2AEX(_In_ const CW2AEX&) throw() = delete; + CW2AEX& operator=(_In_ const CW2AEX&) throw() = delete; + + void Init(_In_z_ LPCWSTR psz, _In_ UINT nConvertCodePage) + { + if (!psz) + { + m_psz = NULL; + m_szBuffer[0] = 0; + return; + } + + // NOTE: This has a failure. + int cchMax = WideCharToMultiByte(nConvertCodePage, 0, psz, -1, NULL, 0, NULL, NULL); + if (cchMax <= (int)_countof(m_szBuffer)) + { + // Use the static buffer + m_psz = m_szBuffer; + cchMax = _countof(m_szBuffer); + } + else + { + // Allocate a new buffer + m_szBuffer[0] = 0; + m_psz = (LPSTR)malloc(cchMax * sizeof(CHAR)); + if (!m_psz) + AtlThrow(E_OUTOFMEMORY); + } + + WideCharToMultiByte(nConvertCodePage, 0, psz, -1, m_psz, cchMax, NULL, NULL); + m_psz[cchMax - 1] = 0; + } +}; + +typedef CA2AEX<> CA2A; +typedef CW2AEX<> CW2A; +typedef CA2WEX<> CA2W; +typedef CW2WEX<> CW2W; +typedef CA2CAEX<> CA2CA; +typedef CW2CWEX<> CW2CW; + +#ifdef UNICODE + #define CA2CTEX CA2WEX + #define CA2TEX CA2WEX + #define CT2AEX CW2AEX + #define CT2CAEX CW2AEX + #define CT2CWEX CW2CWEX + #define CT2WEX CW2WEX + #define CW2CTEX CW2CWEX + #define CW2CTEX CW2CWEX +#else + #define CA2CTEX CA2CAEX + #define CA2TEX CA2AEX + #define CT2AEX CA2AEX + #define CT2CAEX CA2CAEX + #define CT2CWEX CA2WEX + #define CT2WEX CA2WEX + #define CW2CTEX CW2AEX + #define CW2TEX CW2AEX +#endif + +} // namespace ATL + +#endif // ndef __ATLCONV_H__