4 changed files with 339 additions and 178 deletions
@ -0,0 +1,198 @@ |
|||||||
|
#include "InputSwitch.h" |
||||||
|
|
||||||
|
#include <shellscalingapi.h> |
||||||
|
#include <wrl/implements.h> |
||||||
|
#include <wil/result_macros.h> |
||||||
|
|
||||||
|
#define TB_POS_NOWHERE 0 |
||||||
|
#define TB_POS_BOTTOM 1 |
||||||
|
#define TB_POS_TOP 2 |
||||||
|
#define TB_POS_LEFT 3 |
||||||
|
#define TB_POS_RIGHT 4 |
||||||
|
extern "C" UINT GetTaskbarLocationAndSize(POINT ptCursor, RECT* rc); |
||||||
|
|
||||||
|
extern "C" __MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 dwIMEStyle; |
||||||
|
extern "C" HRESULT CInputSwitchControl_ModifyAnchor(UINT dwNumberOfProfiles, RECT* lpRect); |
||||||
|
|
||||||
|
HRESULT CInputSwitchControl_ModifyAnchor(UINT dwNumberOfProfiles, RECT* lpRect) |
||||||
|
{ |
||||||
|
if (!dwIMEStyle) // impossible case (this is not called for the Windows 11 language switcher), but just in case
|
||||||
|
{ |
||||||
|
return S_FALSE; |
||||||
|
} |
||||||
|
|
||||||
|
HWND hWndTaskbar = FindWindowW(L"Shell_TrayWnd", NULL); |
||||||
|
|
||||||
|
UINT dpiX = 96, dpiY = 96; |
||||||
|
HRESULT hr = GetDpiForMonitor( |
||||||
|
MonitorFromWindow(hWndTaskbar, MONITOR_DEFAULTTOPRIMARY), |
||||||
|
MDT_DEFAULT, |
||||||
|
&dpiX, |
||||||
|
&dpiY |
||||||
|
); |
||||||
|
double dpix = dpiX / 96.0; |
||||||
|
double dpiy = dpiY / 96.0; |
||||||
|
|
||||||
|
//printf("RECT %d %d %d %d - %d %d\n", lpRect->left, lpRect->right, lpRect->top, lpRect->bottom, dwNumberOfProfiles, a3);
|
||||||
|
|
||||||
|
RECT rc; |
||||||
|
GetWindowRect(hWndTaskbar, &rc); |
||||||
|
POINT pt; |
||||||
|
pt.x = rc.left; |
||||||
|
pt.y = rc.top; |
||||||
|
UINT tbPos = GetTaskbarLocationAndSize(pt, &rc); |
||||||
|
if (tbPos == TB_POS_BOTTOM) |
||||||
|
{ |
||||||
|
} |
||||||
|
else if (tbPos == TB_POS_TOP) |
||||||
|
{ |
||||||
|
if (dwIMEStyle == 1) // Windows 10 (with Language preferences link)
|
||||||
|
{ |
||||||
|
lpRect->top = rc.top + (rc.bottom - rc.top) + (UINT)(((double)dwNumberOfProfiles * (60.0 * dpiy)) + (5.0 * dpiy * 4.0) + (dpiy) + (48.0 * dpiy)); |
||||||
|
} |
||||||
|
else if (dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5) // LOGONUI, UAC, Windows 10, OOBE
|
||||||
|
{ |
||||||
|
lpRect->top = rc.top + (rc.bottom - rc.top) + (UINT)(((double)dwNumberOfProfiles * (60.0 * dpiy)) + (5.0 * dpiy * 2.0)); |
||||||
|
} |
||||||
|
} |
||||||
|
else if (tbPos == TB_POS_LEFT) |
||||||
|
{ |
||||||
|
if (dwIMEStyle == 1 || dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5) |
||||||
|
{ |
||||||
|
lpRect->right = rc.left + (rc.right - rc.left) + (UINT)((double)(300.0 * dpix)); |
||||||
|
lpRect->top += (lpRect->bottom - lpRect->top); |
||||||
|
} |
||||||
|
} |
||||||
|
if (tbPos == TB_POS_RIGHT) |
||||||
|
{ |
||||||
|
if (dwIMEStyle == 1 || dwIMEStyle == 2 || dwIMEStyle == 3 || dwIMEStyle == 4 || dwIMEStyle == 5) |
||||||
|
{ |
||||||
|
lpRect->right = lpRect->right - (rc.right - rc.left); |
||||||
|
lpRect->top += (lpRect->bottom - lpRect->top); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (dwIMEStyle == 4) |
||||||
|
{ |
||||||
|
lpRect->right -= (UINT)((double)(300.0 * dpix)) - (lpRect->right - lpRect->left); |
||||||
|
} |
||||||
|
|
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
|
||||||
|
class CInputSwitchControlProxy : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, IInputSwitchControl> |
||||||
|
{ |
||||||
|
public: |
||||||
|
CInputSwitchControlProxy() |
||||||
|
: m_type((__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001)-1) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT RuntimeClassInitialize(IInputSwitchControl* original) |
||||||
|
{ |
||||||
|
m_original = original; |
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 type) override |
||||||
|
{ |
||||||
|
m_type = type; |
||||||
|
return m_original->Init(type == ISCT_IDL_DESKTOP && dwIMEStyle != ISCT_IDL_DESKTOP ? dwIMEStyle : type); |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP ShowInputSwitch(const RECT* rect) override |
||||||
|
{ |
||||||
|
RECT myRect = *rect; |
||||||
|
if (m_type == ISCT_IDL_DESKTOP) |
||||||
|
{ |
||||||
|
UINT dwNumberOfProfiles = 0; |
||||||
|
BOOL bImePresent = FALSE; |
||||||
|
m_original->GetProfileCount(&dwNumberOfProfiles, &bImePresent); |
||||||
|
CInputSwitchControl_ModifyAnchor(dwNumberOfProfiles, &myRect); |
||||||
|
} |
||||||
|
return m_original->ShowInputSwitch(&myRect); |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP SetCallback(IInputSwitchCallback* callback) override { return m_original->SetCallback(callback); } |
||||||
|
STDMETHODIMP GetProfileCount(UINT* count, BOOL* bOutImePresent) override { return m_original->GetProfileCount(count, bOutImePresent); } |
||||||
|
STDMETHODIMP GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002* data) override { return m_original->GetCurrentProfile(data); } |
||||||
|
STDMETHODIMP RegisterHotkeys() override { return m_original->RegisterHotkeys(); } |
||||||
|
STDMETHODIMP ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004 type, POINT point, const RECT* rect) override { return m_original->ClickImeModeItem(type, point, rect); } |
||||||
|
STDMETHODIMP ForceHide() override { return m_original->ForceHide(); } |
||||||
|
STDMETHODIMP ShowTouchKeyboardInputSwitch(const RECT* rect, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006 align, int a3, DWORD a4, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005 a5) override { return m_original->ShowTouchKeyboardInputSwitch(rect, align, a3, a4, a5); } |
||||||
|
STDMETHODIMP GetContextFlags(DWORD* flags) override { return m_original->GetContextFlags(flags); } |
||||||
|
STDMETHODIMP SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008 mode) override { return m_original->SetContextOverrideMode(mode); } |
||||||
|
STDMETHODIMP GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003* data) override { return m_original->GetCurrentImeModeItem(data); } |
||||||
|
STDMETHODIMP ActivateInputProfile(const WCHAR* profile) override { return m_original->ActivateInputProfile(profile); } |
||||||
|
STDMETHODIMP SetUserSid(const WCHAR* sid) override { return m_original->SetUserSid(sid); } |
||||||
|
|
||||||
|
private: |
||||||
|
Microsoft::WRL::ComPtr<IInputSwitchControl> m_original; |
||||||
|
__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 m_type; |
||||||
|
}; |
||||||
|
|
||||||
|
HRESULT CInputSwitchControlProxy_CreateInstance(IInputSwitchControl* original, REFIID riid, void** ppvObject) |
||||||
|
{ |
||||||
|
Microsoft::WRL::ComPtr<CInputSwitchControlProxy> proxy; |
||||||
|
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CInputSwitchControlProxy>(&proxy, original)); |
||||||
|
RETURN_HR(proxy.CopyTo(riid, ppvObject)); |
||||||
|
} |
||||||
|
|
||||||
|
class CInputSwitchControlProxySV2 : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, IInputSwitchControlSV2> |
||||||
|
{ |
||||||
|
public: |
||||||
|
CInputSwitchControlProxySV2() |
||||||
|
: m_type((__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001)-1) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT RuntimeClassInitialize(IInputSwitchControlSV2* original) |
||||||
|
{ |
||||||
|
m_original = original; |
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 type) override |
||||||
|
{ |
||||||
|
m_type = type; |
||||||
|
return m_original->Init(type == ISCT_IDL_DESKTOP && dwIMEStyle != ISCT_IDL_DESKTOP ? dwIMEStyle : type); |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP ShowInputSwitch(const RECT* rect) override |
||||||
|
{ |
||||||
|
RECT myRect = *rect; |
||||||
|
if (m_type == ISCT_IDL_DESKTOP) |
||||||
|
{ |
||||||
|
UINT dwNumberOfProfiles = 0; |
||||||
|
BOOL bImePresent = FALSE; |
||||||
|
m_original->GetProfileCount(&dwNumberOfProfiles, &bImePresent); |
||||||
|
CInputSwitchControl_ModifyAnchor(dwNumberOfProfiles, &myRect); |
||||||
|
} |
||||||
|
return m_original->ShowInputSwitch(&myRect); |
||||||
|
} |
||||||
|
|
||||||
|
STDMETHODIMP SetCallback(IInputSwitchCallback* callback) override { return m_original->SetCallback(callback); } |
||||||
|
STDMETHODIMP GetProfileCount(UINT* count, BOOL* bOutImePresent) override { return m_original->GetProfileCount(count, bOutImePresent); } |
||||||
|
STDMETHODIMP GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002* data) override { return m_original->GetCurrentProfile(data); } |
||||||
|
STDMETHODIMP RegisterHotkeys() override { return m_original->RegisterHotkeys(); } |
||||||
|
STDMETHODIMP ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004 type, POINT point, const RECT* rect) override { return m_original->ClickImeModeItem(type, point, rect); } |
||||||
|
STDMETHODIMP ClickImeModeItemWithAnchor(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004 type, IUnknown* anchor) override { return m_original->ClickImeModeItemWithAnchor(type, anchor); } |
||||||
|
STDMETHODIMP ForceHide() override { return m_original->ForceHide(); } |
||||||
|
STDMETHODIMP ShowTouchKeyboardInputSwitch(const RECT* rect, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006 align, int a3, DWORD a4, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005 a5) override { return m_original->ShowTouchKeyboardInputSwitch(rect, align, a3, a4, a5); } |
||||||
|
STDMETHODIMP GetContextFlags(DWORD* flags) override { return m_original->GetContextFlags(flags); } |
||||||
|
STDMETHODIMP SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008 mode) override { return m_original->SetContextOverrideMode(mode); } |
||||||
|
STDMETHODIMP GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003* data) override { return m_original->GetCurrentImeModeItem(data); } |
||||||
|
STDMETHODIMP ActivateInputProfile(const WCHAR* profile) override { return m_original->ActivateInputProfile(profile); } |
||||||
|
STDMETHODIMP SetUserSid(const WCHAR* sid) override { return m_original->SetUserSid(sid); } |
||||||
|
|
||||||
|
private: |
||||||
|
Microsoft::WRL::ComPtr<IInputSwitchControlSV2> m_original; |
||||||
|
__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 m_type; |
||||||
|
}; |
||||||
|
|
||||||
|
HRESULT CInputSwitchControlProxySV2_CreateInstance(IInputSwitchControlSV2* original, REFIID riid, void** ppvObject) |
||||||
|
{ |
||||||
|
Microsoft::WRL::ComPtr<CInputSwitchControlProxySV2> proxy; |
||||||
|
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CInputSwitchControlProxySV2>(&proxy, original)); |
||||||
|
RETURN_HR(proxy.CopyTo(riid, ppvObject)); |
||||||
|
} |
||||||
@ -0,0 +1,122 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <Windows.h> |
||||||
|
|
||||||
|
DEFINE_GUID(CLSID_InputSwitchControl, 0xb9bc2a50, 0x43c3, 0x41aa, 0xa0, 0x86, 0x5d, 0xb1, 0x4e, 0x18, 0x4b, 0xae); |
||||||
|
DEFINE_GUID(IID_IInputSwitchControl, 0xb9bc2a50, 0x43c3, 0x41aa, 0xa0, 0x82, 0x5d, 0xb1, 0x4e, 0x18, 0x4b, 0xae); |
||||||
|
|
||||||
|
enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0001 |
||||||
|
{ |
||||||
|
ISCT_IDL_DESKTOP, |
||||||
|
ISCT_IDL_TOUCHKEYBOARD, |
||||||
|
ISCT_IDL_LOGONUI, |
||||||
|
ISCT_IDL_UAC, |
||||||
|
ISCT_IDL_SETTINGSPANE, |
||||||
|
ISCT_IDL_OOBE, |
||||||
|
ISCT_IDL_USEROOBE |
||||||
|
}; |
||||||
|
|
||||||
|
struct __MIDL___MIDL_itf_inputswitchserver_0000_0000_0002 |
||||||
|
{ |
||||||
|
int dummy; // We don't need its contents
|
||||||
|
}; |
||||||
|
|
||||||
|
struct __MIDL___MIDL_itf_inputswitchserver_0000_0000_0003 |
||||||
|
{ |
||||||
|
WCHAR* pszTooltip; |
||||||
|
HICON hIcon; |
||||||
|
BOOL fDisabled; |
||||||
|
BOOL fHidden; |
||||||
|
WCHAR* pszIconGlyph; |
||||||
|
}; |
||||||
|
|
||||||
|
enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0004 |
||||||
|
{ |
||||||
|
INPUT_SWITCH_IDL_IME_CLICK_TYPE_LEFT, |
||||||
|
INPUT_SWITCH_IDL_IME_CLICK_TYPE_RIGHT, |
||||||
|
INPUT_SWITCH_IDL_IME_CLICK_TYPE_LEFT_DISABLED |
||||||
|
}; |
||||||
|
|
||||||
|
enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005 |
||||||
|
{ |
||||||
|
INPUT_SWITCH_IDL_MODALITY_STANDARDKEYBOARD = 0x1, |
||||||
|
INPUT_SWITCH_IDL_MODALITY_SPLITKEYBOARD = 0x2, |
||||||
|
INPUT_SWITCH_IDL_MODALITY_CLASSICKEYBOARD = 0x4, |
||||||
|
INPUT_SWITCH_IDL_MODALITY_HANDWRITING = 0x8, |
||||||
|
INPUT_SWITCH_IDL_MODALITY_HIDE = 0x10, |
||||||
|
INPUT_SWITCH_IDL_MODALITY_ONEHANDEDKEYBOARD = 0x20, |
||||||
|
}; |
||||||
|
|
||||||
|
enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006 |
||||||
|
{ |
||||||
|
INPUT_SWITCH_IDL_ALIGN_DEFAULT, |
||||||
|
INPUT_SWITCH_IDL_ALIGN_RIGHT_EDGE, |
||||||
|
INPUT_SWITCH_IDL_ALIGN_LEFT_EDGE, |
||||||
|
}; |
||||||
|
|
||||||
|
enum __MIDL___MIDL_itf_inputswitchserver_0000_0000_0008 |
||||||
|
{ |
||||||
|
INPUT_SWITCH_IDL_CFOM_NO_OVERRIDE, |
||||||
|
INPUT_SWITCH_IDL_CFOM_DESKTOP, |
||||||
|
INPUT_SWITCH_IDL_CFOM_IMMERSIVE, |
||||||
|
}; |
||||||
|
|
||||||
|
interface IInputSwitchCallback; |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
MIDL_INTERFACE("b9bc2a50-43c3-41aa-a082-5db14e184bae") |
||||||
|
IInputSwitchControl : IUnknown |
||||||
|
{ |
||||||
|
virtual HRESULT STDMETHODCALLTYPE Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetCallback(IInputSwitchCallback*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ShowInputSwitch(const RECT*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetProfileCount(UINT*, BOOL*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE RegisterHotkeys() = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004, POINT, const RECT*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ForceHide() = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ShowTouchKeyboardInputSwitch(const RECT*, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006, int, DWORD, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetContextFlags(DWORD*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ActivateInputProfile(const WCHAR*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetUserSid(const WCHAR*) = 0; |
||||||
|
}; |
||||||
|
#else |
||||||
|
typedef interface IInputSwitchControl IInputSwitchControl; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
MIDL_INTERFACE("b9bc2a50-43c3-41aa-a082-5db14e184bae") |
||||||
|
IInputSwitchControlSV2 : IUnknown |
||||||
|
{ |
||||||
|
virtual HRESULT STDMETHODCALLTYPE Init(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0001) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetCallback(IInputSwitchCallback*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ShowInputSwitch(const RECT*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetProfileCount(UINT*, BOOL*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetCurrentProfile(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0002*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE RegisterHotkeys() = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ClickImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004, POINT, const RECT*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ClickImeModeItemWithAnchor(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0004, IUnknown*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ForceHide() = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ShowTouchKeyboardInputSwitch(const RECT*, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0006, int, DWORD, __MIDL___MIDL_itf_inputswitchserver_0000_0000_0005) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetContextFlags(DWORD*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetContextOverrideMode(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0008) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE GetCurrentImeModeItem(__MIDL___MIDL_itf_inputswitchserver_0000_0000_0003*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE ActivateInputProfile(const WCHAR*) = 0; |
||||||
|
virtual HRESULT STDMETHODCALLTYPE SetUserSid(const WCHAR*) = 0; |
||||||
|
}; |
||||||
|
#else |
||||||
|
typedef interface IInputSwitchControlSV2 IInputSwitchControlSV2; |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
HRESULT CInputSwitchControlProxy_CreateInstance(IInputSwitchControl* original, REFIID riid, void** ppvObject); |
||||||
|
HRESULT CInputSwitchControlProxySV2_CreateInstance(IInputSwitchControlSV2* original, REFIID riid, void** ppvObject); |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
||||||
Loading…
Reference in new issue