Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 12.07.2017, 21:15   #1
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию Шаблон для вывода ANSI и UNICODE строк

При перечислении названий криптопровайдеров мне нужно предусмотреть вывод как ANSI-строк, так и UNICODE.

Код:
void EnumProviders(void)
{
	DWORD dwIndex = 0, dwType = 0, cbName = 0;
	while (CryptEnumProviders(dwIndex,	// Next prov index
		NULL,							// Reserved
		0,								// Reserved
		&dwType,						// Prov type
		NULL,							// Get prov name size in bytes
		&cbName))						// Prov name size
	{
		TCHAR *pszName = NULL;
		if (!(pszName = (PTCHAR)LocalAlloc(LMEM_ZEROINIT, cbName)))
		{
			std::cout << "LocalAlloc failed" << std::endl;
			exit(1);
		}

		if (CryptEnumProviders(dwIndex++,
			NULL,
			0,
			&dwType,
			(LPTSTR)pszName,
			&cbName))
		{
			PRINT_FUNC(pszName);
		}
		else
		{
			std::cout << "CryptEnumProviders failed" << std::endl;
			exit(1);
		}
		LocalFree(pszName);
	}
}
Я написал такой шаблон для печати произвольных строк:

Код:
template <typename T>
void PRINT_FUNC(T *pszStr)
{
#ifdef UNICODE
#  define os std::wcout
#else
#  define os std::cout
#endif

	os << pszStr << std::endl;
}
Какие недостатки в нем есть? Как можно переписать этот шаблон?
От препроцесссора рекомендуют отказываться, однако я не вижу способа сделать это здесь.

Имеет ли значение, как передавать строку в шаблон: как указатель * или как ссылку на массив *&?
Aoizora вне форума Ответить с цитированием
Старый 12.07.2017, 23:39   #2
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Код:
void Print(LPCSTR str)
{
    std::cout << str;
}
void Print(LPCWSTR str)
{
    std::wcout << str;
}
waleri вне форума Ответить с цитированием
Старый 13.07.2017, 13:13   #3
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

А как можно определить std::map, который в зависимости от кодировки будет содержить строки ANSI или UNICODE? Функция, перечисляющая типы и имена типов провайдеров, должна возвращать для удобства std::map.

UPD. Попробую передавать шаблону типа LPTSTR, но не уверен, что поможет.

Возникли проблемы с выводом содержимого контейнера в консоль.

Код:
#include <iostream>
#include <map>

#include <windows.h>
#include <wincrypt.h>

#pragma comment(lib, "advapi32.lib")



std::ostream& PRINT_FUNC(LPCSTR pszData)
{
	return std::cout << pszData;
}

std::wostream& PRINT_FUNC(LPCWSTR pszData)
{
	return std::wcout << pszData;
}

void EnumProviderNames(void)
{
	DWORD dwIndex = 0, dwType = 0, cbName = 0;
	while (CryptEnumProviders(dwIndex,	// Next prov index
		NULL,							// Reserved
		0,								// Reserved
		&dwType,						// Prov type
		NULL,							// Get prov name size in bytes
		&cbName))						// Prov name size
	{
		TCHAR *pszName = NULL;
		if (!(pszName = (PTCHAR)LocalAlloc(LMEM_ZEROINIT, cbName)))
		{
			std::cout << "LocalAlloc failed" << std::endl;
			exit(1);
		}

		if (CryptEnumProviders(dwIndex++,
			NULL,
			0,
			&dwType,
			(LPTSTR)pszName,
			&cbName))
		{
			PRINT_FUNC(pszName) << std::endl;
		}
		else
		{
			std::cout << "CryptEnumProviders failed" << std::endl;
			exit(1);
		}
		LocalFree(pszName);
	}
}

using TypesDictionary = std::map<LPTSTR, DWORD>;

