🙆‍♀️

RichEditコントロールでカラー絵文字を表示させる(要Office)

2022/05/10に公開

少し前にメモ帳アプリでカラー絵文字対応された記事が出ていましたが、
そこからリンクされたdevblogのコメントに、

you can already use the riched20.dll that comes with it. On my Surface Book, it’s located in C:\Program Files\Microsoft Office\root\vfs\ProgramFilesCommonX64\Microsoft Shared\OFFICE16

とありますので、試してみました。

やることは、

  1. Officeに付属するriched20.dllLoadLibraryする。
  2. ウィンドウクラスにRichEditD2Dを指定して、コントロールを作成する。

だけでできます。

環境

  • Windows 10
  • Microsoft 365(手元の環境だとOffice 2019で出来ました)がインストールされている必要があります。
  • x64環境のみ(x86のDLLが無いため)

Windows 11ならメモ帳アプリに付属するriched20.dllをロードすれば出来るような気がしますが、LoadLibraryでエラーになってしまいました。(UWPアプリのDLLだから?)

表示結果

  • RICHEDIT50Wでの表示
  • RichEditD2DPTクラスでの表示

簡単ですね!

メモ

  • RichEditD2DPTでも表示できた。
  • devblogではRichEditPTで作成したコントロールに対してEM_SWITCHTOD2Dメッセージをすることもできると書かれているが、絵文字を入力するとDLL内部クラッシュして出来なかった。
  • riched20.dllの再配布は許可されていないので、アプリケーションに組み込むのは難しい。

ソースコード

長いので折りたたんでます。
#include <SDKDDKVer.h>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Richedit.h>
#include <commctrl.h>
#pragma comment(lib, "Comctl32.lib")

#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <assert.h>

#define MY_CLASSNAME L"RichEditD2DDemoClass"

#if 0
#define MY_RICHEDITDLL L"MSFTEDIT.DLL"
#define MY_RICHEDIT_CLASS MSFTEDIT_CLASS
#else
#define MY_RICHEDITDLL L"C:\\Program Files\\Microsoft Office\\root\\vfs\\ProgramFilesCommonX64\\Microsoft Shared\\OFFICE16\\riched20.dll"
#define MY_RICHEDIT_CLASS L"RichEditD2D"
#endif

HINSTANCE g_hInst;
HWND g_hWndRichEdit;
BOOL InitInstance(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_CREATE:

		g_hWndRichEdit = CreateWindowEx(WS_EX_CLIENTEDGE,
			MY_RICHEDIT_CLASS,
			L"",
			WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL |
			ES_AUTOVSCROLL | ES_NOHIDESEL | ES_MULTILINE,
			0, 0, 100, 100,
			hWnd, NULL, g_hInst, NULL);
		assert(g_hWndRichEdit);
		SetWindowText(g_hWndRichEdit, L"😀");

		break;
	case WM_SIZE:
		MoveWindow(g_hWndRichEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	InitCommonControls();
	HMODULE hRichEdit = LoadLibrary(MY_RICHEDITDLL);
	assert(hRichEdit);

	{
		WNDCLASSEXW wcex = { .cbSize = sizeof(WNDCLASSEX) };
		wcex.style = CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc = WndProc;
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = hInstance;
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
		wcex.lpszClassName = MY_CLASSNAME;

		ATOM atom = RegisterClassExW(&wcex);
		assert(atom);
	}

	if (!InitInstance(hInstance, nCmdShow))
	{
		return FALSE;
	}

	MSG msg = { 0 };

	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	g_hInst = hInstance;

	HWND hWnd = CreateWindowW(MY_CLASSNAME, L"RichEditD2DDemo", WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

	if (!hWnd)
	{
		return FALSE;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	return TRUE;
}

Discussion