最終更新日 2024-09-25

その他② リスト候補の取得と強制追加

概要

「HmAutoCompleteEx.dll」を利用することで、入力補完が出力時に強制的に候補に新しい項目を追加することが出来ます。
また、どんな候補が出ているのかを知ることができます。
但し、異常に重たくなってしまわないように、候補の取得や強制挿入は最大でも「1000」個までとなっています。

リスト候補の取得と強制追加

#include <windows.h>
#include <vector>

#include "OutputDebugStream.h"

using namespace std;

extern void PrintList(vector<wstring> list);


struct AUTOCOMPLETELIST {
	LPTSTR wstring_ptr_list[1000]; // やり取りするのは1000個まで
	size_t list_size;
};
extern "C" __declspec(dllexport) AUTOCOMPLETELIST* OnQueryListBoxCustomAdded(HWND hWnd, AUTOCOMPLETELIST *pAutoCompleteOriginalList) {

	//------------------------------ 受け取り部
	// 今回のリストを受けるにあたって、前回までのをクリア
	static vector<wstring> original_list;
	original_list.clear();

	// 元々のリストを受け取る。(ただし、最初の1000個まで)
	// char **をvector<wstring>へ
	if (pAutoCompleteOriginalList->wstring_ptr_list) {
		for (size_t ix = 0; ix<pAutoCompleteOriginalList->list_size; ix++) {

			// 配列に文字列をコピーして追加
			original_list.push_back(wstring(pAutoCompleteOriginalList->wstring_ptr_list[ix]));
		}
	}
	//------------------------------ 受け取り部 ここまで

	OutputDebugStream("元のリストの先頭の方:\n");
	PrintList(original_list);


	// 永続する必要があるので、static忘れないこと。
	static vector<wstring> addition_list;
	addition_list.clear(); // staticなので、毎度のクリアは必須である。

	addition_list.push_back(L"あああ");
	addition_list.push_back(L"いいい");



	//------------------------------ 引き渡し部
	// 特別に追加するリストへのポインタを返す
	// static を忘れないように
	static AUTOCOMPLETELIST AutoCompleteAddiList{ 0 };
	ZeroMemory(&AutoCompleteAddiList, sizeof(AutoCompleteAddiList)); // staticなのでクリアを忘れないこと

	// 追加していく。(追加数自体が1000個を超えないように注意)
	for (size_t i = 0; i < addition_list.size() && i < 1000; i++) {
		AutoCompleteAddiList.wstring_ptr_list[i] = (LPTSTR)addition_list[i].data();
	}
	AutoCompleteAddiList.list_size = addition_list.size();
	return &AutoCompleteAddiList;
	//------------------------------ 引き渡し部 ここまで
}

void PrintList(vector<wstring> list) {
	// 最初の5個をプリント
	for (int i = 0; i < list.size() && i < 5; i++) {
		OutputDebugStream(L"%s", list[i].data());
	}
}

解説

HmAutoCompleteEx.dll本体との情報のやり取りは

struct AUTOCOMPLETELIST {
  LPTSTR wstring_ptr_list[1000]; // やり取りするのは1000個まで
  size_t list_size;
};

にて行います。

先頭から挿入するのではなく、2番目のアイテム以降に挿入されます。
(先頭の要素と秀丸の入力補完はかなり密接に絡みついているため、
秀丸の仕様変更の影響を受けにくいように、2番目以降に追加しています。

1000個まで、というのは、それ以上の入力候補がある時を対象としても
普段のパフォーマンスが低下するだけで、あまり有意ではないだろうという判断です。

「データの受け取り」については、少々どのように受け取っても自由ですが、
「追加候補の引き渡し」については、各々の文字列を指すポインタを引き渡す形になりますので、
肝心の文字列である実態が残っている必要があります。

(グローバル変数であったり、staticなりにする必要があるということです。)