CPP Windows 字符串转换混淆了 CStringA 和 LPCWSTR

CPP Windows string conversions confusion CStringA and LPCWSTR

本文关键字:CStringA LPCWSTR Windows 字符串 转换 CPP      更新时间:2023-10-16

我需要使用 WinAPI 函数重新启动 Windows 服务,我不熟悉C++中的字符串。

我的函数接收为参数:const CStringA& serviceName

bool MyClassName::RestartServer(const CStringA& serviceName)

当我通过OpenService(..)获取SC句柄时,我需要提供类型LPCWSTR

SC_HANDLE SHandle = OpenService(hSCManager, LPCWSTR serviceNameAsWideString, SC_MANAGER_ALL_ACCESS);

如何将CStringA转换为LPCWSTR

我试图遵循:

  1. CA2W(serviceName, CP_UTF8);
  2. CString str("MyServiceName"); CStringW strw(str); LPCWSTR ptr = strw;

两者都无法正常工作,它们进行了编译,但是当我尝试执行代码时。
它未能OpenService().
什么有效:

  1. LPCWSTR newString = serviceName.AllocSysString();

我在这里错过了什么?为什么 1 和 2 不起作用?为什么 3 有效?

如何正确释放新字符串?

您的代码需要转换,因为您正在调用基于TCHAROpenService()宏,该宏映射到OpenServiceW()OpenServiceA(),具体取决于是否定义了UNICODE

__checkReturn
WINADVAPI
SC_HANDLE
WINAPI
OpenServiceA(
__in            SC_HANDLE               hSCManager,
__in            LPCSTR                lpServiceName,
__in            DWORD                   dwDesiredAccess
);
__checkReturn
WINADVAPI
SC_HANDLE
WINAPI
OpenServiceW(
__in            SC_HANDLE               hSCManager,
__in            LPCWSTR                lpServiceName,
__in            DWORD                   dwDesiredAccess
);
#ifdef UNICODE
#define OpenService  OpenServiceW
#else
#define OpenService  OpenServiceA
#endif // !UNICODE

在您的情况下,UNICODE在您的项目中明确定义,因此您的代码实际上是在调用OpenServiceW(),这就是为什么它需要LPCWSTR作为输入。

您的RestartServer()方法将CStringA(基于char的 ANSI)字符串作为输入,因此您应该显式使用OpenServiceA()来匹配相同的字符类型,无需转换:

bool MyClassName::RestartServer(const CStringA& serviceName)
{
...
SC_HANDLE SHandle = OpenServiceA(hSCManager, serviceName, SC_MANAGER_ALL_ACCESS);
...
}

否则,如果要继续在代码1中使用基于TCHAR的功能,则应将RestartServer()方法更改为采用CString而不是CStringA,以便它采用与OpenService()相同的 ANSI/Unicode 映射(以及其他基于TCHAR的函数),再次避免转换:

1:你不应该这样做,因为现在很少需要为Win9x/ME编写代码。自NT4以来,Windows一直是基于Unicode的操作系统。

bool MyClassName::RestartServer(const CString& serviceName)

如果这不是您的选择,那么CA2W()就可以正常工作:

bool MyClassName::RestartServer(const CStringA& serviceName)
{
USES_CONVERSION;
...
SC_HANDLE SHandle = OpenService(hSCManager, ATL::CA2W(serviceName), SC_MANAGER_ALL_ACCESS);
...
}

不过,您可以考虑在内部仅使用CString,并在需要时让它处理转换:

bool MyClassName::RestartServer(const CStringA& serviceName)
{
...
SC_HANDLE SHandle = OpenService(hSCManager, CString(serviceName), SC_MANAGER_ALL_ACCESS);
...
}

或者,使代码具有条件:

bool MyClassName::RestartServer(const CStringA& serviceName)
{
...
SC_HANDLE SHandle = OpenService(hSCManager,
#ifdef UNICODE
CStringW(serviceName)
#else
serviceName
#endif
, SC_MANAGER_ALL_ACCESS);
...
}

CStringACStringW都有构造函数同时接受const char*const wchar_t*C字符串。

写下以下内容:

CStringW serviceNameW( serviceName );

大约AllocSysString,它在 BSTR 中创建一个副本,它们比 C 字符串更复杂,它们也是以 null 结尾的,但它们的长度也为负偏移量。如果要执行手动内存管理,请在指针上调用SysFreeString。或者,如果需要 BSTR 但不需要手动内存管理,请使用CComBSTR类。