CPP Windows преобразования строк путаница CStringA и LPCWSTR - PullRequest
1 голос
/ 09 июля 2019

Мне нужно использовать функцию WinAPI для перезапуска службы Windows, я не знаком со строками в C ++.

Моя функция получает в качестве параметра: const CStringA& serviceName:

bool MyClassName::RestartServer(const CStringA& serviceName)

Когда я получаю SC Handle через OpenService(..), мне нужно указать тип 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().
Что сработало:

LPCWSTR newString = serviceName.AllocSysString();

Что мне здесь не хватает?Почему 1 и 2 не сработали?Почему 3 сработало?

Как правильно освободить newString?

Ответы [ 2 ]

3 голосов
/ 10 июля 2019

Ваш код требует преобразования, потому что вы вызываете макрос OpenService() на основе TCHAR, который отображается либо на 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);
    ...
}

В противном случае, если выесли вы продолжите использовать в своем коде функциональность на основе TCHAR 1 , тогда вам следует изменить метод RestartServer(), чтобы он принимал CString вместо CStringA, чтобы он принимал тот же ANSI / Unicodeотображение, которое делает OpenService() (и другие функции на основе TCHAR), снова избегая преобразования:

1: что вам не следует делать, поскольку редко требуется когда-либо писать коддля Win9x / ME в настоящее время.Windows была Unicode-ОС начиная с NT4.

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);
    ...
}
2 голосов
/ 09 июля 2019

CStringA и CStringW имеют конструкторы, принимающие строки const char* и const wchar_t* C.

Пишите следующее:

CStringW serviceNameW( serviceName );

О AllocSysString, он создаетскопируйте в BSTR, они более сложные, чем строки C, они также заканчиваются нулем, но имеют длину с отрицательным смещением.Если вы хотите сделать ручное управление памятью, позвоните SysFreeString на указатель.Или, если вы хотите BSTR, но не хотите ручного управления памятью, используйте CComBSTR class.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...