系列文章目录


文章目录

  • 系列文章目录
  • 前言
  • 一、中文乱码原因
  • 二、解决方法
  • 1.如果是windos11下,使用英文语言,需要加以下代码
  • 2.如果是中文语言只需要一行关键代码
  • 3.如果在异常处理中显示宽字符中文
  • 4.完整代码如下:
  • 实现文件
  • 测试代码
  • 输出打印


前言

我们在win32编程中使用宽字符,std::wstring经常会遇到中文乱码的情况,比方说在调试时,查看std::string类型的字符串是显示字符串的字符无效,其实这时候已经中文乱码了,还有就是在控制台输出时也会出现中文乱码。

std::wcout,std::cout控制台输出中文乱码,std::cerr字符串的字符无效_std wstring中文乱码


std::wcout,std::cout控制台输出中文乱码,std::cerr字符串的字符无效_std wstring中文乱码_02

一、中文乱码原因

1.编码不匹配:
宽字符编码与输出流编码不匹配:std::wstring 存储的是宽字符(wchar_t),通常使用 UTF-16 或者其他宽字符编码(如 UCS-2)。当你尝试将 std::wstring 输出到 std::cout 或 std::cerr 时,这些流默认使用的是 char 类型,因此需要将宽字符转换为相应的 char 类型编码(例如 UTF-8 或 GBK)。
控制台编码设置不正确:Windows 控制台默认使用的是 CP850 或 CP437 编码。如果你的程序输出的是 UTF-8 或者其他编码的字符串,那么在默认编码下可能会导致乱码。

2.输出流设置不正确:
如果你使用 std::wcout 或 std::wcerr 输出宽字符串,那么你需要确保你的控制台支持宽字符输出,并且设置了正确的编码。
如果你使用 std::cout 或 std::cerr 输出宽字符串,你需要先将宽字符串转换为对应的窄字符串(std::string),并确保转换编码正确。

二、解决方法

1.如果是windos11下,使用英文语言,需要加以下代码

system("chcp 936");
std::wcout.imbue(std::locale("chs"));

2.如果是中文语言只需要一行关键代码

std::wcout.imbue(std::locale("chs"));

3.如果在异常处理中显示宽字符中文

std::string utf8ToGbk(const std::string& utf8Str)
{
	int size_needed = MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), NULL, 0);
	std::wstring wstrTo(size_needed, 0);
	MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), &wstrTo[0], size_needed);

	int size_needed_gbk = WideCharToMultiByte(CP_ACP, 0, &wstrTo[0], -1, NULL, 0, NULL, NULL);
	std::string strTo(size_needed_gbk, 0);
	WideCharToMultiByte(CP_ACP, 0, &wstrTo[0], -1, &strTo[0], size_needed_gbk, NULL, NULL);

	return strTo;
}
int main()
{
	try {
		system("chcp 936");
		std::wcout.imbue(std::locale("chs"));
		std::wcout << "控制台输出中文" << std::endl;
		//setConsoleEncodingUTF8(); // 设置控制台编码为 UTF-8
		// 创建 ServicesControl 实例
		//ServicesControl svcCtrl(L"Delivery Optimization");
		auto svcCtrl = std::make_shared<WindowsServiceControl::ServicesControl>(L"Delivery Optimization");

		// 检查是否已具有管理员权限
		if (svcCtrl->isAdmin()) {
			std::cout << "Running with administrator permissions.\n";

			// 启动服务
			svcCtrl->startService(L"Delivery Optimization");
			std::cout << "Service started successfully.\n";

			// 停止服务
			svcCtrl->stopService(L"Delivery Optimization");
			std::cout << "Service stopped successfully.\n";
		}
		else {
			// 如果没有管理员权限,尝试提升权限
			svcCtrl->elevatePermissionsAndRun();
		}
	}
	catch (const std::runtime_error& e) {
		std::string str(e.what());
		std::string gbkStr = utf8ToGbk(str);
		std::cerr << "An error occurred: " << str << std::endl;
		return 1;
	}

	return 0;
}

4.完整代码如下:

头文件:

#pragma once

#include <windows.h>
#include <iostream>
#include <string>

