#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#define COBJMACROS
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "commctrl.h"
#include "winerror.h"
#include "winreg.h"
#include "comctl32.h"
#include "uxtheme.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static LPWSTR COMCTL32_wSubclass = NULL;
HMODULE COMCTL32_hModule = 0;
static LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
HBRUSH COMCTL32_hPattern55AABrush = NULL;
COMCTL32_SysColor comctl32_color;
static HBITMAP COMCTL32_hPattern55AABitmap = NULL;
static const WORD wPattern55AA[] =
{
0x5555, 0xaaaa, 0x5555, 0xaaaa,
0x5555, 0xaaaa, 0x5555, 0xaaaa
};
static const WCHAR strCC32SubclassInfo[] = L"CC32SubclassInfo";
static void unregister_versioned_classes(void)
{
#define VERSION "6.0.2600.2982!"
static const char *classes[] =
{
VERSION WC_BUTTONA,
VERSION WC_COMBOBOXA,
VERSION "ComboLBox",
VERSION WC_EDITA,
VERSION WC_LISTBOXA,
VERSION WC_STATICA,
};
int i;
for (i = 0; i < ARRAY_SIZE(classes); i++)
UnregisterClassA(classes[i], NULL);
#undef VERSION
}
BOOL WINAPI RegisterClassNameW(const WCHAR *class)
{
static const struct
{
const WCHAR nameW[16];
void (*fn_register)(void);
}
classes[] =
{
{ L"Button", BUTTON_Register },
{ L"ComboBox", COMBO_Register },
{ L"ComboLBox", COMBOLBOX_Register },
{ L"Edit", EDIT_Register },
{ L"ListBox", LISTBOX_Register },
{ L"Static", STATIC_Register },
};
int min = 0, max = ARRAY_SIZE(classes) - 1;
while (min <= max)
{
int res, pos = (min + max) / 2;
if (!(res = wcsicmp(class, classes[pos].nameW)))
{
classes[pos].fn_register();
return TRUE;
}
if (res < 0) max = pos - 1;
else min = pos + 1;
}
return FALSE;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
TRACE("%p, %#lx, %p\n", hinstDLL, fdwReason, lpvReserved);
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL);
COMCTL32_hModule = hinstDLL;
COMCTL32_wSubclass = (LPWSTR)(DWORD_PTR)GlobalAddAtomW (strCC32SubclassInfo);
TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass);
COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA);
COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap);
COMCTL32_RefreshSysColors();
ANIMATE_Register ();
COMBOEX_Register ();
DATETIME_Register ();
FLATSB_Register ();
HEADER_Register ();
HOTKEY_Register ();
IPADDRESS_Register ();
LISTVIEW_Register ();
MONTHCAL_Register ();
NATIVEFONT_Register ();
PAGER_Register ();
PROGRESS_Register ();
REBAR_Register ();
STATUS_Register ();
SYSLINK_Register ();
TAB_Register ();
TOOLBAR_Register ();
TOOLTIPS_Register ();
TRACKBAR_Register ();
TREEVIEW_Register ();
UPDOWN_Register ();
break;
case DLL_PROCESS_DETACH:
if (lpvReserved) break;
ANIMATE_Unregister ();
COMBOEX_Unregister ();
DATETIME_Unregister ();
FLATSB_Unregister ();
HEADER_Unregister ();
HOTKEY_Unregister ();
IPADDRESS_Unregister ();
LISTVIEW_Unregister ();
MONTHCAL_Unregister ();
NATIVEFONT_Unregister ();
PAGER_Unregister ();
PROGRESS_Unregister ();
REBAR_Unregister ();
STATUS_Unregister ();
SYSLINK_Unregister ();
TAB_Unregister ();
TOOLBAR_Unregister ();
TOOLTIPS_Unregister ();
TRACKBAR_Unregister ();
TREEVIEW_Unregister ();
UPDOWN_Unregister ();
unregister_versioned_classes ();
DeleteObject (COMCTL32_hPattern55AABrush);
DeleteObject (COMCTL32_hPattern55AABitmap);
GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
break;
}
return TRUE;
}
VOID WINAPI
MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs)
{
UINT uMenuID = 0;
if (!IsWindow (hwndStatus))
return;
switch (uMsg) {
case WM_MENUSELECT:
TRACE("WM_MENUSELECT wParam %#Ix, lParam %#Ix\n", wParam, lParam);
if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) {
TRACE("menu was closed!\n");
SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0);
}
else {
if (HIWORD(wParam) & MF_POPUP)
uMenuID = *(lpwIDs+1);
else
uMenuID = (UINT)LOWORD(wParam);
TRACE("uMenuID = %u\n", uMenuID);
if (uMenuID) {
WCHAR szText[256];
if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
szText[0] = '\0';
SendMessageW (hwndStatus, SB_SETTEXTW,
255 | SBT_NOBORDERS, (LPARAM)szText);
SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0);
}
}
break;
case WM_COMMAND :
TRACE("WM_COMMAND wParam %#Ix, lParam %#Ix\n", wParam, lParam);
WARN("We don't care about the WM_COMMAND\n");
break;
default:
FIXME("Invalid Message 0x%x!\n", uMsg);
break;
}
}
BOOL WINAPI
ShowHideMenuCtl (HWND hwnd, UINT_PTR uFlags, LPINT lpInfo)
{
LPINT lpMenuId;
TRACE("%p, %Ix, %p\n", hwnd, uFlags, lpInfo);
if (lpInfo == NULL)
return FALSE;
if (!(lpInfo[0]) || !(lpInfo[1]))
return FALSE;
lpMenuId = &lpInfo[2];
while (*lpMenuId != uFlags)
lpMenuId += 2;
if (GetMenuState ((HMENU)(DWORD_PTR)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) {
CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED);
lpMenuId++;
SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
SWP_HIDEWINDOW);
}
else {
CheckMenuItem ((HMENU)(DWORD_PTR)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED);
lpMenuId++;
SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0,
SWP_SHOWWINDOW);
}
return TRUE;
}
VOID WINAPI
GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, const INT *lpInfo)
{
RECT rcCtrl;
const INT *lpRun;
HWND hwndCtrl;
TRACE("(%p %p %p)\n",
hwnd, lpRect, lpInfo);
GetClientRect (hwnd, lpRect);
lpRun = lpInfo;
do {
lpRun += 2;
if (*lpRun == 0)
return;
lpRun++;
hwndCtrl = GetDlgItem (hwnd, *lpRun);
if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) {
TRACE("control id 0x%x\n", *lpRun);
GetWindowRect (hwndCtrl, &rcCtrl);
MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2);
SubtractRect (lpRect, lpRect, &rcCtrl);
}
lpRun++;
} while (*lpRun);
}
void COMCTL32_DrawStatusText(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style, BOOL draw_background)
{
RECT r = *lprc;
UINT border;
COLORREF oldbkcolor;
if (draw_background)
{
if (style & SBT_POPOUT)
border = BDR_RAISEDOUTER;
else if (style & SBT_NOBORDERS)
border = 0;
else
border = BDR_SUNKENOUTER;
oldbkcolor = SetBkColor (hdc, comctl32_color.clrBtnFace);
DrawEdge (hdc, &r, border, BF_MIDDLE|BF_RECT|BF_ADJUST);
SetBkColor (hdc, oldbkcolor);
}
if (text) {
int oldbkmode = SetBkMode (hdc, TRANSPARENT);
COLORREF oldtextcolor;
UINT align = DT_LEFT;
int strCnt = 0;
oldtextcolor = SetTextColor (hdc, comctl32_color.clrBtnText);
if (style & SBT_RTLREADING)
FIXME("Unsupported RTL style!\n");
r.left += 3;
do {
if (*text == '\t') {
if (strCnt) {
DrawTextW (hdc, text - strCnt, strCnt, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
strCnt = 0;
}
if (align==DT_RIGHT) {
break;
}
align = (align==DT_LEFT ? DT_CENTER : DT_RIGHT);
} else {
strCnt++;
}
} while(*text++);
if (strCnt) DrawTextW (hdc, text - strCnt, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX);
SetBkMode (hdc, oldbkmode);
SetTextColor (hdc, oldtextcolor);
}
}
void WINAPI DrawStatusTextW(HDC hdc, LPCRECT lprc, LPCWSTR text, UINT style)
{
COMCTL32_DrawStatusText(hdc, lprc, text, style, TRUE);
}
void WINAPI DrawStatusTextA (HDC hdc, LPCRECT lprc, LPCSTR text, UINT style)
{
INT len;
LPWSTR textW = NULL;
if ( text ) {
if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) {
if ( (textW = Alloc( len * sizeof(WCHAR) )) )
MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len );
}
}
DrawStatusTextW( hdc, lprc, textW, style );
Free( textW );
}
HWND WINAPI
CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid)
{
return CreateWindowA(STATUSCLASSNAMEA, text, style,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parent, (HMENU)(DWORD_PTR)wid, 0, 0);
}
HWND WINAPI
CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid)
{
return CreateWindowW(STATUSCLASSNAMEW, text, style,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parent, (HMENU)(DWORD_PTR)wid, 0, 0);
}
HWND WINAPI
CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
HWND parent, INT id, HINSTANCE inst,
HWND buddy, INT maxVal, INT minVal, INT curVal)
{
HWND hUD =
CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy,
parent, (HMENU)(DWORD_PTR)id, inst, 0);
if (hUD) {
SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0);
SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal));
SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0));
}
return hUD;
}
VOID WINAPI
InitCommonControls (void)
{
}
BOOL WINAPI
InitCommonControlsEx (const INITCOMMONCONTROLSEX *lpInitCtrls)
{
if (!lpInitCtrls || lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX))
return FALSE;
TRACE("%#lx\n", lpInitCtrls->dwICC);
return TRUE;
}
HWND WINAPI
CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
HINSTANCE hBMInst, UINT_PTR wBMID, LPCTBBUTTON lpButtons,
INT iNumButtons, INT dxButton, INT dyButton,
INT dxBitmap, INT dyBitmap, UINT uStructSize)
{
HWND hwndTB;
hwndTB =
CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30,
hwnd, (HMENU)(DWORD_PTR)wID, COMCTL32_hModule, NULL);
if(hwndTB) {
TBADDBITMAP tbab;
SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
if (dxBitmap < 0)
dxBitmap = 16;
if (dyBitmap < 0)
dyBitmap = 16;
if (dxBitmap == 0 || dyBitmap == 0)
dxBitmap = dyBitmap = 16;
SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxBitmap, dyBitmap));
if (dxButton < 0)
dxButton = dxBitmap;
if (dyButton < 0)
dyButton = dyBitmap;
if (dxButton != 0 && dyButton != 0)
SendMessageW(hwndTB, TB_SETBITMAPSIZE, 0, MAKELPARAM(dxButton, dyButton));
if (nBitmaps > 0 || hBMInst == HINST_COMMCTRL)
{
tbab.hInst = hBMInst;
tbab.nID = wBMID;
SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
}
if(iNumButtons > 0)
SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
}
return hwndTB;
}
HBITMAP WINAPI
CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
LPCOLORMAP lpColorMap, INT iNumMaps)
{
HGLOBAL hglb;
HRSRC hRsrc;
const BITMAPINFOHEADER *lpBitmap;
LPBITMAPINFOHEADER lpBitmapInfo;
UINT nSize, nColorTableSize, iColor;
RGBQUAD *pColorTable;
INT i, iMaps, nWidth, nHeight;
HDC hdcScreen;
HBITMAP hbm;
LPCOLORMAP sysColorMap;
COLORREF cRef;
COLORMAP internalColorMap[4] =
{{0x000000, 0}, {0x808080, 0}, {0xC0C0C0, 0}, {0xFFFFFF, 0}};
if (lpColorMap) {
iMaps = iNumMaps;
sysColorMap = lpColorMap;
}
else {
internalColorMap[0].to = GetSysColor (COLOR_BTNTEXT);
internalColorMap[1].to = GetSysColor (COLOR_BTNSHADOW);
internalColorMap[2].to = GetSysColor (COLOR_BTNFACE);
internalColorMap[3].to = GetSysColor (COLOR_BTNHIGHLIGHT);
iMaps = 4;
sysColorMap = internalColorMap;
}
hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP);
if (hRsrc == 0)
return 0;
hglb = LoadResource (hInstance, hRsrc);
if (hglb == 0)
return 0;
lpBitmap = LockResource (hglb);
if (lpBitmap == NULL)
return 0;
if (lpBitmap->biSize >= sizeof(BITMAPINFOHEADER) && lpBitmap->biClrUsed)
nColorTableSize = lpBitmap->biClrUsed;
else if (lpBitmap->biBitCount <= 8)
nColorTableSize = (1 << lpBitmap->biBitCount);
else
nColorTableSize = 0;
nSize = lpBitmap->biSize;
if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
nSize += 3 * sizeof(DWORD);
nSize += nColorTableSize * sizeof(RGBQUAD);
lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
if (lpBitmapInfo == NULL)
return 0;
RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize);
pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo) + lpBitmapInfo->biSize);
for (iColor = 0; iColor < nColorTableSize; iColor++) {
for (i = 0; i < iMaps; i++) {
cRef = RGB(pColorTable[iColor].rgbRed,
pColorTable[iColor].rgbGreen,
pColorTable[iColor].rgbBlue);
if ( cRef == sysColorMap[i].from) {
#if 0
if (wFlags & CBS_MASKED) {
if (sysColorMap[i].to != COLOR_BTNTEXT)
pColorTable[iColor] = RGB(255, 255, 255);
}
else
#endif
pColorTable[iColor].rgbBlue = GetBValue(sysColorMap[i].to);
pColorTable[iColor].rgbGreen = GetGValue(sysColorMap[i].to);
pColorTable[iColor].rgbRed = GetRValue(sysColorMap[i].to);
break;
}
}
}
nWidth = lpBitmapInfo->biWidth;
nHeight = lpBitmapInfo->biHeight;
hdcScreen = GetDC (NULL);
hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight);
if (hbm) {
HDC hdcDst = CreateCompatibleDC (hdcScreen);
HBITMAP hbmOld = SelectObject (hdcDst, hbm);
const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
SRCCOPY);
SelectObject (hdcDst, hbmOld);
DeleteDC (hdcDst);
}
ReleaseDC (NULL, hdcScreen);
GlobalFree (lpBitmapInfo);
FreeResource (hglb);
return hbm;
}
HWND WINAPI
CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
HINSTANCE hBMInst, UINT wBMID,
LPCTBBUTTON lpButtons,INT iNumButtons)
{
return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps,
hBMInst, wBMID, lpButtons,
iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData));
}
HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
{
TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
return S_OK;
}
BOOL WINAPI
_TrackMouseEvent (TRACKMOUSEEVENT *ptme)
{
return TrackMouseEvent (ptme);
}
LANGID WINAPI GetMUILanguage (VOID)
{
return COMCTL32_uiLang;
}
VOID WINAPI InitMUILanguage (LANGID uiLang)
{
COMCTL32_uiLang = uiLang;
}
BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
UINT_PTR uIDSubclass, DWORD_PTR dwRef)
{
LPSUBCLASS_INFO stack;
LPSUBCLASSPROCS proc;
TRACE("%p, %p, %Ix, %Ix\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
if (!hWnd || !pfnSubclass)
return FALSE;
stack = GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack) {
stack = Alloc (sizeof(SUBCLASS_INFO));
if (!stack) {
ERR ("Failed to allocate our Subclassing stack\n");
return FALSE;
}
SetPropW (hWnd, COMCTL32_wSubclass, stack);
stack->is_unicode = IsWindowUnicode (hWnd);
stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC,
(DWORD_PTR)COMCTL32_SubclassProc);
}
else {
proc = stack->SubclassProcs;
while (proc) {
if ((proc->id == uIDSubclass) &&
(proc->subproc == pfnSubclass)) {
proc->ref = dwRef;
return TRUE;
}
proc = proc->next;
}
}
proc = Alloc(sizeof(SUBCLASSPROCS));
if (!proc) {
ERR ("Failed to allocate subclass entry in stack\n");
if (stack->is_unicode)
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
else
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
Free (stack);
RemovePropW( hWnd, COMCTL32_wSubclass );
return FALSE;
}
proc->subproc = pfnSubclass;
proc->ref = dwRef;
proc->id = uIDSubclass;
proc->next = stack->SubclassProcs;
stack->SubclassProcs = proc;
return TRUE;
}
BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
UINT_PTR uID, DWORD_PTR *pdwRef)
{
const SUBCLASS_INFO *stack;
const SUBCLASSPROCS *proc;
TRACE("%p, %p, %Ix, %p\n", hWnd, pfnSubclass, uID, pdwRef);
stack = GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack)
goto done;
proc = stack->SubclassProcs;
while (proc) {
if ((proc->id == uID) &&
(proc->subproc == pfnSubclass)) {
if (pdwRef)
*pdwRef = proc->ref;
return TRUE;
}
proc = proc->next;
}
done:
if (pdwRef)
*pdwRef = 0;
return FALSE;
}
BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID)
{
LPSUBCLASS_INFO stack;
LPSUBCLASSPROCS prevproc = NULL;
LPSUBCLASSPROCS proc;
BOOL ret = FALSE;
TRACE("%p, %p, %Ix.\n", hWnd, pfnSubclass, uID);
stack = GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack)
return FALSE;
proc = stack->SubclassProcs;
while (proc) {
if ((proc->id == uID) &&
(proc->subproc == pfnSubclass)) {
if (!prevproc)
stack->SubclassProcs = proc->next;
else
prevproc->next = proc->next;
if (stack->stackpos == proc)
stack->stackpos = stack->stackpos->next;
Free (proc);
ret = TRUE;
break;
}
prevproc = proc;
proc = proc->next;
}
if (!stack->SubclassProcs && !stack->running) {
TRACE("Last Subclass removed, cleaning up\n");
if ((WNDPROC)GetWindowLongPtrW (hWnd, GWLP_WNDPROC) != COMCTL32_SubclassProc)
WARN("Window procedure has been modified, skipping restore\n");
else if (stack->is_unicode)
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
else
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
Free (stack);
RemovePropW( hWnd, COMCTL32_wSubclass );
}
return ret;
}
static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPSUBCLASS_INFO stack;
LPSUBCLASSPROCS proc;
LRESULT ret;
TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
stack = GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack) {
ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
return 0;
}
proc = stack->stackpos;
stack->stackpos = stack->SubclassProcs;
stack->running++;
ret = DefSubclassProc(hWnd, uMsg, wParam, lParam);
stack->running--;
stack->stackpos = proc;
if (!stack->SubclassProcs && !stack->running) {
TRACE("Last Subclass removed, cleaning up\n");
if (stack->is_unicode)
SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
else
SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc);
Free (stack);
RemovePropW( hWnd, COMCTL32_wSubclass );
}
return ret;
}
LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPSUBCLASS_INFO stack;
LRESULT ret;
TRACE("%p, %#x, %#Ix, %#Ix\n", hWnd, uMsg, wParam, lParam);
stack = GetPropW (hWnd, COMCTL32_wSubclass);
if (!stack) {
ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd);
return 0;
}
if (!stack->stackpos) {
ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam);
} else {
const SUBCLASSPROCS *proc = stack->stackpos;
stack->stackpos = stack->stackpos->next;
ret = proc->subproc (hWnd, uMsg, wParam, lParam,
proc->id, proc->ref);
}
return ret;
}
HWND
COMCTL32_CreateToolTip(HWND hwndOwner)
{
HWND hwndToolTip;
hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner,
0, 0, 0);
if (hwndToolTip)
{
NMTOOLTIPSCREATED nmttc;
HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER);
nmttc.hdr.hwndFrom = hwndTrueOwner;
nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID);
nmttc.hdr.code = NM_TOOLTIPSCREATED;
nmttc.hwndToolTips = hwndToolTip;
SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
}
return hwndToolTip;
}
VOID
COMCTL32_RefreshSysColors(void)
{
comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT);
comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW);
comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT);
comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE);
comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT);
comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
comctl32_color.clrHotTrackingColor = GetSysColor (COLOR_HOTLIGHT);
comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT);
comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW);
comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW);
comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE);
comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW);
comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT);
comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT);
comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION);
comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK);
comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT);
}
void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal)
{
HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark);
HPEN hOldPen;
static const DWORD adwPolyPoints[] = {4,4,4};
LONG lCentre = (bHorizontal ?
lpRect->top + (lpRect->bottom - lpRect->top)/2 :
lpRect->left + (lpRect->right - lpRect->left)/2);
LONG l1 = (bHorizontal ? lpRect->left : lpRect->top);
LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom);
const POINT aptInsertMark[] =
{
{lCentre , l1 + 2},
{lCentre - 2, l1 },
{lCentre + 3, l1 },
{lCentre + 1, l1 + 2},
{lCentre , l2 - 2},
{lCentre , l1 - 1},
{lCentre + 1, l1 - 1},
{lCentre + 1, l2 - 2},
{lCentre , l2 - 3},
{lCentre - 2, l2 - 1},
{lCentre + 3, l2 - 1},
{lCentre + 1, l2 - 3},
};
hOldPen = SelectObject(hDC, hPen);
PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
SelectObject(hDC, hOldPen);
DeleteObject(hPen);
}
void COMCTL32_EnsureBitmapSize(HBITMAP *pBitmap, int cxMinWidth, int cyMinHeight, COLORREF crBackground)
{
int cxNew, cyNew;
BITMAP bmp;
HBITMAP hNewBitmap;
HBITMAP hNewDCBitmap, hOldDCBitmap;
HBRUSH hNewDCBrush;
HDC hdcNew, hdcOld;
if (!GetObjectW(*pBitmap, sizeof(BITMAP), &bmp))
return;
cxNew = (cxMinWidth > bmp.bmWidth ? cxMinWidth : bmp.bmWidth);
cyNew = (cyMinHeight > bmp.bmHeight ? cyMinHeight : bmp.bmHeight);
if (cxNew == bmp.bmWidth && cyNew == bmp.bmHeight)
return;
hdcNew = CreateCompatibleDC(NULL);
hNewBitmap = CreateBitmap(cxNew, cyNew, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
hNewDCBitmap = SelectObject(hdcNew, hNewBitmap);
hNewDCBrush = SelectObject(hdcNew, CreateSolidBrush(crBackground));
hdcOld = CreateCompatibleDC(NULL);
hOldDCBitmap = SelectObject(hdcOld, *pBitmap);
BitBlt(hdcNew, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcOld, 0, 0, SRCCOPY);
if (bmp.bmWidth < cxMinWidth)
PatBlt(hdcNew, bmp.bmWidth, 0, cxNew, bmp.bmHeight, PATCOPY);
if (bmp.bmHeight < cyMinHeight)
PatBlt(hdcNew, 0, bmp.bmHeight, bmp.bmWidth, cyNew, PATCOPY);
if (bmp.bmWidth < cxMinWidth && bmp.bmHeight < cyMinHeight)
PatBlt(hdcNew, bmp.bmWidth, bmp.bmHeight, cxNew, cyNew, PATCOPY);
SelectObject(hdcNew, hNewDCBitmap);
DeleteObject(SelectObject(hdcNew, hNewDCBrush));
DeleteDC(hdcNew);
SelectObject(hdcOld, hOldDCBitmap);
DeleteDC(hdcOld);
DeleteObject(*pBitmap);
*pBitmap = hNewBitmap;
return;
}
void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
{
HDC hdc = GetDC(NULL);
HFONT hOldFont;
hOldFont = SelectObject(hdc, hFont);
GetTextMetricsW(hdc, ptm);
SelectObject(hdc, hOldFont);
ReleaseDC(NULL, hdc);
}
#ifndef OCM__BASE
#define OCM__BASE (WM_USER+0x1c00)
#endif
BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
{
switch (uMsg)
{
case OCM__BASE + WM_COMMAND:
case OCM__BASE + WM_CTLCOLORBTN:
case OCM__BASE + WM_CTLCOLOREDIT:
case OCM__BASE + WM_CTLCOLORDLG:
case OCM__BASE + WM_CTLCOLORLISTBOX:
case OCM__BASE + WM_CTLCOLORMSGBOX:
case OCM__BASE + WM_CTLCOLORSCROLLBAR:
case OCM__BASE + WM_CTLCOLORSTATIC:
case OCM__BASE + WM_DRAWITEM:
case OCM__BASE + WM_MEASUREITEM:
case OCM__BASE + WM_DELETEITEM:
case OCM__BASE + WM_VKEYTOITEM:
case OCM__BASE + WM_CHARTOITEM:
case OCM__BASE + WM_COMPAREITEM:
case OCM__BASE + WM_HSCROLL:
case OCM__BASE + WM_VSCROLL:
case OCM__BASE + WM_PARENTNOTIFY:
case OCM__BASE + WM_NOTIFY:
return TRUE;
default:
return FALSE;
}
}
BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
{
FIXME("(%p, %p): stub\n", phicon1, phicon2);
return FALSE;
}
static inline BOOL IsDelimiter(WCHAR c)
{
switch(c)
{
case '/':
case '\\':
case '.':
case ' ':
return TRUE;
}
return FALSE;
}
static int CALLBACK PathWordBreakProc(LPCWSTR lpch, int ichCurrent, int cch, int code)
{
if (code == WB_ISDELIMITER)
return IsDelimiter(lpch[ichCurrent]);
else
{
int dir = (code == WB_LEFT) ? -1 : 1;
for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir)
if (IsDelimiter(lpch[ichCurrent])) return ichCurrent;
}
return ichCurrent;
}
LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
{
return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0,
(LPARAM)(bSet ? PathWordBreakProc : NULL));
}
int WINAPI DrawShadowText(HDC hdc, LPCWSTR text, UINT length, RECT *rect, DWORD flags,
COLORREF crText, COLORREF crShadow, int offset_x, int offset_y)
{
int bkmode, ret;
COLORREF clr;
RECT r;
FIXME("%p, %s, %d, %p, %#lx, %#lx, %#lx, %d, %d: semi-stub\n", hdc, debugstr_w(text),
length, rect, flags, crText, crShadow, offset_x, offset_y);
bkmode = SetBkMode(hdc, TRANSPARENT);
clr = SetTextColor(hdc, crShadow);
r = *rect;
OffsetRect(&r, 1, 1);
DrawTextW(hdc, text, length, &r, flags);
SetTextColor(hdc, crText);
ret = DrawTextW(hdc, text, length, rect, flags);
SetTextColor(hdc, clr);
SetBkMode(hdc, bkmode);
return ret;
}
HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
{
TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
*icon = NULL;
if (!name)
return E_INVALIDARG;
*icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
(hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
if (!*icon)
return HRESULT_FROM_WIN32(GetLastError());
return S_OK;
}
HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
{
int cx, cy;
TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
if (size == LIM_SMALL)
{
cx = GetSystemMetrics(SM_CXSMICON);
cy = GetSystemMetrics(SM_CYSMICON);
}
else if (size == LIM_LARGE)
{
cx = GetSystemMetrics(SM_CXICON);
cy = GetSystemMetrics(SM_CYICON);
}
else
{
*icon = NULL;
return E_INVALIDARG;
}
return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
}
static const WCHAR strMRUList[] = L"MRUList";
void * WINAPI Alloc(DWORD size)
{
return LocalAlloc(LMEM_ZEROINIT, size);
}
void * WINAPI ReAlloc(void *src, DWORD size)
{
if (src)
return LocalReAlloc(src, size, LMEM_ZEROINIT | LMEM_MOVEABLE);
else
return LocalAlloc(LMEM_ZEROINIT, size);
}
BOOL WINAPI Free(void *mem)
{
return !LocalFree(mem);
}
DWORD WINAPI GetSize(void *mem)
{
return LocalSize(mem);
}
typedef INT (CALLBACK *MRUStringCmpFnA)(LPCSTR lhs, LPCSTR rhs);
typedef INT (CALLBACK *MRUStringCmpFnW)(LPCWSTR lhs, LPCWSTR rhs);
typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length);
struct MRUINFOA
{
DWORD cbSize;
UINT uMax;
UINT fFlags;
HKEY hKey;
LPSTR lpszSubKey;
union
{
MRUStringCmpFnA string_cmpfn;
MRUBinaryCmpFn binary_cmpfn;
} u;
};
struct MRUINFOW
{
DWORD cbSize;
UINT uMax;
UINT fFlags;
HKEY hKey;
LPWSTR lpszSubKey;
union
{
MRUStringCmpFnW string_cmpfn;
MRUBinaryCmpFn binary_cmpfn;
} u;
};
#define MRU_STRING 0
#define MRU_BINARY 1
#define MRU_CACHEWRITE 2
typedef struct tagWINEMRUITEM
{
DWORD size;
DWORD itemFlag;
BYTE datastart;
} WINEMRUITEM, *LPWINEMRUITEM;
#define WMRUIF_CHANGED 0x0001
typedef struct tagWINEMRULIST
{
struct MRUINFOW extview;
BOOL isUnicode;
DWORD wineFlags;
DWORD cursize;
LPWSTR realMRU;
LPWINEMRUITEM *array;
} WINEMRULIST, *LPWINEMRULIST;
#define WMRUF_CHANGED 0x0001
static void MRU_SaveChanged(WINEMRULIST *mp)
{
UINT i, err;
HKEY newkey;
WCHAR realname[2];
WINEMRUITEM *witem;
if ((err = RegOpenKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, KEY_WRITE, &newkey)))
{
ERR("Could not open key, error=%d, attempting to create\n", err);
if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE, 0, &newkey, 0)))
{
ERR("failed to create key /%s/, err=%d\n", debugstr_w(mp->extview.lpszSubKey), err);
return;
}
}
if (mp->wineFlags & WMRUF_CHANGED)
{
mp->wineFlags &= ~WMRUF_CHANGED;
if ((err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (BYTE *)mp->realMRU,
(lstrlenW(mp->realMRU) + 1)*sizeof(WCHAR))))
{
ERR("error saving MRUList, err=%d\n", err);
}
TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU));
}
realname[1] = 0;
for (i = 0; i < mp->cursize; ++i)
{
witem = mp->array[i];
if (witem->itemFlag & WMRUIF_CHANGED)
{
witem->itemFlag &= ~WMRUIF_CHANGED;
realname[0] = 'a' + i;
if ((err = RegSetValueExW(newkey, realname, 0, (mp->extview.fFlags & MRU_BINARY) ?
REG_BINARY : REG_SZ, &witem->datastart, witem->size)))
{
ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err);
}
TRACE("saving value for name /%s/ size %ld\n", debugstr_w(realname), witem->size);
}
}
RegCloseKey(newkey);
}
void WINAPI FreeMRUList(HANDLE hMRUList)
{
WINEMRULIST *mp = hMRUList;
unsigned int i;
TRACE("%p.\n", hMRUList);
if (!hMRUList)
return;
if (mp->wineFlags & WMRUF_CHANGED)
{
MRU_SaveChanged(mp);
}
for (i = 0; i < mp->extview.uMax; ++i)
Free(mp->array[i]);
Free(mp->realMRU);
Free(mp->array);
Free(mp->extview.lpszSubKey);
Free(mp);
}
INT WINAPI FindMRUData(HANDLE hList, const void *data, DWORD cbData, int *pos)
{
const WINEMRULIST *mp = hList;
INT ret;
UINT i;
LPSTR dataA = NULL;
if (!mp || !mp->extview.u.string_cmpfn)
return -1;
if (!(mp->extview.fFlags & MRU_BINARY) && !mp->isUnicode)
{
DWORD len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
dataA = Alloc(len);
WideCharToMultiByte(CP_ACP, 0, data, -1, dataA, len, NULL, NULL);
}
for (i = 0; i < mp->cursize; ++i)
{
if (mp->extview.fFlags & MRU_BINARY)
{
if (!mp->extview.u.binary_cmpfn(data, &mp->array[i]->datastart, cbData))
break;
}
else
{
if (mp->isUnicode)
{
if (!mp->extview.u.string_cmpfn(data, (LPWSTR)&mp->array[i]->datastart))
break;
}
else
{
DWORD len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1,
NULL, 0, NULL, NULL);
LPSTR itemA = Alloc(len);
INT cmp;
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, itemA, len, NULL, NULL);
cmp = mp->extview.u.string_cmpfn((LPWSTR)dataA, (LPWSTR)itemA);
Free(itemA);
if (!cmp)
break;
}
}
}
Free(dataA);
if (i < mp->cursize)
ret = i;
else
ret = -1;
if (pos && (ret != -1))
*pos = 'a' + i;
TRACE("%p, %p, %ld, %p, returning %d.\n", hList, data, cbData, pos, ret);
return ret;
}
INT WINAPI AddMRUData(HANDLE hList, const void *data, DWORD cbData)
{
WINEMRULIST *mp = hList;
WINEMRUITEM *witem;
INT i, replace;
if ((replace = FindMRUData(hList, data, cbData, NULL)) >= 0)
{
LPWSTR pos = wcschr(mp->realMRU, replace + 'a');
while (pos > mp->realMRU)
{
pos[0] = pos[-1];
pos--;
}
}
else
{
if (mp->cursize < mp->extview.uMax)
{
replace = mp->cursize;
mp->cursize++;
}
else
{
replace = mp->realMRU[mp->cursize - 1] - 'a';
Free(mp->array[replace]);
}
mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM));
witem->itemFlag |= WMRUIF_CHANGED;
witem->size = cbData;
memcpy( &witem->datastart, data, cbData);
for (i = mp->cursize - 1; i >= 1; --i)
mp->realMRU[i] = mp->realMRU[i-1];
}
mp->wineFlags |= WMRUF_CHANGED;
mp->realMRU[0] = replace + 'a';
TRACE("%p, %p, %ld adding data, /%c/ now most current\n", hList, data, cbData, replace+'a');
if (!(mp->extview.fFlags & MRU_CACHEWRITE))
{
MRU_SaveChanged(mp);
}
return replace;
}
INT WINAPI AddMRUStringW(HANDLE hList, const WCHAR *str)
{
TRACE("%p, %s.\n", hList, debugstr_w(str));
if (!hList)
return -1;
if (!str || IsBadStringPtrW(str, -1))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
return AddMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR));
}
INT WINAPI AddMRUStringA(HANDLE hList, const char *str)
{
WCHAR *strW;
DWORD len;
INT ret;
TRACE("%p, %s.\n", hList, debugstr_a(str));
if (!hList)
return -1;
if (IsBadStringPtrA(str, -1))
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR);
strW = Alloc(len);
if (!strW)
return -1;
MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len/sizeof(WCHAR));
ret = AddMRUData(hList, strW, len);
Free(strW);
return ret;
}
BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos)
{
FIXME("(%p, %d): stub\n", hList, nItemPos);
return TRUE;
}
INT WINAPI FindMRUStringW(HANDLE hList, const WCHAR *str, int *pos)
{
return FindMRUData(hList, str, (lstrlenW(str) + 1) * sizeof(WCHAR), pos);
}
INT WINAPI FindMRUStringA(HANDLE hList, const char *str, int *pos)
{
DWORD len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
WCHAR *strW = Alloc(len * sizeof(*strW));
INT ret;
MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len);
ret = FindMRUData(hList, strW, len * sizeof(WCHAR), pos);
Free(strW);
return ret;
}
static HANDLE create_mru_list(WINEMRULIST *mp)
{
UINT i, err;
HKEY newkey;
DWORD datasize, dwdisp;
WCHAR realname[2];
WINEMRUITEM *witem;
DWORD type;
mp->realMRU = Alloc((mp->extview.uMax + 2) * sizeof(WCHAR));
mp->array = Alloc(mp->extview.uMax * sizeof(LPVOID));
if ((err = RegCreateKeyExW(mp->extview.hKey, mp->extview.lpszSubKey, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE, 0, &newkey, &dwdisp)))
{
ERR("%lu, %u, %x, %p, %s, %p: Could not open key, error=%d\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, err);
return 0;
}
if (newkey)
{
datasize = (mp->extview.uMax + 1) * sizeof(WCHAR);
if (RegQueryValueExW( newkey, strMRUList, 0, &type, (BYTE *)mp->realMRU, &datasize))
{
datasize = 1;
*mp->realMRU = 0;
}
else
datasize /= sizeof(WCHAR);
TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize);
mp->cursize = datasize - 1;
realname[1] = 0;
for (i = 0; i < mp->cursize; ++i)
{
realname[0] = 'a' + i;
if (RegQueryValueExW(newkey, realname, 0, &type, 0, &datasize))
{
ERR("Key %s not found 1\n", debugstr_w(realname));
}
mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM));
witem->size = datasize;
if (RegQueryValueExW(newkey, realname, 0, &type, &witem->datastart, &datasize))
{
ERR("Key %s not found 2\n", debugstr_w(realname));
}
}
RegCloseKey( newkey );
}
else
mp->cursize = 0;
TRACE("%lu, %u, %x, %p, %s, %p: Current Size = %ld\n", mp->extview.cbSize, mp->extview.uMax, mp->extview.fFlags,
mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), mp->extview.u.string_cmpfn, mp->cursize);
return mp;
}
HANDLE WINAPI CreateMRUListLazyW(const struct MRUINFOW *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
{
WINEMRULIST *mp;
if (!info->hKey || IsBadStringPtrW(info->lpszSubKey, -1))
return NULL;
mp = Alloc(sizeof(*mp));
memcpy(&mp->extview, info, sizeof(*info));
mp->extview.lpszSubKey = Alloc((lstrlenW(info->lpszSubKey) + 1) * sizeof(WCHAR));
lstrcpyW(mp->extview.lpszSubKey, info->lpszSubKey);
mp->isUnicode = TRUE;
return create_mru_list(mp);
}
HANDLE WINAPI CreateMRUListLazyA(const struct MRUINFOA *info, DWORD dwParam2, DWORD dwParam3, DWORD dwParam4)
{
WINEMRULIST *mp;
DWORD len;
if (!info->hKey || IsBadStringPtrA(info->lpszSubKey, -1))
return 0;
mp = Alloc(sizeof(*mp));
memcpy(&mp->extview, info, sizeof(*info));
len = MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, NULL, 0);
mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, info->lpszSubKey, -1, mp->extview.lpszSubKey, len);
mp->isUnicode = FALSE;
return create_mru_list(mp);
}
HANDLE WINAPI CreateMRUListW(const struct MRUINFOW *info)
{
return CreateMRUListLazyW(info, 0, 0, 0);
}
HANDLE WINAPI CreateMRUListA(const struct MRUINFOA *info)
{
return CreateMRUListLazyA(info, 0, 0, 0);
}
INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
{
const WINEMRULIST *mp = hList;
const WINEMRUITEM *witem;
INT desired, datasize;
if (!mp) return -1;
if ((nItemPos < 0) || !buffer) return mp->cursize;
if (nItemPos >= mp->cursize) return -1;
desired = mp->realMRU[nItemPos];
desired -= 'a';
TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
witem = mp->array[desired];
datasize = min(witem->size, nBufferSize);
memcpy(buffer, &witem->datastart, datasize);
TRACE("(%p, %d, %p, %ld): returning len %d\n", hList, nItemPos, buffer, nBufferSize, datasize);
return datasize;
}
INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, void *buffer, DWORD nBufferSize)
{
const WINEMRULIST *mp = hList;
WINEMRUITEM *witem;
INT desired, datasize;
DWORD lenA;
if (!mp) return -1;
if ((nItemPos < 0) || !buffer) return mp->cursize;
if (nItemPos >= mp->cursize) return -1;
desired = mp->realMRU[nItemPos];
desired -= 'a';
TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired);
witem = mp->array[desired];
if (mp->extview.fFlags & MRU_BINARY)
{
datasize = min(witem->size, nBufferSize);
memcpy(buffer, &witem->datastart, datasize);
}
else
{
lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, NULL, 0, NULL, NULL);
datasize = min(lenA, nBufferSize);
WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, buffer, datasize, NULL, NULL);
((char *)buffer)[ datasize - 1 ] = '\0';
datasize = lenA - 1;
}
TRACE("(%p, %d, %p, %ld): returning len=%d\n", hList, nItemPos, buffer, nBufferSize, datasize);
return datasize;
}
INT Str_GetPtrWtoA(const WCHAR *src, char *dst, INT nMaxLen)
{
INT len;
TRACE("%s, %p, %d.\n", debugstr_w(src), dst, nMaxLen);
if (!dst && src)
return WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
if (!nMaxLen)
return 0;
if (!src)
{
dst[0] = 0;
return 0;
}
len = WideCharToMultiByte(CP_ACP, 0, src, -1, 0, 0, NULL, NULL);
if (len >= nMaxLen)
len = nMaxLen - 1;
WideCharToMultiByte(CP_ACP, 0, src, -1, dst, len, NULL, NULL);
dst[len] = '\0';
return len;
}
INT Str_GetPtrAtoW(const char *src, WCHAR *dst, INT nMaxLen)
{
INT len;
TRACE("%s, %p, %d.\n", debugstr_a(src), dst, nMaxLen);
if (!dst && src)
return MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
if (!nMaxLen)
return 0;
if (!src)
{
*dst = 0;
return 0;
}
len = MultiByteToWideChar(CP_ACP, 0, src, -1, 0, 0);
if (len >= nMaxLen)
len = nMaxLen - 1;
MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
dst[len] = 0;
return len;
}
BOOL Str_SetPtrAtoW(WCHAR **dst, const char *src)
{
TRACE("%p, %s.\n", dst, debugstr_a(src));
if (src)
{
INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
LPWSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
if (!ptr)
return FALSE;
MultiByteToWideChar(CP_ACP, 0, src, -1, ptr, len);
*dst = ptr;
}
else
{
Free(*dst);
*dst = NULL;
}
return TRUE;
}
BOOL Str_SetPtrWtoA(char **dst, const WCHAR *src)
{
TRACE("%p, %s.\n", dst, debugstr_w(src));
if (src)
{
INT len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, FALSE);
LPSTR ptr = ReAlloc(*dst, len * sizeof(**dst));
if (!ptr)
return FALSE;
WideCharToMultiByte(CP_ACP, 0, src, -1, ptr, len, NULL, FALSE);
*dst = ptr;
}
else
{
Free(*dst);
*dst = NULL;
}
return TRUE;
}
struct NOTIFYDATA
{
HWND hwndFrom;
HWND hwndTo;
DWORD dwParam3;
DWORD dwParam4;
DWORD dwParam5;
DWORD dwParam6;
};
static LRESULT DoNotify(const struct NOTIFYDATA *notify, UINT code, NMHDR *hdr)
{
NMHDR nmhdr;
NMHDR *lpNmh = NULL;
UINT idFrom = 0;
TRACE("%p, %p, %d, %p, %#lx.\n", notify->hwndFrom, notify->hwndTo, code, hdr, notify->dwParam5);
if (!notify->hwndTo)
return 0;
if (notify->hwndFrom == (HWND)-1)
{
lpNmh = hdr;
idFrom = hdr->idFrom;
}
else
{
if (notify->hwndFrom)
idFrom = GetDlgCtrlID(notify->hwndFrom);
lpNmh = hdr ? hdr : &nmhdr;
lpNmh->hwndFrom = notify->hwndFrom;
lpNmh->idFrom = idFrom;
lpNmh->code = code;
}
return SendMessageW(notify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
}
LRESULT WINAPI SendNotify(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr)
{
struct NOTIFYDATA notify;
TRACE("%p, %p, %d, %p.\n", hwndTo, hwndFrom, code, hdr);
notify.hwndFrom = hwndFrom;
notify.hwndTo = hwndTo;
notify.dwParam5 = 0;
notify.dwParam6 = 0;
return DoNotify(¬ify, code, hdr);
}
LRESULT WINAPI SendNotifyEx(HWND hwndTo, HWND hwndFrom, UINT code, NMHDR *hdr, DWORD dwParam5)
{
struct NOTIFYDATA notify;
HWND hwndNotify;
TRACE("%p, %p, %d, %p, %#lx\n", hwndFrom, hwndTo, code, hdr, dwParam5);
hwndNotify = hwndTo;
if (!hwndTo)
{
if (IsWindow(hwndFrom))
{
hwndNotify = GetParent(hwndFrom);
if (!hwndNotify)
return 0;
}
}
notify.hwndFrom = hwndFrom;
notify.hwndTo = hwndNotify;
notify.dwParam5 = dwParam5;
notify.dwParam6 = 0;
return DoNotify(¬ify, code, hdr);
}
static BOOL COMCTL32_array_reserve(void **array, DWORD *size, DWORD count, DWORD item_size)
{
void *new_array;
DWORD needed_size;
if (count > (DWORD)-1 / item_size)
return FALSE;
needed_size = count * item_size;
if (*size >= needed_size)
return TRUE;
new_array = *array ? ReAlloc(*array, needed_size) : Alloc(needed_size);
if (!new_array)
return FALSE;
*array = new_array;
*size = needed_size;
return TRUE;
}
enum conversion_flags
{
CONVERT_SEND = 0x01,
CONVERT_RECEIVE = 0x02,
SEND_EMPTY_IF_NULL = 0x04,
SET_NULL_IF_NO_MASK = 0x08,
ZERO_SEND = 0x10
};
static UINT COMCTL32_GetAnsiNtfCode(UINT code)
{
switch (code)
{
case CBEN_DRAGBEGINW: return CBEN_DRAGBEGINA;
case CBEN_ENDEDITW: return CBEN_ENDEDITA;
case CBEN_GETDISPINFOW: return CBEN_GETDISPINFOA;
case DTN_FORMATW: return DTN_FORMATA;
case DTN_FORMATQUERYW: return DTN_FORMATQUERYA;
case DTN_USERSTRINGW: return DTN_USERSTRINGA;
case DTN_WMKEYDOWNW: return DTN_WMKEYDOWNA;
case HDN_BEGINTRACKW: return HDN_BEGINTRACKA;
case HDN_DIVIDERDBLCLICKW: return HDN_DIVIDERDBLCLICKA;
case HDN_ENDTRACKW: return HDN_ENDTRACKA;
case HDN_GETDISPINFOW: return HDN_GETDISPINFOA;
case HDN_ITEMCHANGEDW: return HDN_ITEMCHANGEDA;
case HDN_ITEMCHANGINGW: return HDN_ITEMCHANGINGA;
case HDN_ITEMCLICKW: return HDN_ITEMCLICKA;
case HDN_ITEMDBLCLICKW: return HDN_ITEMDBLCLICKA;
case HDN_TRACKW: return HDN_TRACKA;
case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA;
case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA;
case LVN_GETDISPINFOW: return LVN_GETDISPINFOA;
case LVN_GETINFOTIPW: return LVN_GETINFOTIPA;
case LVN_INCREMENTALSEARCHW: return LVN_INCREMENTALSEARCHA;
case LVN_ODFINDITEMW: return LVN_ODFINDITEMA;
case LVN_SETDISPINFOW: return LVN_SETDISPINFOA;
case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA;
case TBN_GETINFOTIPW: return TBN_GETINFOTIPA;
case TTN_GETDISPINFOW: return TTN_GETDISPINFOA;
case TVN_BEGINDRAGW: return TVN_BEGINDRAGA;
case TVN_BEGINLABELEDITW: return TVN_BEGINLABELEDITA;
case TVN_BEGINRDRAGW: return TVN_BEGINRDRAGA;
case TVN_DELETEITEMW: return TVN_DELETEITEMA;
case TVN_ENDLABELEDITW: return TVN_ENDLABELEDITA;
case TVN_GETDISPINFOW: return TVN_GETDISPINFOA;
case TVN_GETINFOTIPW: return TVN_GETINFOTIPA;
case TVN_ITEMEXPANDEDW: return TVN_ITEMEXPANDEDA;
case TVN_ITEMEXPANDINGW: return TVN_ITEMEXPANDINGA;
case TVN_SELCHANGEDW: return TVN_SELCHANGEDA;
case TVN_SELCHANGINGW: return TVN_SELCHANGINGA;
case TVN_SETDISPINFOW: return TVN_SETDISPINFOA;
}
return code;
}
static WCHAR *COMCTL32_ConvertText(WCHAR **text)
{
WCHAR *oldText = *text;
*text = NULL;
Str_SetPtrWtoA((CHAR **)text, oldText);
return oldText;
}
static void COMCTL32_RestoreText(WCHAR **text, WCHAR *oldText)
{
if (!oldText) return;
Free(*text);
*text = oldText;
}
static LRESULT COMCTL32_SendConvertedNotify(HWND hwndNotify, NMHDR *hdr, UINT *mask, UINT requiredMask, WCHAR **text,
INT *textMax, DWORD flags)
{
CHAR *sendBuffer = NULL;
CHAR *receiveBuffer;
INT bufferSize;
WCHAR *oldText;
INT oldTextMax;
LRESULT ret = NO_ERROR;
oldText = *text;
oldTextMax = textMax ? *textMax : 0;
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
if (mask && !(*mask & requiredMask))
{
ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
if (flags & SET_NULL_IF_NO_MASK) oldText = NULL;
goto done;
}
if (oldTextMax < 0) goto done;
if ((*text && flags & (CONVERT_SEND | ZERO_SEND)) || (!*text && flags & SEND_EMPTY_IF_NULL))
{
bufferSize = textMax ? *textMax : lstrlenW(*text) + 1;
sendBuffer = Alloc(bufferSize);
if (!sendBuffer) goto done;
if (!(flags & ZERO_SEND)) WideCharToMultiByte(CP_ACP, 0, *text, -1, sendBuffer, bufferSize, NULL, FALSE);
*text = (WCHAR *)sendBuffer;
}
ret = SendMessageW(hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
if (*text && oldText && (flags & CONVERT_RECEIVE))
{
if (*text == oldText)
{
bufferSize = lstrlenA((CHAR *)*text) + 1;
receiveBuffer = Alloc(bufferSize);
if (!receiveBuffer) goto done;
memcpy(receiveBuffer, *text, bufferSize);
MultiByteToWideChar(CP_ACP, 0, receiveBuffer, bufferSize, oldText, oldTextMax);
Free(receiveBuffer);
}
else
MultiByteToWideChar(CP_ACP, 0, (CHAR *)*text, -1, oldText, oldTextMax);
}
done:
Free(sendBuffer);
*text = oldText;
return ret;
}
LRESULT COMCTL32_forward_notify_to_ansi_window(HWND hwnd_notify, NMHDR *hdr, WCHAR **unicode_buffer, DWORD *unicode_buffer_size)
{
LRESULT ret;
switch (hdr->code)
{
case CBEN_GETDISPINFOW:
{
NMCOMBOBOXEXW *nmcbe = (NMCOMBOBOXEXW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmcbe->ceItem.mask, CBEIF_TEXT, &nmcbe->ceItem.pszText,
&nmcbe->ceItem.cchTextMax, ZERO_SEND | SET_NULL_IF_NO_MASK | CONVERT_RECEIVE);
}
case CBEN_DRAGBEGINW:
{
NMCBEDRAGBEGINW *nmdbW = (NMCBEDRAGBEGINW *)hdr;
NMCBEDRAGBEGINA nmdbA = {{0}};
nmdbA.hdr.code = COMCTL32_GetAnsiNtfCode(nmdbW->hdr.code);
nmdbA.hdr.hwndFrom = nmdbW->hdr.hwndFrom;
nmdbA.hdr.idFrom = nmdbW->hdr.idFrom;
nmdbA.iItemid = nmdbW->iItemid;
WideCharToMultiByte(CP_ACP, 0, nmdbW->szText, ARRAY_SIZE(nmdbW->szText), nmdbA.szText, ARRAY_SIZE(nmdbA.szText),
NULL, FALSE);
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmdbA);
}
case CBEN_ENDEDITW:
{
NMCBEENDEDITW *nmedW = (NMCBEENDEDITW *)hdr;
NMCBEENDEDITA nmedA = {{0}};
nmedA.hdr.code = COMCTL32_GetAnsiNtfCode(nmedW->hdr.code);
nmedA.hdr.hwndFrom = nmedW->hdr.hwndFrom;
nmedA.hdr.idFrom = nmedW->hdr.idFrom;
nmedA.fChanged = nmedW->fChanged;
nmedA.iNewSelection = nmedW->iNewSelection;
nmedA.iWhy = nmedW->iWhy;
WideCharToMultiByte(CP_ACP, 0, nmedW->szText, ARRAY_SIZE(nmedW->szText), nmedA.szText, ARRAY_SIZE(nmedA.szText),
NULL, FALSE);
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmedA);
}
case DTN_FORMATW:
{
NMDATETIMEFORMATW *nmdtf = (NMDATETIMEFORMATW *)hdr;
WCHAR *oldFormat;
DWORD textLength;
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
oldFormat = COMCTL32_ConvertText((WCHAR **)&nmdtf->pszFormat);
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)nmdtf);
COMCTL32_RestoreText((WCHAR **)&nmdtf->pszFormat, oldFormat);
if (nmdtf->pszDisplay)
{
textLength = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, 0, 0);
if (!COMCTL32_array_reserve((void **)unicode_buffer, unicode_buffer_size, textLength, sizeof(WCHAR))) return ret;
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmdtf->pszDisplay, -1, *unicode_buffer, textLength);
if (nmdtf->pszDisplay != nmdtf->szDisplay)
nmdtf->pszDisplay = *unicode_buffer;
else
{
textLength = min(textLength, ARRAY_SIZE(nmdtf->szDisplay));
memcpy(nmdtf->szDisplay, *unicode_buffer, textLength * sizeof(WCHAR));
}
}
return ret;
}
case DTN_FORMATQUERYW:
{
NMDATETIMEFORMATQUERYW *nmdtfq = (NMDATETIMEFORMATQUERYW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, (WCHAR **)&nmdtfq->pszFormat, NULL, CONVERT_SEND);
}
case DTN_WMKEYDOWNW:
{
NMDATETIMEWMKEYDOWNW *nmdtkd = (NMDATETIMEWMKEYDOWNW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, (WCHAR **)&nmdtkd->pszFormat, NULL, CONVERT_SEND);
}
case DTN_USERSTRINGW:
{
NMDATETIMESTRINGW *nmdts = (NMDATETIMESTRINGW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, (WCHAR **)&nmdts->pszUserString, NULL, CONVERT_SEND);
}
case HDN_BEGINTRACKW:
case HDN_DIVIDERDBLCLICKW:
case HDN_ENDTRACKW:
case HDN_ITEMCHANGEDW:
case HDN_ITEMCHANGINGW:
case HDN_ITEMCLICKW:
case HDN_ITEMDBLCLICKW:
case HDN_TRACKW:
{
NMHEADERW *nmh = (NMHEADERW *)hdr;
WCHAR *oldText = NULL, *oldFilterText = NULL;
HD_TEXTFILTERW *tf = NULL;
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
if (!nmh->pitem) return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
if (nmh->pitem->mask & HDI_TEXT) oldText = COMCTL32_ConvertText(&nmh->pitem->pszText);
if ((nmh->pitem->mask & HDI_FILTER) && (nmh->pitem->type == HDFT_ISSTRING) && nmh->pitem->pvFilter)
{
tf = (HD_TEXTFILTERW *)nmh->pitem->pvFilter;
oldFilterText = COMCTL32_ConvertText(&tf->pszText);
}
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
COMCTL32_RestoreText(&nmh->pitem->pszText, oldText);
if (tf) COMCTL32_RestoreText(&tf->pszText, oldFilterText);
return ret;
}
case HDN_GETDISPINFOW:
{
NMHDDISPINFOW *nmhddi = (NMHDDISPINFOW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmhddi->mask, HDI_TEXT, &nmhddi->pszText, &nmhddi->cchTextMax,
SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE);
}
case LVN_BEGINLABELEDITW:
case LVN_ENDLABELEDITW:
case LVN_SETDISPINFOW:
{
NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText,
&nmlvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
}
case LVN_GETDISPINFOW:
{
NMLVDISPINFOW *nmlvdi = (NMLVDISPINFOW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmlvdi->item.mask, LVIF_TEXT, &nmlvdi->item.pszText,
&nmlvdi->item.cchTextMax, CONVERT_RECEIVE);
}
case LVN_GETINFOTIPW:
{
NMLVGETINFOTIPW *nmlvgit = (NMLVGETINFOTIPW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmlvgit->pszText, &nmlvgit->cchTextMax,
CONVERT_SEND | CONVERT_RECEIVE);
}
case LVN_INCREMENTALSEARCHW:
case LVN_ODFINDITEMW:
{
NMLVFINDITEMW *nmlvfi = (NMLVFINDITEMW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmlvfi->lvfi.flags, LVFI_STRING | LVFI_SUBSTRING,
(WCHAR **)&nmlvfi->lvfi.psz, NULL, CONVERT_SEND);
}
case TBN_GETBUTTONINFOW:
{
NMTOOLBARW *nmtb = (NMTOOLBARW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmtb->pszText, &nmtb->cchText,
SEND_EMPTY_IF_NULL | CONVERT_SEND | CONVERT_RECEIVE);
}
case TBN_GETINFOTIPW:
{
NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmtbgit->pszText, &nmtbgit->cchTextMax, CONVERT_RECEIVE);
}
case TTN_GETDISPINFOW:
{
NMTTDISPINFOW *nmttdiW = (NMTTDISPINFOW *)hdr;
NMTTDISPINFOA nmttdiA = {{0}};
DWORD size;
nmttdiA.hdr.code = COMCTL32_GetAnsiNtfCode(nmttdiW->hdr.code);
nmttdiA.hdr.hwndFrom = nmttdiW->hdr.hwndFrom;
nmttdiA.hdr.idFrom = nmttdiW->hdr.idFrom;
nmttdiA.hinst = nmttdiW->hinst;
nmttdiA.uFlags = nmttdiW->uFlags;
nmttdiA.lParam = nmttdiW->lParam;
nmttdiA.lpszText = nmttdiA.szText;
WideCharToMultiByte(CP_ACP, 0, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText), nmttdiA.szText,
ARRAY_SIZE(nmttdiA.szText), NULL, FALSE);
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmttdiA);
nmttdiW->hinst = nmttdiA.hinst;
nmttdiW->uFlags = nmttdiA.uFlags;
nmttdiW->lParam = nmttdiA.lParam;
MultiByteToWideChar(CP_ACP, 0, nmttdiA.szText, ARRAY_SIZE(nmttdiA.szText), nmttdiW->szText,
ARRAY_SIZE(nmttdiW->szText));
if (!nmttdiA.lpszText)
nmttdiW->lpszText = nmttdiW->szText;
else if (!IS_INTRESOURCE(nmttdiA.lpszText))
{
size = MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, 0, 0);
if (size > ARRAY_SIZE(nmttdiW->szText))
{
if (!COMCTL32_array_reserve((void **)unicode_buffer, unicode_buffer_size, size, sizeof(WCHAR))) return ret;
MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, *unicode_buffer, size);
nmttdiW->lpszText = *unicode_buffer;
memcpy(nmttdiW->szText, nmttdiW->lpszText, min(sizeof(nmttdiW->szText), size * sizeof(WCHAR)));
}
else
{
MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText));
nmttdiW->lpszText = nmttdiW->szText;
}
}
else
{
nmttdiW->szText[0] = 0;
nmttdiW->lpszText = (WCHAR *)nmttdiA.lpszText;
}
return ret;
}
case TVN_BEGINDRAGW:
case TVN_BEGINRDRAGW:
case TVN_ITEMEXPANDEDW:
case TVN_ITEMEXPANDINGW:
{
NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtv->itemNew.mask, TVIF_TEXT, &nmtv->itemNew.pszText, NULL,
CONVERT_SEND);
}
case TVN_DELETEITEMW:
{
NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtv->itemOld.mask, TVIF_TEXT, &nmtv->itemOld.pszText, NULL,
CONVERT_SEND);
}
case TVN_BEGINLABELEDITW:
case TVN_ENDLABELEDITW:
{
NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText,
&nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
}
case TVN_SELCHANGINGW:
case TVN_SELCHANGEDW:
{
NMTREEVIEWW *nmtv = (NMTREEVIEWW *)hdr;
WCHAR *oldItemOldText = NULL;
WCHAR *oldItemNewText = NULL;
hdr->code = COMCTL32_GetAnsiNtfCode(hdr->code);
if (!((nmtv->itemNew.mask | nmtv->itemOld.mask) & TVIF_TEXT))
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
if (nmtv->itemOld.mask & TVIF_TEXT) oldItemOldText = COMCTL32_ConvertText(&nmtv->itemOld.pszText);
if (nmtv->itemNew.mask & TVIF_TEXT) oldItemNewText = COMCTL32_ConvertText(&nmtv->itemNew.pszText);
ret = SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
COMCTL32_RestoreText(&nmtv->itemOld.pszText, oldItemOldText);
COMCTL32_RestoreText(&nmtv->itemNew.pszText, oldItemNewText);
return ret;
}
case TVN_GETDISPINFOW:
{
NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText,
&nmtvdi->item.cchTextMax, ZERO_SEND | CONVERT_RECEIVE);
}
case TVN_SETDISPINFOW:
{
NMTVDISPINFOW *nmtvdi = (NMTVDISPINFOW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, &nmtvdi->item.mask, TVIF_TEXT, &nmtvdi->item.pszText,
&nmtvdi->item.cchTextMax, SET_NULL_IF_NO_MASK | CONVERT_SEND | CONVERT_RECEIVE);
}
case TVN_GETINFOTIPW:
{
NMTVGETINFOTIPW *nmtvgit = (NMTVGETINFOTIPW *)hdr;
return COMCTL32_SendConvertedNotify(hwnd_notify, hdr, NULL, 0, &nmtvgit->pszText, &nmtvgit->cchTextMax, CONVERT_RECEIVE);
}
}
return SendMessageW(hwnd_notify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
}