[ATL][ATL_APITEST] Add <atlconv.h> and atlconv testcase (#5449)

- Add <atlconv.h> header file.
- Add atlconv testcase to atl_apitest.exe.
CORE-16668
This commit is contained in:
Katayama Hirofumi MZ 2023-07-20 07:54:11 +09:00 committed by GitHub
parent d24c991aa7
commit 1191bcaf03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 738 additions and 1 deletions

View file

@ -3,6 +3,7 @@ add_definitions(-DINITGUID -DWINETEST_USE_DBGSTR_LONGLONG)
list(APPEND SOURCE list(APPEND SOURCE
AtlObjMap.cpp AtlObjMap.cpp
atlconv.cpp
atltypes.cpp atltypes.cpp
CAtlFileMapping.cpp CAtlFileMapping.cpp
CAtlArray.cpp CAtlArray.cpp

View file

@ -0,0 +1,218 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Test for <atlconv.h>
* COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#ifdef HAVE_APITEST
#include <apitest.h>
#else
#include "atltest.h"
#endif
#include <atlbase.h>
#include <atlconv.h>
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);
}
}

View file

@ -107,7 +107,7 @@ char *wine_dbgstr_w(const wchar_t *wstr)
#define ok_ptr(expression, result) \ #define ok_ptr(expression, result) \
do { \ do { \
void *_value = (expression); \ const void *_value = (expression); \
ok(_value == (result), "Wrong value for '%s', expected: " #result " (%p), got: %p\n", \ ok(_value == (result), "Wrong value for '%s', expected: " #result " (%p), got: %p\n", \
#expression, (void*)(result), _value); \ #expression, (void*)(result), _value); \
} while (0) } while (0)

View file

@ -1,7 +1,11 @@
*.opendb *.opendb
*.db *.db
*.user
*.filters
x64/ x64/
.vs/ .vs/
ipch/
atlconv/
CAtlArray/ CAtlArray/
CAtlFileMapping/ CAtlFileMapping/
CAtlList/ CAtlList/

View file

@ -31,6 +31,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CPath", "CPath.vcxproj", "{
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtlObjMap", "AtlObjMap.vcxproj", "{B628C42A-A38E-488E-8512-2B997B75E95C}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtlObjMap", "AtlObjMap.vcxproj", "{B628C42A-A38E-488E-8512-2B997B75E95C}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "atlconv", "atlconv.vcxproj", "{85194CA3-A828-4270-962A-333743E2BF83}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 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|x64.Build.0 = Release|x64
{B628C42A-A38E-488E-8512-2B997B75E95C}.Release|x86.ActiveCfg = Release|Win32 {B628C42A-A38E-488E-8512-2B997B75E95C}.Release|x86.ActiveCfg = Release|Win32
{B628C42A-A38E-488E-8512-2B997B75E95C}.Release|x86.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View file

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\atlconv.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{85194CA3-A828-4270-962A-333743E2BF83}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>atlconv</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IntDir>$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>Use</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -2,6 +2,7 @@
#include <apitest.h> #include <apitest.h>
extern void func_AtlObjMap(void); extern void func_AtlObjMap(void);
extern void func_atlconv(void);
extern void func_atltypes(void); extern void func_atltypes(void);
extern void func_CAtlFileMapping(void); extern void func_CAtlFileMapping(void);
extern void func_CAtlArray(void); extern void func_CAtlArray(void);
@ -23,6 +24,7 @@ extern void func_SubclassWindow(void);
const struct test winetest_testlist[] = const struct test winetest_testlist[] =
{ {
{ "AtlObjMap", func_AtlObjMap }, { "AtlObjMap", func_AtlObjMap },
{ "atlconv", func_atlconv },
{ "atltypes", func_atltypes }, { "atltypes", func_atltypes },
{ "CAtlFileMapping", func_CAtlFileMapping }, { "CAtlFileMapping", func_CAtlFileMapping },
{ "CAtlArray", func_CAtlArray }, { "CAtlArray", func_CAtlArray },

348
sdk/lib/atl/atlconv.h Normal file
View file

@ -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 <katayama.hirofumi.mz@gmail.com>
*/
#ifndef __ATLCONV_H__
#define __ATLCONV_H__
#pragma once
#include "atlbase.h"
namespace ATL
{
// This class does not own the string
template <int t_nBufferLength = 128>
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 <int t_nBufferLength = 128>
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 <int t_nBufferLength = 128>
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 <int t_nBufferLength = 128>
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 <int t_nBufferLength = 128>
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 <int t_nBufferLength = 128>
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__