-
-
Save GmavionR/404508628370d4913b9484eeef9546a2 to your computer and use it in GitHub Desktop.
Apply dark theme to your built-in MsgBox.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************ | |
* @description Apply dark theme to the built-in MsgBox. | |
* @file Dark_MsgBox.ahk | |
* @link https://gist.github.com/nperovic/0b9a511eda773f9304813a6ad9eec137 | |
* @author Nikola Perovic | |
* @date 2024/04/20 | |
* @version 1.0.1 | |
***********************************************************************/ | |
#Requires AutoHotkey v2.1-alpha.9 | |
#DllLoad gdi32.dll | |
; for v2.1.alpha.9 or later | |
class POINT { | |
x: i32, y: i32 | |
} | |
class RECT { | |
left: i32, top: i32, right: i32, bottom: i32 | |
} | |
/* | |
; for v2.0.12 or later | |
POINT(x := 0, y := 0) { | |
NumPut("int", x, "int", y, buf := Buffer(8)) | |
buf.DefineProp("x", {Get: NumGet.Bind(, 0, "int"), Set: IntPut.Bind(0)}) | |
buf.DefineProp("y", {Get: NumGet.Bind(, 4, "int"), Set: IntPut.Bind(4)}) | |
return buf | |
} | |
RECT(left := 0, top := 0, right := 0, bottom := 0){ | |
static ofst := Map("left", 0, "top", 4, "right", 8, "bottom", 12) | |
NumPut("int", left, "int", top, "int", right, "int", bottom, buf := Buffer(16)) | |
for k, v in ofst | |
buf.DefineProp(k, {Get: NumGet.Bind(, v, "int"), Set: IntPut.Bind(v)}) | |
return buf | |
} | |
IntPut(ofst, _, v) => NumPut("int", v, _, ofst) | |
*/ | |
class __MsgBox | |
{ | |
static __New() | |
{ | |
/** Thanks to geekdude & Mr Doge for providing this method to rewrite built-in functions. */ | |
static nativeMsgbox := MsgBox.Call.Bind(MsgBox) | |
MsgBox.DefineProp("Call", {Call: MsgBoxEx}) | |
MsgBoxEx(_this, text?, title?, options?, iconFile := "", iconNumber := 1) | |
{ | |
static WM_COMMNOTIFY := 0x44 | |
SetThreadDpiAwarenessContext(-4) | |
OnMessage(WM_COMMNOTIFY, ON_WM_COMMNOTIFY, -1) | |
return nativeMsgbox(text?, title?, options?) | |
ON_WM_COMMNOTIFY(wParam, lParam, msg, hwnd) | |
{ | |
DetectHiddenWindows(true) | |
if (msg = 68 && wParam = 1027) | |
EnumThreadWindows(GetCurrentThreadId(), CallbackCreate(WNDENUMPROC), 0) | |
} | |
WNDENUMPROC(hwnd, *) | |
{ | |
static SM_CICON := "W" SysGet(11) " H" SysGet(12) | |
static SM_CSMICON := "W" SysGet(49) " H" SysGet(50) | |
static ICON_BIG := 1 | |
static ICON_SMALL := 0 | |
static WM_SETICON := 0x80 | |
static WS_CLIPCHILDREN := 0x02000000 | |
static WS_CLIPSIBLINGS := 0x04000000 | |
static WS_EX_COMPOSITED := 0x02000000 | |
static WS_VSCROLL := 0x00200000 | |
static winAttrMap := Map(2, 2, 4, 0, 10, true, 17, true, 20, true, 38, 2, 35, 0x2b2b2b) ; 34, 0xFFFFFFFE, | |
Critical() | |
SetWinDelay(-1) | |
SetControlDelay(-1) | |
DetectHiddenWindows(true) | |
if !WinExist("ahk_class #32770 ahk_id" hwnd) | |
return 1 | |
WinSetStyle("+" (WS_CLIPCHILDREN | WS_CLIPSIBLINGS)) | |
WinSetExStyle("+" (WS_EX_COMPOSITED)) | |
SetWindowTheme(hwnd, "DarkMode_Explorer") | |
if iconFile { | |
hICON_SMALL := LoadPicture(iconFile, SM_CSMICON " Icon" iconNumber, &handleType) | |
hICON_BIG := LoadPicture(iconFile, SM_CICON " Icon" iconNumber, &handleType) | |
PostMessage(WM_SETICON, ICON_SMALL, hICON_SMALL) | |
PostMessage(WM_SETICON, ICON_BIG, hICON_BIG) | |
} | |
for dwAttribute, pvAttribute in winAttrMap | |
DwmSetWindowAttribute(hwnd, dwAttribute, pvAttribute) | |
OnMessage(0x44, ON_WM_COMMNOTIFY, 0) | |
GWL_WNDPROC(hwnd, hICON_SMALL?, hICON_BIG?) | |
return 0 | |
} | |
GWL_WNDPROC(winId := "", hIcons*) | |
{ | |
static SetWindowLong := DllCall.Bind(A_PtrSize = 8 ? "SetWindowLongPtr" : "SetWindowLong", "ptr",, "int",, "ptr",, "ptr") | |
static BS_FLAT := 0x8000 | |
static BS_BITMAP := 0x0080 | |
static DPI := (A_ScreenDPI / 96) | |
static WM_CLOSE := 0x0010 | |
static WM_CTLCOLORBTN := 0x0135 | |
static WM_CTLCOLORDLG := 0x0136 | |
static WM_CTLCOLORSTATIC := 0x0138 | |
static WM_DESTROY := 0x0002 | |
static WM_SETREDRAW := 0x000B | |
DetectHiddenWindows(true) | |
SetControlDelay(-1) | |
btns := [] | |
btnHwnd := hbrush1 := hbrush2 := "" | |
for ctrl in WinGetControlsHwnd(winId) | |
{ | |
SetWindowTheme(ctrl, "DarkMode_Explorer") | |
if !InStr(ControlGetClassNN(ctrl), "B") | |
continue | |
ControlSetStyle("+" (BS_FLAT | BS_BITMAP), ctrl) | |
btns.Push(btnHwnd := ctrl) | |
} | |
WindowProcOld := SetWindowLong(winId, -4, CallbackCreate(WNDPROC)) | |
WNDPROC(hwnd, uMsg, wParam, lParam) | |
{ | |
Critical(-1) | |
DetectHiddenWindows(true) | |
SetWinDelay(-1) | |
SetControlDelay(-1) | |
if !hbrush1 | |
hbrush1 := CreateSolidBrush(0x202020) | |
if !hbrush2 | |
hbrush2 := CreateSolidBrush(0x2b2b2b) | |
switch uMsg { | |
case WM_CTLCOLORSTATIC: | |
{ | |
SelectObject(wParam, hbrush2) | |
SetBkMode(wParam, 0) | |
SetTextColor(wParam, 0xFFFFFF) | |
SetBkColor(wParam, 0x2b2b2b) | |
for _hwnd in btns | |
PostMessage(WM_SETREDRAW,,,_hwnd) | |
GetWindowRect(winId, rcW := RECT()) | |
GetClientRect(winId, rcC := RECT()) | |
GetWindowRect(btnHwnd, rcBtn := RECT()) | |
pt := POINT() | |
pt.y := rcW.bottom - rcBtn.bottom | |
ScreenToClient(winId, pt) | |
hdc := GetWindowDC(winId) | |
rcC.top := rcBtn.top + pt.y -2 | |
rcC.bottom *= 2 | |
rcC.right *= 2 | |
SetBkMode(hdc, 0) | |
FillRect(hdc, rcC, hbrush1) | |
ReleaseDC(winId, hdc) | |
for _hwnd in btns | |
PostMessage(WM_SETREDRAW, 1,,_hwnd) | |
return hbrush2 | |
} | |
case WM_CTLCOLORDLG: | |
{ | |
SelectObject(wParam, hbrush2) | |
SetBkMode(wParam, 0) | |
SetTextColor(wParam, 0xFFFFFF) | |
SetBkColor(wParam, 0x2b2b2b) | |
return hbrush2 | |
} | |
case WM_CTLCOLORBTN: | |
{ | |
SelectObject(wParam, hbrush1) | |
SetBkMode(wParam, 0) | |
SetTextColor(wParam, 0xFFFFFF) | |
SetBkColor(wParam, 0x202020) | |
return hbrush2 | |
} | |
case WM_DESTROY: | |
{ | |
for v in [hbrush1, hbrush2] | |
(v && DeleteObject(v)) | |
for hIcon in hIcons | |
(hIcon??0) && DestroyIcon(hIcon) | |
}} | |
return CallWindowProc(WindowProcOld, hwnd, uMsg, wParam, lParam) | |
} | |
} | |
} | |
CallWindowProc(lpPrevWndFunc, hWnd, uMsg, wParam, lParam) => DllCall("CallWindowProc", "Ptr", lpPrevWndFunc, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam) | |
ClientToScreen(hWnd, lpPoint) => DllCall("User32\ClientToScreen", "ptr", hWnd, "ptr", lpPoint, "int") | |
CreateSolidBrush(crColor) => DllCall('Gdi32\CreateSolidBrush', 'uint', crColor, 'ptr') | |
DestroyIcon(hIcon) => DllCall("DestroyIcon", "ptr", hIcon) | |
/** @see — https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute */ | |
DWMSetWindowAttribute(hwnd, dwAttribute, pvAttribute, cbAttribute := 4) => DllCall("Dwmapi\DwmSetWindowAttribute", "Ptr" , hwnd, "UInt", dwAttribute, "Ptr*", &pvAttribute, "UInt", cbAttribute) | |
DeleteObject(hObject) => DllCall('Gdi32\DeleteObject', 'ptr', hObject, 'int') | |
EnumThreadWindows(dwThreadId, lpfn, lParam) => DllCall("User32\EnumThreadWindows", "uint", dwThreadId, "ptr", lpfn, "uptr", lParam, "int") | |
FillRect(hDC, lprc, hbr) => DllCall("User32\FillRect", "ptr", hDC, "ptr", lprc, "ptr", hbr, "int") | |
GetClientRect(hWnd, lpRect) => DllCall("User32\GetClientRect", "ptr", hWnd, "ptr", lpRect, "int") | |
GetCurrentThreadId() => DllCall("Kernel32\GetCurrentThreadId", "uint") | |
GetWindowDC(hwnd) => DllCall("User32\GetWindowDC", "ptr", hwnd, "ptr") | |
GetWindowRect(hWnd, lpRect) => DllCall("User32\GetWindowRect", "ptr", hWnd, "ptr", lpRect, "uptr") | |
GetWindowRgn(hWnd, hRgn) => DllCall("User32\GetWindowRgn", "ptr", hWnd, "ptr", hRgn, "int") | |
GetWindowRgnBox(hWnd, hRgn) => DllCall("User32\GetWindowRgnBox", "ptr", hWnd, "ptr", hRgn, "int") | |
ReleaseDC(hWnd, hDC) => DllCall("User32\ReleaseDC", "ptr", hWnd, "ptr", hDC, "int") | |
ScreenToClient(hWnd, lpPoint) => DllCall("User32\ScreenToClient", "ptr", hWnd, "ptr", lpPoint, "int") | |
SelectObject(hdc, hgdiobj) => DllCall('Gdi32\SelectObject', 'ptr', hdc, 'ptr', hgdiobj, 'ptr') | |
SetBkColor(hdc, crColor) => DllCall('Gdi32\SetBkColor', 'ptr', hdc, 'uint', crColor, 'uint') | |
SetBkMode(hdc, iBkMode) => DllCall('Gdi32\SetBkMode', 'ptr', hdc, 'int', iBkMode, 'int') | |
SetTextColor(hdc, crColor) => DllCall('Gdi32\SetTextColor', 'ptr', hdc, 'uint', crColor, 'uint') | |
SetThreadDpiAwarenessContext(dpiContext) => DllCall("SetThreadDpiAwarenessContext", "ptr", dpiContext, "ptr") | |
SetWindowTheme(hwnd, pszSubAppName, pszSubIdList := "") => (!DllCall("uxtheme\SetWindowTheme", "ptr", hwnd, "ptr", StrPtr(pszSubAppName), "ptr", pszSubIdList ? StrPtr(pszSubIdList) : 0) ? true : false) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************ | |
* @description Apply dark theme to the built-in MsgBox. | |
* @file Dark_MsgBox_v2.ahk | |
* @link https://gist.github.com/nperovic/0b9a511eda773f9304813a6ad9eec137 | |
* @author Nikola Perovic | |
* @date 2024/04/20 | |
* @version 1.0.1 | |
***********************************************************************/ | |
#Requires AutoHotkey v2 | |
#DllLoad gdi32.dll | |
/* | |
; for v2.1.alpha.9 or later | |
class POINT { | |
x: i32, y: i32 | |
} | |
class RECT { | |
left: i32, top: i32, right: i32, bottom: i32 | |
} | |
*/ | |
; for v2.0 or later | |
POINT(x := 0, y := 0) { | |
NumPut("int", x, "int", y, buf := Buffer(8)) | |
buf.DefineProp("x", {Get: NumGet.Bind(, 0, "int"), Set: IntPut.Bind(0)}) | |
buf.DefineProp("y", {Get: NumGet.Bind(, 4, "int"), Set: IntPut.Bind(4)}) | |
return buf | |
} | |
RECT(left := 0, top := 0, right := 0, bottom := 0){ | |
static ofst := Map("left", 0, "top", 4, "right", 8, "bottom", 12) | |
NumPut("int", left, "int", top, "int", right, "int", bottom, buf := Buffer(16)) | |
for k, v in ofst | |
buf.DefineProp(k, {Get: NumGet.Bind(, v, "int"), Set: IntPut.Bind(v)}) | |
return buf | |
} | |
IntPut(ofst, _, v) => NumPut("int", v, _, ofst) | |
class __MsgBox | |
{ | |
static __New() | |
{ | |
/** Thanks to geekdude & Mr Doge for providing this method to rewrite built-in functions. */ | |
static nativeMsgbox := MsgBox.Call.Bind(MsgBox) | |
MsgBox.DefineProp("Call", {Call: MsgBoxEx}) | |
MsgBoxEx(_this, text?, title?, options?, iconFile := "", iconNumber := 1) | |
{ | |
static WM_COMMNOTIFY := 0x44 | |
SetThreadDpiAwarenessContext(-4) | |
OnMessage(WM_COMMNOTIFY, ON_WM_COMMNOTIFY, -1) | |
return nativeMsgbox(text?, title?, options?) | |
ON_WM_COMMNOTIFY(wParam, lParam, msg, hwnd) | |
{ | |
DetectHiddenWindows(true) | |
if (msg = 68 && wParam = 1027) | |
EnumThreadWindows(GetCurrentThreadId(), CallbackCreate(WNDENUMPROC), 0) | |
} | |
WNDENUMPROC(hwnd, *) | |
{ | |
static SM_CICON := "W" SysGet(11) " H" SysGet(12) | |
static SM_CSMICON := "W" SysGet(49) " H" SysGet(50) | |
static ICON_BIG := 1 | |
static ICON_SMALL := 0 | |
static WM_SETICON := 0x80 | |
static WS_CLIPCHILDREN := 0x02000000 | |
static WS_CLIPSIBLINGS := 0x04000000 | |
static WS_EX_COMPOSITED := 0x02000000 | |
static WS_VSCROLL := 0x00200000 | |
static winAttrMap := Map(2, 2, 4, 0, 10, true, 17, true, 20, true, 38, 2, 35, 0x2b2b2b) ; 34, 0xFFFFFFFE, | |
Critical() | |
SetWinDelay(-1) | |
SetControlDelay(-1) | |
DetectHiddenWindows(true) | |
if !WinExist("ahk_class #32770 ahk_id" hwnd) | |
return 1 | |
WinSetStyle("+" (WS_CLIPCHILDREN | WS_CLIPSIBLINGS)) | |
WinSetExStyle("+" (WS_EX_COMPOSITED)) | |
SetWindowTheme(hwnd, "DarkMode_Explorer") | |
if iconFile { | |
hICON_SMALL := LoadPicture(iconFile, SM_CSMICON " Icon" iconNumber, &handleType) | |
hICON_BIG := LoadPicture(iconFile, SM_CICON " Icon" iconNumber, &handleType) | |
PostMessage(WM_SETICON, ICON_SMALL, hICON_SMALL) | |
PostMessage(WM_SETICON, ICON_BIG, hICON_BIG) | |
} | |
for dwAttribute, pvAttribute in winAttrMap | |
DwmSetWindowAttribute(hwnd, dwAttribute, pvAttribute) | |
OnMessage(0x44, ON_WM_COMMNOTIFY, 0) | |
GWL_WNDPROC(hwnd, hICON_SMALL?, hICON_BIG?) | |
return 0 | |
} | |
GWL_WNDPROC(winId := "", hIcons*) | |
{ | |
static SetWindowLong := DllCall.Bind(A_PtrSize = 8 ? "SetWindowLongPtr" : "SetWindowLong", "ptr",, "int",, "ptr",, "ptr") | |
static BS_FLAT := 0x8000 | |
static BS_BITMAP := 0x0080 | |
static DPI := (A_ScreenDPI / 96) | |
static WM_CLOSE := 0x0010 | |
static WM_CTLCOLORBTN := 0x0135 | |
static WM_CTLCOLORDLG := 0x0136 | |
static WM_CTLCOLORSTATIC := 0x0138 | |
static WM_DESTROY := 0x0002 | |
static WM_SETREDRAW := 0x000B | |
DetectHiddenWindows(true) | |
SetControlDelay(-1) | |
btns := [] | |
btnHwnd := hbrush1 := hbrush2 := "" | |
for ctrl in WinGetControlsHwnd(winId) | |
{ | |
SetWindowTheme(ctrl, "DarkMode_Explorer") | |
if !InStr(ControlGetClassNN(ctrl), "B") | |
continue | |
ControlSetStyle("+" (BS_FLAT | BS_BITMAP), ctrl) | |
btns.Push(btnHwnd := ctrl) | |
} | |
WindowProcOld := SetWindowLong(winId, -4, CallbackCreate(WNDPROC)) | |
WNDPROC(hwnd, uMsg, wParam, lParam) | |
{ | |
Critical(-1) | |
DetectHiddenWindows(true) | |
SetWinDelay(-1) | |
SetControlDelay(-1) | |
if !hbrush1 | |
hbrush1 := CreateSolidBrush(0x202020) | |
if !hbrush2 | |
hbrush2 := CreateSolidBrush(0x2b2b2b) | |
switch uMsg { | |
case WM_CTLCOLORSTATIC: | |
{ | |
SelectObject(wParam, hbrush2) | |
SetBkMode(wParam, 0) | |
SetTextColor(wParam, 0xFFFFFF) | |
SetBkColor(wParam, 0x2b2b2b) | |
for _hwnd in btns | |
PostMessage(WM_SETREDRAW,,,_hwnd) | |
GetWindowRect(winId, rcW := RECT()) | |
GetClientRect(winId, rcC := RECT()) | |
GetWindowRect(btnHwnd, rcBtn := RECT()) | |
pt := POINT() | |
pt.y := rcW.bottom - rcBtn.bottom | |
ScreenToClient(winId, pt) | |
hdc := GetWindowDC(winId) | |
rcC.top := rcBtn.top + pt.y -2 | |
rcC.bottom *= 2 | |
rcC.right *= 2 | |
SetBkMode(hdc, 0) | |
FillRect(hdc, rcC, hbrush1) | |
ReleaseDC(winId, hdc) | |
for _hwnd in btns | |
PostMessage(WM_SETREDRAW, 1,,_hwnd) | |
return hbrush2 | |
} | |
case WM_CTLCOLORDLG: | |
{ | |
SelectObject(wParam, hbrush2) | |
SetBkMode(wParam, 0) | |
SetTextColor(wParam, 0xFFFFFF) | |
SetBkColor(wParam, 0x2b2b2b) | |
return hbrush2 | |
} | |
case WM_CTLCOLORBTN: | |
{ | |
SelectObject(wParam, hbrush1) | |
SetBkMode(wParam, 0) | |
SetTextColor(wParam, 0xFFFFFF) | |
SetBkColor(wParam, 0x202020) | |
return hbrush2 | |
} | |
case WM_DESTROY: | |
{ | |
for v in [hbrush1, hbrush2] | |
(v && DeleteObject(v)) | |
for hIcon in hIcons | |
(hIcon??0) && DestroyIcon(hIcon) | |
}} | |
return CallWindowProc(WindowProcOld, hwnd, uMsg, wParam, lParam) | |
} | |
} | |
} | |
CallWindowProc(lpPrevWndFunc, hWnd, uMsg, wParam, lParam) => DllCall("CallWindowProc", "Ptr", lpPrevWndFunc, "Ptr", hwnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam) | |
ClientToScreen(hWnd, lpPoint) => DllCall("User32\ClientToScreen", "ptr", hWnd, "ptr", lpPoint, "int") | |
CreateSolidBrush(crColor) => DllCall('Gdi32\CreateSolidBrush', 'uint', crColor, 'ptr') | |
DestroyIcon(hIcon) => DllCall("DestroyIcon", "ptr", hIcon) | |
/** @see — https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute */ | |
DWMSetWindowAttribute(hwnd, dwAttribute, pvAttribute, cbAttribute := 4) => DllCall("Dwmapi\DwmSetWindowAttribute", "Ptr" , hwnd, "UInt", dwAttribute, "Ptr*", &pvAttribute, "UInt", cbAttribute) | |
DeleteObject(hObject) => DllCall('Gdi32\DeleteObject', 'ptr', hObject, 'int') | |
EnumThreadWindows(dwThreadId, lpfn, lParam) => DllCall("User32\EnumThreadWindows", "uint", dwThreadId, "ptr", lpfn, "uptr", lParam, "int") | |
FillRect(hDC, lprc, hbr) => DllCall("User32\FillRect", "ptr", hDC, "ptr", lprc, "ptr", hbr, "int") | |
GetClientRect(hWnd, lpRect) => DllCall("User32\GetClientRect", "ptr", hWnd, "ptr", lpRect, "int") | |
GetCurrentThreadId() => DllCall("Kernel32\GetCurrentThreadId", "uint") | |
GetWindowDC(hwnd) => DllCall("User32\GetWindowDC", "ptr", hwnd, "ptr") | |
GetWindowRect(hWnd, lpRect) => DllCall("User32\GetWindowRect", "ptr", hWnd, "ptr", lpRect, "uptr") | |
GetWindowRgn(hWnd, hRgn) => DllCall("User32\GetWindowRgn", "ptr", hWnd, "ptr", hRgn, "int") | |
GetWindowRgnBox(hWnd, hRgn) => DllCall("User32\GetWindowRgnBox", "ptr", hWnd, "ptr", hRgn, "int") | |
ReleaseDC(hWnd, hDC) => DllCall("User32\ReleaseDC", "ptr", hWnd, "ptr", hDC, "int") | |
ScreenToClient(hWnd, lpPoint) => DllCall("User32\ScreenToClient", "ptr", hWnd, "ptr", lpPoint, "int") | |
SelectObject(hdc, hgdiobj) => DllCall('Gdi32\SelectObject', 'ptr', hdc, 'ptr', hgdiobj, 'ptr') | |
SetBkColor(hdc, crColor) => DllCall('Gdi32\SetBkColor', 'ptr', hdc, 'uint', crColor, 'uint') | |
SetBkMode(hdc, iBkMode) => DllCall('Gdi32\SetBkMode', 'ptr', hdc, 'int', iBkMode, 'int') | |
SetTextColor(hdc, crColor) => DllCall('Gdi32\SetTextColor', 'ptr', hdc, 'uint', crColor, 'uint') | |
SetThreadDpiAwarenessContext(dpiContext) => DllCall("SetThreadDpiAwarenessContext", "ptr", dpiContext, "ptr") | |
SetWindowTheme(hwnd, pszSubAppName, pszSubIdList := "") => (!DllCall("uxtheme\SetWindowTheme", "ptr", hwnd, "ptr", StrPtr(pszSubAppName), "ptr", pszSubIdList ? StrPtr(pszSubIdList) : 0) ? true : false) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment