1 // Scintilla source code edit control
3 ** Korean Hanja Dictionary
4 ** Convert between Korean Hanja and Hangul by COM interface.
6 // Copyright 2015 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
10 #include <string_view>
13 #define WIN32_LEAN_AND_MEAN 1
20 namespace Scintilla::Internal::HanjaDict
{
26 enum HANJA_TYPE
{ HANJA_UNKNOWN
= 0, HANJA_K0
= 1, HANJA_K1
= 2, HANJA_OTHER
= 3 };
28 interface IHanjaDic
: IUnknown
{
29 STDMETHOD(OpenMainDic
)();
30 STDMETHOD(CloseMainDic
)();
31 STDMETHOD(GetHanjaWords
)(BSTR bstrHangul
, SAFEARRAY
* ppsaHanja
, VARIANT_BOOL
* pfFound
);
32 STDMETHOD(GetHanjaChars
)(unsigned short wchHangul
, BSTR
* pbstrHanjaChars
, VARIANT_BOOL
* pfFound
);
33 STDMETHOD(HanjaToHangul
)(BSTR bstrHanja
, BSTR
* pbstrHangul
);
34 STDMETHOD(GetHanjaType
)(unsigned short wchHanja
, HANJA_TYPE
* pHanjaType
);
35 STDMETHOD(GetHanjaSense
)(unsigned short wchHanja
, BSTR
* pbstrSense
);
36 STDMETHOD(GetRadicalID
)(short SeqNumOfRadical
, short* pRadicalID
, unsigned short* pwchRadical
);
37 STDMETHOD(GetRadical
)(short nRadicalID
, IRadical
** ppIRadical
);
38 STDMETHOD(RadicalIDToHanja
)(short nRadicalID
, unsigned short* pwchRadical
);
39 STDMETHOD(GetHanja
)(unsigned short wchHanja
, IHanja
** ppIHanja
);
40 STDMETHOD(GetStrokes
)(short nStrokes
, IStrokes
** ppIStrokes
);
41 STDMETHOD(OpenDefaultCustomDic
)();
42 STDMETHOD(OpenCustomDic
)(BSTR bstrPath
, long* plUdr
);
43 STDMETHOD(CloseDefaultCustomDic
)();
44 STDMETHOD(CloseCustomDic
)(long lUdr
);
45 STDMETHOD(CloseAllCustomDics
)();
46 STDMETHOD(GetDefaultCustomHanjaWords
)(BSTR bstrHangul
, SAFEARRAY
** ppsaHanja
, VARIANT_BOOL
* pfFound
);
47 STDMETHOD(GetCustomHanjaWords
)(long lUdr
, BSTR bstrHangul
, SAFEARRAY
** ppsaHanja
, VARIANT_BOOL
* pfFound
);
48 STDMETHOD(PutDefaultCustomHanjaWord
)(BSTR bstrHangul
, BSTR bstrHanja
);
49 STDMETHOD(PutCustomHanjaWord
)(long lUdr
, BSTR bstrHangul
, BSTR bstrHanja
);
50 STDMETHOD(MaxNumOfRadicals
)(short* pVal
);
51 STDMETHOD(MaxNumOfStrokes
)(short* pVal
);
52 STDMETHOD(DefaultCustomDic
)(long* pVal
);
53 STDMETHOD(DefaultCustomDic
)(long pVal
);
54 STDMETHOD(MaxHanjaType
)(HANJA_TYPE
* pHanjaType
);
55 STDMETHOD(MaxHanjaType
)(HANJA_TYPE pHanjaType
);
58 extern "C" const GUID
__declspec(selectany
) IID_IHanjaDic
=
59 { 0xad75f3ac, 0x18cd, 0x48c6, { 0xa2, 0x7d, 0xf1, 0xe9, 0xa7, 0xdc, 0xe4, 0x32 } };
64 ScopedBSTR() noexcept
= default;
65 explicit ScopedBSTR(const OLECHAR
*psz
) noexcept
:
66 bstr(SysAllocString(psz
)) {
68 explicit ScopedBSTR(OLECHAR character
) noexcept
:
69 bstr(SysAllocStringLen(&character
, 1)) {
71 // Deleted so ScopedBSTR objects can not be copied. Moves are OK.
72 ScopedBSTR(const ScopedBSTR
&) = delete;
73 ScopedBSTR
&operator=(const ScopedBSTR
&) = delete;
75 ScopedBSTR(ScopedBSTR
&&) = default;
76 ScopedBSTR
&operator=(ScopedBSTR
&&) = default;
81 BSTR
get() const noexcept
{
84 void reset(BSTR value
=nullptr) noexcept
{
85 // https://en.cppreference.com/w/cpp/memory/unique_ptr/reset
86 BSTR
const old
= bstr
;
93 std::unique_ptr
<IHanjaDic
, UnknownReleaser
> HJinterface
;
95 bool OpenHanjaDic(LPCOLESTR lpszProgID
) noexcept
{
97 HRESULT hr
= CLSIDFromProgID(lpszProgID
, &CLSID_HanjaDic
);
99 IHanjaDic
*instance
= nullptr;
100 hr
= CoCreateInstance(CLSID_HanjaDic
, nullptr,
101 CLSCTX_INPROC_SERVER
, IID_IHanjaDic
,
102 reinterpret_cast<LPVOID
*>(&instance
));
103 if (SUCCEEDED(hr
) && instance
) {
104 HJinterface
.reset(instance
);
105 hr
= instance
->OpenMainDic();
106 return SUCCEEDED(hr
);
113 bool Open() noexcept
{
114 return OpenHanjaDic(OLESTR("imkrhjd.hanjadic"))
115 || OpenHanjaDic(OLESTR("mshjdic.hanjadic"));
118 void Close() const noexcept
{
119 HJinterface
->CloseMainDic();
122 bool IsHanja(wchar_t hanja
) const noexcept
{
123 HANJA_TYPE hanjaType
= HANJA_UNKNOWN
;
124 const HRESULT hr
= HJinterface
->GetHanjaType(hanja
, &hanjaType
);
125 return SUCCEEDED(hr
) && hanjaType
> HANJA_UNKNOWN
;
128 bool HanjaToHangul(const ScopedBSTR
&bstrHanja
, ScopedBSTR
&bstrHangul
) const noexcept
{
129 BSTR result
= nullptr;
130 const HRESULT hr
= HJinterface
->HanjaToHangul(bstrHanja
.get(), &result
);
131 bstrHangul
.reset(result
);
132 return SUCCEEDED(hr
);
136 bool GetHangulOfHanja(std::wstring
&inout
) noexcept
{
137 // Convert every hanja to hangul.
138 // Return whether any character been converted.
139 // Hanja linked to different notes in Hangul have different codes,
140 // so current character based conversion is enough.
141 // great thanks for BLUEnLIVE.
142 bool changed
= false;
145 for (wchar_t &character
: inout
) {
146 if (dict
.IsHanja(character
)) { // Pass hanja only!
147 ScopedBSTR bstrHangul
;
148 if (dict
.HanjaToHangul(ScopedBSTR(character
), bstrHangul
)) {
150 character
= *(bstrHangul
.get());