使用 boost 或标准库的 wchar 参数
wchar parameters using boost or the Standard Library
如何使此代码使用 boost C++ 字符串库或标准库,以避免 wchar_t
大小定义,并获得更容易处理的动态字符串?此代码使用 MFC 的 CString
,但我更愿意使用标准库或 boost。
TCHAR drive[_MAX_DRIVE];
TCHAR dir[_MAX_DIR];
TCHAR fname[_MAX_FNAME];
TCHAR ext[_MAX_EXT];
CString cstr;
GetModuleFileName(NULL,cstr.GetBuffer(MAX_PATH),MAX_PATH);
cstr.ReleaseBuffer();
_wsplitpath_s(cstr,drive,dir,fname,ext);
cstr=drive;
cstr+=dir;
cstr+=_T("\myfile.dat");
你应该看看 C++ 标准 <filesystem>
library, specifically its path
class, which has a replace_filename()
方法,例如:
#include <filesystem>
#include <windows.h>
WCHAR szFileName[MAX_PATH] = {};
GetModuleFileNameW(NULL, szFileName, MAX_PATH);
std:wstring str = std::filesystem::path(szFileName).replace_filename(L"myfile.dat").wstring();
或者,由于您使用的是 Win32 API,您可以简单地使用 PathRemoveFileSpec()
and PathAppend()
(或更安全的 Cch
对应物),例如:
#include <windows.h>
WCHAR szFileName[MAX_PATH] = {};
GetModuleFileNameW(NULL, szFileName, MAX_PATH);
PathRemoveFileSpecW(szFileName);
PathAppendW(szFileName, L"myfile.dat");
std:wstring str = szFileName;
如果你真的想避免 MAX_PATH
限制,你将不得不在循环中调用 GetModuleFileName()
,在每次迭代中增加缓冲区的大小,直到它最终成功:
std::wstring wFileName(MAX_PATH, L'[=12=]');
do {
DWORD dwSize = GetModuleFileNameW(NULL, wFileName.data(), wFileName.size()); // or &wFileName[0] before C++17
if (dwSize < wFileName.size()) {
wFileName.resize(dwSize);
break;
}
wFileName.resize(wFileName.size() * 2);
}
while (true);
// use wFileName as needed...
只要您必须处理包含 C 风格 return 引用参数的 API,但您希望使用仅遵循 RAI 的类型,这个小帮手就可以使用。
#include <cstddef>
#include <string>
#include <iostream>
/**
* Wrap an instance of class S for C-style return-by-reference
* with base-type T and maximum length N.
*
* Use is required when S only supports modification by methods,
* and direct modification of internal buffer is forbidden.
*/
template<class S, class T, size_t N = 1>
class ref_param
{
public:
ref_param() = delete;
ref_param(const ref_param&) = delete;
ref_param(ref_param&&) = delete;
ref_param(S& ref) : _ref(ref), _storage{} {}
~ref_param()
{
_ref = _storage;
}
operator T*()
{
return _storage;
}
private:
S& _ref;
T _storage[N];
};
// Specialization for single value
template<class S, class T>
class ref_param<S, T, 1>
{
public:
ref_param() = delete;
ref_param(const ref_param&) = delete;
ref_param(ref_param&&) = delete;
ref_param(S& ref) : _ref(ref), _storage{} {}
~ref_param()
{
_ref = _storage;
}
operator T*()
{
return &_storage;
}
private:
S& _ref;
T _storage;
};
extern "C"
{
// example function with C style return-by-reference
void foo(char* ret, size_t size)
{
for(size_t i = 0; i < size - 1; ++i)
{
ret[i] = i + 'a';
}
ret[size - 1] = 0;
}
}
int main()
{
std::string bar;
foo(ref_param<std::string, char, 32>(bar), 32);
std::cout << bar;
return 0;
}
此模式也适用于其他类型,例如 ComPtr
s,基本上所有在 C++ 端具有赋值运算符的东西都可以使用。
如何使此代码使用 boost C++ 字符串库或标准库,以避免 wchar_t
大小定义,并获得更容易处理的动态字符串?此代码使用 MFC 的 CString
,但我更愿意使用标准库或 boost。
TCHAR drive[_MAX_DRIVE];
TCHAR dir[_MAX_DIR];
TCHAR fname[_MAX_FNAME];
TCHAR ext[_MAX_EXT];
CString cstr;
GetModuleFileName(NULL,cstr.GetBuffer(MAX_PATH),MAX_PATH);
cstr.ReleaseBuffer();
_wsplitpath_s(cstr,drive,dir,fname,ext);
cstr=drive;
cstr+=dir;
cstr+=_T("\myfile.dat");
你应该看看 C++ 标准 <filesystem>
library, specifically its path
class, which has a replace_filename()
方法,例如:
#include <filesystem>
#include <windows.h>
WCHAR szFileName[MAX_PATH] = {};
GetModuleFileNameW(NULL, szFileName, MAX_PATH);
std:wstring str = std::filesystem::path(szFileName).replace_filename(L"myfile.dat").wstring();
或者,由于您使用的是 Win32 API,您可以简单地使用 PathRemoveFileSpec()
and PathAppend()
(或更安全的 Cch
对应物),例如:
#include <windows.h>
WCHAR szFileName[MAX_PATH] = {};
GetModuleFileNameW(NULL, szFileName, MAX_PATH);
PathRemoveFileSpecW(szFileName);
PathAppendW(szFileName, L"myfile.dat");
std:wstring str = szFileName;
如果你真的想避免 MAX_PATH
限制,你将不得不在循环中调用 GetModuleFileName()
,在每次迭代中增加缓冲区的大小,直到它最终成功:
std::wstring wFileName(MAX_PATH, L'[=12=]');
do {
DWORD dwSize = GetModuleFileNameW(NULL, wFileName.data(), wFileName.size()); // or &wFileName[0] before C++17
if (dwSize < wFileName.size()) {
wFileName.resize(dwSize);
break;
}
wFileName.resize(wFileName.size() * 2);
}
while (true);
// use wFileName as needed...
只要您必须处理包含 C 风格 return 引用参数的 API,但您希望使用仅遵循 RAI 的类型,这个小帮手就可以使用。
#include <cstddef>
#include <string>
#include <iostream>
/**
* Wrap an instance of class S for C-style return-by-reference
* with base-type T and maximum length N.
*
* Use is required when S only supports modification by methods,
* and direct modification of internal buffer is forbidden.
*/
template<class S, class T, size_t N = 1>
class ref_param
{
public:
ref_param() = delete;
ref_param(const ref_param&) = delete;
ref_param(ref_param&&) = delete;
ref_param(S& ref) : _ref(ref), _storage{} {}
~ref_param()
{
_ref = _storage;
}
operator T*()
{
return _storage;
}
private:
S& _ref;
T _storage[N];
};
// Specialization for single value
template<class S, class T>
class ref_param<S, T, 1>
{
public:
ref_param() = delete;
ref_param(const ref_param&) = delete;
ref_param(ref_param&&) = delete;
ref_param(S& ref) : _ref(ref), _storage{} {}
~ref_param()
{
_ref = _storage;
}
operator T*()
{
return &_storage;
}
private:
S& _ref;
T _storage;
};
extern "C"
{
// example function with C style return-by-reference
void foo(char* ret, size_t size)
{
for(size_t i = 0; i < size - 1; ++i)
{
ret[i] = i + 'a';
}
ret[size - 1] = 0;
}
}
int main()
{
std::string bar;
foo(ref_param<std::string, char, 32>(bar), 32);
std::cout << bar;
return 0;
}
此模式也适用于其他类型,例如 ComPtr
s,基本上所有在 C++ 端具有赋值运算符的东西都可以使用。