namespace WindowsServiceControl {
	class IServicesControl 
	{
	public:
		virtual bool isAdmin() = 0;
		virtual bool elevatePermissionsAndRun() = 0;
		virtual bool startService(const std::wstring& serviceName) = 0;
		virtual bool stopService(const std::wstring& serviceName) = 0;
	};
}

#pragma once
#include "IServicesControl.h"

using namespace WindowsServiceControl;

namespace WindowsServiceControl {
	class ServicesControl : public IServicesControl {
	public:
		explicit ServicesControl(const std::wstring& serviceName);
		bool isAdmin() override;
		bool elevatePermissionsAndRun() override;
		bool startService(const std::wstring& serviceName) override;
		bool stopService(const std::wstring& serviceName) override;

		//getting,setting
		std::wstring getServiceName() { return _errorMessage; }
		void setServiceName(std::wstring& serviceName) { _serviceName = serviceName; }
	private:
		std::wstring _serviceName;
		std::wstring _errorMessage;
	private:
		std::wstring formatErrorMessage();
		std::string wstringToUtf8String(const std::wstring& wstr);
		void throwRuntimeErrorWithWstring(const std::wstring& wstr);
	};
}

实现文件

#include "ServicesControl.h"
#include <tchar.h>
#include <vector>
#include <stdexcept>
#include <sstream>


ServicesControl::ServicesControl(const std::wstring& serviceName) : _serviceName(serviceName)
{

}

bool ServicesControl::isAdmin()
{
	HANDLE hToken = nullptr;
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("Failed to open process token. Error code: " + std::to_string(lastError));
	}

	TOKEN_ELEVATION elevation;
	DWORD cbSize = sizeof(TOKEN_ELEVATION);

	if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &cbSize)) {
		CloseHandle(hToken);
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("Failed to get token information. Error code: " + std::to_string(lastError));
	}

	CloseHandle(hToken);

	if (elevation.TokenIsElevated == 0) {
		formatErrorMessage();
		throw std::runtime_error("The process is not running with administrator permissions.");
	}

	return true;
}

bool ServicesControl::elevatePermissionsAndRun()
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));

	TCHAR szCmdLine[MAX_PATH];
	_sntprintf_s(szCmdLine, MAX_PATH, _T("%s"), GetCommandLine());

	TCHAR szAppPath[MAX_PATH];
	GetModuleFileName(nullptr, szAppPath, MAX_PATH);

	// Attempt to launch the application with elevated privileges
	if (!CreateProcessAsUser(nullptr, szAppPath, szCmdLine, nullptr, nullptr, FALSE,
		CREATE_NEW_CONSOLE | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT,
		nullptr, nullptr, &si, &pi)) {
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("Failed to create process with elevated privileges. Error code: " + std::to_string(lastError));
	}

	// Wait for the process to finish
	WaitForSingleObject(pi.hProcess, INFINITE);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);

	return true;
}

bool ServicesControl::startService(const std::wstring& serviceName)
{
	SC_HANDLE hSCManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
	if (hSCManager == nullptr) {
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("OpenSCManager failed. Error code: " + std::to_string(lastError));
	}

	SC_HANDLE hService = OpenService(hSCManager, serviceName.c_str(), SERVICE_START | SERVICE_QUERY_STATUS);
	if (hService == nullptr) {
		CloseServiceHandle(hSCManager);
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("OpenService failed. Error code: " + std::to_string(lastError));
	}

	// Send start command
	if (!StartService(hService, 0, nullptr)) {
		CloseServiceHandle(hService);
		CloseServiceHandle(hSCManager);
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("StartService failed. Error code: " + std::to_string(lastError));
	}

	CloseServiceHandle(hService);
	CloseServiceHandle(hSCManager);

	return true;
}