TypesDictionary EnumProviderTypes(void)
{
	TypesDictionary installedTypes;

	DWORD dwIndex = 0, dwProvType = 0, cbName = 0;
	while (CryptEnumProviderTypes(
		dwIndex,
		NULL,			// Reserved
		0,				// Reserved
		&dwProvType,
		NULL,			// Get name length in bytes
		&cbName))
	{
		TCHAR *pszName = NULL;
		if (!(pszName = (PTCHAR)LocalAlloc(LMEM_ZEROINIT, cbName)))
		{
			std::cout << "LocalAlloc failed" << std::endl;
			exit(1);
		}

		if (CryptEnumProviderTypes(dwIndex++,
			NULL,
			0,
			&dwProvType,
			pszName,
			&cbName))
		{
			installedTypes.insert({ pszName, dwProvType });
		}
		else
		{
			std::cout << "CryptEnumProviderTypes failed" << std::endl;
			exit(1);
		}
		LocalFree(pszName);
	}
	return installedTypes;
}

int main()
{
	std::cout << "Enumerating prov names:" << std::endl;
	EnumProviderNames();

	std::cout << std::endl;
	std::cout << "Enumerating prov types" << std::endl;
	auto provTypes = EnumProviderTypes();
	for (const auto& type : provTypes)
	{
		PRINT_FUNC(type.first) << std::endl;
	}
}
Контейнер для строк в разной кодировке объявлен как
Код:
using TypesDictionary = std::map<LPTSTR, DWORD>;
В нем хранятся пары (название_типа, код_типа). Название типа выводится на консоль функцией PRINT_FUNC(type.first) << std::endl, но ее вызов не печатает на экран ничего. При этом в отладчике содержимое pszData начинается с иероглифов, за которыми следует строка с названием. Что здесь не так?

Последний раз редактировалось Aoizora; 13.07.2017 в 13:54.
Aoizora вне форума Ответить с цитированием
Старый 13.07.2017, 14:14   #4
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Цитата:
Сообщение от Aoizora Посмотреть сообщение
Что здесь не так?
Заклавиатурное устройство сломалось.
Вы добавляете в коллекцию выделенный буфер, после чего удаляете его.

Если в С++ вам приходится выделять память вручную, значит вы что-то делаете не так.
waleri вне форума Ответить с цитированием
Старый 13.07.2017, 15:29   #5
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
Заклавиатурное устройство сломалось.
Клевая шутка!

>Вы добавляете в коллекцию выделенный буфер, после чего удаляете его.
Угу, действительно.

>Если в С++ вам приходится выделять память вручную, значит вы что-то делаете не так.
Но буфер выделить надо, потому что функция ожидает его. Использовать интеллектуальный указатель с параметров типа шаблона LPTSTR для хранения строк в произвольной кодировке и хранить эти указатели в std::map?

Код:
std::shared_ptr<TCHAR> pszName(new TCHAR[cbName / sizeof(TCHAR)]);
Не очень красивая запись из-за пересчета размера буфера в символах в зависимости от размера TCHAR. Но если шаблон shared_ptr инстанцировать с типом char или BYTE, тогда придется делать приведения типов ниже по коду.

Последний раз редактировалось Aoizora; 13.07.2017 в 15:42.
Aoizora вне форума Ответить с цитированием
Старый 13.07.2017, 15:54   #6
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Чем не устраивает std::string ?
waleri вне форума Ответить с цитированием
Старый 13.07.2017, 15:59   #7
Aoizora
Заблокирован
 
Регистрация: 11.11.2016
Сообщений: 261
По умолчанию

Цитата:
Сообщение от waleri Посмотреть сообщение
Чем не устраивает std::string ?
Не уверен, что он хранит строки в двух кодировках. Есть ведь std::string и std::wstring.
Aoizora вне форума Ответить с цитированием
Старый 13.07.2017, 23:48   #8
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Цитата:
Сообщение от Aoizora Посмотреть сообщение
Есть ведь std::string и std::wstring.
Это разные специализации одного и того же шаблона - std::basic_string<>
waleri вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Unicode to ANSI. Denutrror Общие вопросы Delphi 10 25.08.2012 16:15
Из ANSI в UNICODE Mrshilov Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 0 06.08.2012 08:55
ANSI & UNICODE AD0 Общие вопросы Delphi 0 15.06.2011 09:21
unicode to ansi Евгений79 Общие вопросы Delphi 10 25.05.2011 22:04
Конвертировать строку из ANSI в UNICODE Миша Общие вопросы Delphi 8 28.12.2009 18:23