L и LPCWSTR в WIndows API - PullRequest
       1

L и LPCWSTR в WIndows API

3 голосов
/ 02 февраля 2011

Я обнаружил, что

NetUserChangePassword(0, 0, L"ab", L"cd");

меняет пароль пользователя с ab на cd.Однако

NetUserChangePassword(0, 0, (LPCWSTR) "ab", (LPCWSTR) "cd");

не работает.Возвращаемое значение указывает на неверный пароль.

Мне нужно передать const char* в качестве двух последних параметров для этого вызова функции.Как я могу это сделать?Например,

NetUserChangePassword(0, 0, (LPCWSTR) vs[0].c_str(), (LPCWSTR) vs[1].c_str());

Где vs равно std::vector<std::string>.

Ответы [ 5 ]

6 голосов
/ 02 февраля 2011

У вас две проблемы.

Первая - это практическая проблема - как это сделать. Вы путаете широкие и узкие струны и переходите от одного к другому. Строка с префиксом L представляет собой широкую строку, где каждый символ составляет два байта (a wchar_t). Строка без L - это один байт (char). Вы не можете приводить от одного к другому, используя приведение в стиле C (LPCWSTR) "ab", потому что у вас есть массив char s, и вы приводите его к указателю на широкие символы. Это просто изменение типа указателя, а не базовых данных.

Чтобы преобразовать узкую строку в широкую, вы обычно используете MultiByteToWideChar . Вы не упоминаете, в какой кодовой странице находятся ваши узкие строки; вы, вероятно, передали бы CP_ACP для первого параметра. Однако, поскольку вы выполняете преобразование между строкой и строкой, вас могут заинтересовать другие способы преобразования ( one , two ). Это даст вам wstring с вашими персонажами, а не string, а метод wstring .c_str() возвращает указатель на wchar_t s.

Вторым является следующее недоразумение:

Мне нужно передать const char * как два последних параметра для этого вызова функции. Как я могу это сделать?

Нет, нет. Вам нужно передать широкую строку, которую вы получили выше. Ваш подход к этому (приведение указателя) показывает, что вы, вероятно, не знаете о различных типах строк и кодировках символов, и это должен знать каждый разработчик программного обеспечения. Итак, если вы заинтересованы, надеюсь, вам пригодятся следующие ссылки:

Я бы порекомендовал вам исследовать перекомпиляцию приложения с UNICODE и использовать широкие строки. Многие API определены как в узкой, так и в широкой версиях, и обычно это означает, что вы получаете доступ к узкой версии по умолчанию (вы можете получить доступ к ANSI (узкой) или широкой версиям этих API, напрямую вызывая версию A или W - они имеют А или W добавлены к их имени, например CreateWindowW - см. Нижнюю часть этой страницы для двух имен. Обычно вам не нужно беспокоиться об этом.) Насколько я могу судить, этот API всегда доступен как есть, независимо от UNICODE, просто он имеет прототип шириной.

5 голосов
/ 02 февраля 2011

Это два совершенно разных L . Первый является частью синтаксиса языка C ++.Префикс строкового литерала с L, и он становится wide string literal;вместо массива char вы получаете массив wchar_t.

Однако L в LPCWSTR не описывает ширину символов.Вместо этого он описывает размер указателя .Или, по крайней мере, это раньше .Аббревиатура L для имен типов является пережитком 16-битной Windows, когда существовало два вида указателей.Были указатели около , где адрес находился где-то внутри текущего сегмента размером 64 КБ, и указатели far или long , которые могли указывать за пределы текущегосегмент.Операционная система требовала, чтобы вызывающие абоненты предоставляли последний своим API-интерфейсам, поэтому все имена типов указателей используют LP.В настоящее время есть только один тип указателя;Microsoft сохраняет те же имена типов, чтобы старый код продолжал компилироваться.

Часть LPCWSTR, которая задает широкие символы, - это W.Но простого преобразования типа char строкового литерала в LPCWSTR недостаточно для преобразования этих символов в широкие символы.Вместо этого то, что происходит, - приведение типа сообщает компилятору, что то, что вы написали , на самом деле является указателем на широкую строку, даже если на самом деле это не так.Компилятор доверяет вам.Не приводите тип, если вы действительно не знаете лучше, чем компилятор, что такое настоящие типы.

Если вам действительно нужно передать const char*, тогда вам не нужнонаберите что-нибудь, и вам не нужен префикс L.Достаточно простого старого строкового литерала.(Если вы действительно хотите привести к типу Windows, используйте LPCSTR - нет W.) Но похоже, что вам действительно нужно передать это const wchar_t*.Как мы узнали выше, вы можете получить это с префиксом L в строковом литерале.

В реальной программе у вас, вероятно, нет строкового литерала.Пользователь предоставит пароль, или вы прочитаете пароль из какого-либо другого внешнего источника.В идеале вы должны хранить этот пароль в std::wstring, что похоже на std::string, но для wchar_t вместо char.Метод c_str() этого типа возвращает const wchar_t*.Если у вас нет wstring, может быть достаточно простого массива wchar_t.

Но если вы храните пароль в std::string, вам необходимо преобразовать егов широкие символы другим способом.Чтобы выполнить преобразование, вам необходимо знать, какую кодовую страницу используют символы std::string.«Текущая кодовая страница ANSI» обычно является безопасной ставкой;он представлен константой CP_ACP.Вы будете использовать это при вызове MultiByteToWideString, чтобы ОС преобразовала кодовую страницу пароля в Unicode.

int required_size = MultiByteToWideChar(CP_ACP, 0, vs[0].c_str(), vs[0].size(), NULL, 0);
if (required_size == 0)
  ERROR;
// We'll be storing the Unicode password in this vector. Reserve at
// least enough space for all the characters plus a null character
// at the end.
std::vector<wchar_t> wv(required_size);
int result = MultiByteToWideChar(CP_ACP, 0, vs[0].c_str(), vs[0].size(), &wv[0], required_size);
if (result != required_size - 1)
  ERROR;

Теперь, когда вам нужен wchar_t*, просто используйтеуказатель на первый элемент этого вектора: &wv[0].Если вам это нужно в wstring, вы можете построить его из вектора несколькими способами:

// The vector is null-terminated, so use "const wchar_t*" constructor
std::wstring ws1 = &wv[0];
// Use iterator constructor. The vector is null-terminated, so omit
// the final character from the iterator range.
std::wstring ws2(wv.begin(), wv.end() - 1);
// Use pointer/length constructor.
std::wstring ws3(&wv[0], wv.size() - 1);
4 голосов
/ 02 февраля 2011
Кастинги в стиле

C, как вы использовали здесь, являются очень тупым инструментом.Они предполагают, что вы точно знаете, что делаете.

Вам потребуется преобразовать ASCII или многобайтовые строки в строки Unicode для API.Возможно, есть функция NetUserChangePasswordA, которая принимает типы char *, которые вы пытаетесь передать, попробуйте сначала.

1 голос
/ 02 февраля 2011

LPWSTR определяется как wchar_t * (whcar_T - 2-байтовый тип символов), которые интерпретируются иначе, чем обычные 1-байтовые символы.

0 голосов
/ 02 февраля 2011

LPCWSTR означает, что вам нужно передать wchar_t *.

, если вы измените vs на std::vector<std::wstring>, который даст вам широкий символ при передаче vs [0] .c_str ()

если вы посмотрите на пример на http://msdn.microsoft.com/en-us/library/aa370650(v=vs.85).aspx, вы увидите, что они определяют UNICODE, поэтому они используют wchar_t.

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