bool ServicesControl::stopService(const std::wstring& serviceName)
{
	SC_HANDLE hSCManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
	if (hSCManager == nullptr) {
		DWORD lastError = GetLastError();
		throw std::runtime_error("OpenSCManager failed. Error code: " + std::to_string(lastError));
	}

	SC_HANDLE hService = OpenService(hSCManager, serviceName.c_str(), SERVICE_STOP | SERVICE_QUERY_STATUS);
	if (hService == nullptr) {
		CloseServiceHandle(hSCManager);
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("OpenService failed. Error code: " + std::to_string(lastError));
	}

	SERVICE_STATUS_PROCESS ssStatus;
	DWORD dwBytesNeeded;

	// Send stop command
	if (!ControlService(hService, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&ssStatus)) {
		CloseServiceHandle(hService);
		CloseServiceHandle(hSCManager);
		DWORD lastError = GetLastError();
		formatErrorMessage();
		throw std::runtime_error("ControlService failed. Error code: " + std::to_string(lastError));
	}

	// Wait for the service to stop
	while (QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssStatus, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded)) {
		if (ssStatus.dwCurrentState == SERVICE_STOPPED)
			break;
		Sleep(ssStatus.dwWaitHint);
	}

	CloseServiceHandle(hService);
	CloseServiceHandle(hSCManager);

	return true;
}

// Helper function to convert wide string to UTF-8 string
std::string ServicesControl::wstringToUtf8String(const std::wstring& wstr)
{
	if (wstr.empty()) return std::string();

	int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
	std::string strTo(size_needed, '\0');

	WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);

	return strTo;
}

void ServicesControl::throwRuntimeErrorWithWstring(const std::wstring& wstr) {
	std::string utf8Str = wstringToUtf8String(wstr);
	throw std::runtime_error(utf8Str);
}

std::wstring ServicesControl::formatErrorMessage()
{

	std::wstring errorMessage;
	wchar_t buffer[1024] = L"";
	DWORD lastError = GetLastError();
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		nullptr, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		buffer, 1024, nullptr);

	errorMessage = L"OpenService failed. Error code: " + std::to_wstring(lastError) + L". " + buffer;

	//std::string utf8Str = wideToUtf8(errorMessage);
	std::wcout << errorMessage << std::endl;
	throw std::runtime_error(wstringToUtf8String(errorMessage));
	//throw std::runtime_error(errorMessage);
}

测试代码

#include "ServicesControl.h" // 包含 ServicesControl 类的定义
#include <memory>
#include <io.h>
#include <fcntl.h>

using namespace WindowsServiceControl;

std::string utf8ToGbk(const std::string& utf8Str)
{
	int size_needed = MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), NULL, 0);
	std::wstring wstrTo(size_needed, 0);
	MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), &wstrTo[0], size_needed);

	int size_needed_gbk = WideCharToMultiByte(CP_ACP, 0, &wstrTo[0], -1, NULL, 0, NULL, NULL);
	std::string strTo(size_needed_gbk, 0);
	WideCharToMultiByte(CP_ACP, 0, &wstrTo[0], -1, &strTo[0], size_needed_gbk, NULL, NULL);

	return strTo;
}

int main()
{
	try {
		system("chcp 936");
		std::wcout.imbue(std::locale("chs"));
		std::wcout << "控制台输出中文" << std::endl;
		//setConsoleEncodingUTF8(); // 设置控制台编码为 UTF-8
		// 创建 ServicesControl 实例
		//ServicesControl svcCtrl(L"Delivery Optimization");
		auto svcCtrl = std::make_shared<WindowsServiceControl::ServicesControl>(L"Delivery Optimization");

		// 检查是否已具有管理员权限
		if (svcCtrl->isAdmin()) {
			std::cout << "Running with administrator permissions.\n";

			// 启动服务
			svcCtrl->startService(L"Delivery Optimization");
			std::cout << "Service started successfully.\n";

			// 停止服务
			svcCtrl->stopService(L"Delivery Optimization");
			std::cout << "Service stopped successfully.\n";
		}
		else {
			// 如果没有管理员权限,尝试提升权限
			svcCtrl->elevatePermissionsAndRun();
		}
	}
	catch (const std::runtime_error& e) {
		std::string str(e.what());
		std::string gbkStr = utf8ToGbk(str);
		std::cerr << "An error occurred: " << str << std::endl;
		return 1;
	}

	return 0;
}

输出打印

std::wcout,std::cout控制台输出中文乱码,std::cerr字符串的字符无效_std cerr_03