The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

/*
###########################################################################
# helper routines
#
# $Id: GUI_Helpers.cpp,v 1.28 2011/07/16 14:51:03 acalpini Exp $
#
###########################################################################
*/
#include "GUI.h"
/*
* Create callback control table
* Warning : Use some order than WIN32__GUI__* constant value
*/
#define CREATE_CONTROL_TABLE(n,T) \
T = { \
Window##n, \
DialogBox##n, \
Label##n, \
Button##n, \
Textfield##n, \
Listbox##n, \
Combobox##n, \
Checkbox##n, \
RadioButton##n, \
Groupbox##n, \
Toolbar##n, \
ProgressBar##n, \
StatusBar##n, \
TabStrip##n, \
RichEdit##n, \
ListView##n, \
TreeView##n, \
Trackbar##n, \
UpDown##n, \
Tooltip##n, \
Animation##n, \
Rebar##n, \
Header##n, \
ComboboxEx##n, \
DateTime##n, \
Graphic##n, \
Splitter##n, \
MDIFrame##n, \
MDIClient##n, \
MDIChild##n, \
MonthCal##n \
};
/*
* Create callback table (Probably nicer to turn into plugin API)
*/
CREATE_CONTROL_TABLE(_onPreCreate, void (*OnPreCreate[])(NOTXSPROC LPPERLWIN32GUI_CREATESTRUCT));
CREATE_CONTROL_TABLE(_onParseOption, BOOL (*OnParseOption[])(NOTXSPROC char *, SV*,LPPERLWIN32GUI_CREATESTRUCT));
CREATE_CONTROL_TABLE(_onPostCreate, void (*OnPostCreate[])(NOTXSPROC HWND, LPPERLWIN32GUI_CREATESTRUCT));
CREATE_CONTROL_TABLE(_onParseEvent, BOOL (*OnParseEvent[])(NOTXSPROC char*, int*));
CREATE_CONTROL_TABLE(_onEvent, int (*OnEvent[])(NOTXSPROC LPPERLWIN32GUI_USERDATA, UINT, WPARAM , LPARAM));
/*
* Free perlud structure
*/
void Perlud_Free(NOTXSPROC LPPERLWIN32GUI_USERDATA perlud) {
// Check perlpud
if (perlud != NULL) {
HWND hwnd_self = SvOK(perlud->svSelf) ? handle_From(NOTXSCALL perlud->svSelf) : NULL;
// Free event hash
if (perlud->hvEvents != NULL) {
// Test ref-count - warn if not one
if(SvREFCNT(perlud->hvEvents) != 1)
W32G_WARN("hvEvents ref count not 1 during destruction - please report this");
SvREFCNT_dec(perlud->hvEvents);
perlud->hvEvents = NULL;
}
// Free hook hash
if (perlud->avHooks != NULL) {
// Test ref-count - warn if not one
if(SvREFCNT(perlud->avHooks) != 1)
W32G_WARN("avHooks ref count not 1 during destruction - please report this");
SvREFCNT_dec(perlud->avHooks);
perlud->avHooks = NULL;
}
// Free self
if (perlud->svSelf != NULL && SvREFCNT(perlud->svSelf) > 0) {
/* Free into parent */
if(SvOK(perlud->svSelf)) {
HWND parent = GetParent(hwnd_self);
if (parent != NULL && *perlud->szWindowName != '\0') {
SV* SvParent = SV_SELF_FROM_WINDOW(parent);
if (SvParent != NULL && SvROK(SvParent)) {
/* During global destruction it is possible that the
* underlying object supporting our tied hash is
* destroyed before the object itself, this results in
* fatal errors "(during cleanup) Can't call method
* "DELETE" on an undefined value" - so we check that
* the tied magic is still there before we try to
* delete from the parent
*/
MAGIC* mg;
if ( (mg = mg_find(SvRV(SvParent), PERL_MAGIC_tied)) && SvROK(mg->mg_obj) ) {
hv_delete((HV*) SvRV(SvParent), perlud->szWindowName,
strlen(perlud->szWindowName), G_DISCARD);
}
}
}
}
SvREFCNT_dec(perlud->svSelf);
perlud->svSelf = NULL;
}
// If we stored a hash in userData, drop it's
// ref count to free it (and it's members)
if (perlud->userData != NULL) {
// Test ref-count - warn if not one
if(SvREFCNT(perlud->userData) != 1)
W32G_WARN("userData ref count not 1 during destruction - please report this");
SvREFCNT_dec(perlud->userData);
perlud->userData = NULL;
}
// If we stored a brush, destroy it
if (perlud->bDeleteBackgroundBrush && perlud->hBackgroundBrush != NULL) {
DeleteObject((HGDIOBJ) perlud->hBackgroundBrush);
}
// If we stored an original wndproc, then restore it so that
// WM_NCDESTORY messages get there.
if (hwnd_self && perlud->WndProc) {
SetWindowLongPtr(hwnd_self, GWLP_WNDPROC, (LONG_PTR)(perlud->WndProc));
}
// Free perlpud
safefree (perlud);
}
}
SV *
SV_SELF_FROM_WINDOW(HWND hwnd) {
LPPERLWIN32GUI_USERDATA perlud;
perlud = (LPPERLWIN32GUI_USERDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if( ValidUserData(perlud) ) {
return perlud->svSelf;
} else {
return NULL;
}
}
static void
hv_magic_check (NOTXSPROC HV *hv, bool *needs_copy, bool *needs_store)
{
MAGIC *mg = SvMAGIC(hv);
*needs_copy = FALSE;
*needs_store = TRUE;
while (mg) {
if (isUPPER(mg->mg_type)) {
*needs_copy = TRUE;
switch (mg->mg_type) {
case 'P':
case 'S':
*needs_store = FALSE;
}
}
#ifdef PERLWIN32GUI_STRONGDEBUG
printf("!XS(hv_magic_check) magic='%c' needs_store='%d'\n", mg->mg_type, *needs_store);
#endif
mg = mg->mg_moremagic;
}
}
SV**
hv_fetch_mg(NOTXSPROC HV *hv, char *key, U32 klen, I32 lval) {
SV** tempsv;
tempsv = hv_fetch(hv, key, klen, lval);
if(SvMAGICAL(hv)) mg_get(*tempsv);
return tempsv;
}
SV**
hv_store_mg(NOTXSPROC HV *hv, char *key, U32 klen, SV* val, U32 hash) {
SV** tempsv;
tempsv = hv_store(hv, key, klen, val, hash);
if(SvMAGICAL(hv)) mg_set(val);
return tempsv;
}
/*
##########################################################################
# (@)INTERNAL:handle_From(SV*)
# gets the handle from either the blessed object
# or the SV passed
*/
HWND handle_From(NOTXSPROC SV *pSv) {
HWND hReturn = 0;
//printf("handle_From %p \n",pSv);
if(NULL != pSv) {
if( SvROK(pSv)) {
SV **pHv;
//sv_dump(SvRV(pSv));
pHv = hv_fetch_mg(NOTXSCALL (HV*) SvRV(pSv), "-handle", 7, 0);
if(pHv != NULL) {
hReturn = INT2PTR(HWND,SvIV(*pHv));
//printf("hReturn(1) is %i \n",hReturn);
}
} else {
hReturn = INT2PTR(HWND,SvIV(pSv));
//printf("hReturn(2) is %i \n",hReturn);
}
}
return(hReturn);
}
/*
##########################################################################
# (@)INTERNAL:classname_From(SV*)
# gets the window class name from either the blessed object
# or the SV passed
*/
char *classname_From(NOTXSPROC SV *pSv) {
char *pszName = NULL;
if(NULL != pSv) {
if(SvROK(pSv)) {
SV **pHv;
pHv = hv_fetch_mg(NOTXSCALL (HV*) SvRV(pSv), "-name", 5, 0);
if(pHv != NULL) {
pszName = SvPV_nolen(*pHv);
}
} else {
pszName = SvPV_nolen(pSv);
}
}
return(pszName);
}
/*
##########################################################################
# (@)INTERNAL:GetDefClassProc( *name)
*/
WNDPROC GetDefClassProc (NOTXSPROC const char *Name) {
HV* hash;
SV** wndproc;
hash = perl_get_hv("Win32::GUI::DefClassProc", FALSE);
wndproc = hv_fetch_mg(NOTXSCALL hash, (char*) Name, strlen(Name), FALSE);
if(wndproc == NULL) return NULL;
return INT2PTR(WNDPROC,SvIV(*wndproc));
}
/*
##########################################################################
# (@)INTERNAL:SetDefClassProc( *name, defproc )
*/
BOOL SetDefClassProc (NOTXSPROC const char *Name, WNDPROC DefClassProc) {
HV* hash = perl_get_hv("Win32::GUI::DefClassProc", FALSE);
return (hv_store_mg(NOTXSCALL hash, (char*) Name, strlen(Name), newSViv(PTR2IV(DefClassProc)), 0) != NULL);
}
/*
##########################################################################
# (@)INTERNAL:SvCOLORREF(SV*)
# returns a COLORREF from either a numerical value
# or a color expressed as [RR, GG, BB]
# or a color expressed in HTML notation (#RRGGBB)
*/
COLORREF SvCOLORREF(NOTXSPROC SV* c) {
SV** t;
int r;
int g;
int b;
char html_color[8];
char html_color_component[3];
ZeroMemory(html_color, 8);
ZeroMemory(html_color_component, 3);
r = 0;
g = 0;
b = 0;
if(SvROK(c) && SvTYPE(SvRV(c)) == SVt_PVAV) {
t = av_fetch((AV*)SvRV(c), 0, 0);
if(t != NULL) {
r = SvIV(*t);
}
t = av_fetch((AV*)SvRV(c), 1, 0);
if(t!= NULL) {
g = SvIV(*t);
}
t = av_fetch((AV*)SvRV(c), 2, 0);
if(t != NULL) {
b = SvIV(*t);
}
return RGB((BYTE) r, (BYTE) g, (BYTE) b);
} else {
if(SvPOK(c)) {
strncpy(html_color, SvPV_nolen(c), 7);
if(strncmp(html_color, "#", 1) == 0) {
strncpy(html_color_component, html_color+1, 2);
*(html_color_component+2) = 0;
sscanf(html_color_component, "%x", &r);
strncpy(html_color_component, html_color+3, 2);
*(html_color_component+2) = 0;
sscanf(html_color_component, "%x", &g);
strncpy(html_color_component, html_color+5, 2);
*(html_color_component+2) = 0;
sscanf(html_color_component, "%x", &b);
return RGB((BYTE) r, (BYTE) g, (BYTE) b);
} else {
return (COLORREF) SvIV(c);
}
} else {
return (COLORREF) SvIV(c);
}
}
}
/*
##########################################################################
# (@)INTERNAL:CreateTooltip(parent)
*/
HWND CreateTooltip(
NOTXSPROC
HV* parent
) {
HWND hTooltip;
HWND hParent;
SV** t;
t = hv_fetch_mg(NOTXSCALL parent, "-handle", 7, 0);
if(t != NULL) {
hParent = INT2PTR(HWND,SvIV(*t));
} else {
return NULL;
}
hTooltip = CreateWindowEx(
0, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hParent, NULL, NULL,
NULL
);
if(hTooltip != NULL) {
SetWindowPos(
hTooltip, HWND_TOPMOST,0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE
);
hv_store_mg(NOTXSCALL parent, "-tooltip", 8, newSViv(PTR2IV(hTooltip)), 0);
}
return hTooltip;
}
/*
##########################################################################
# (@)INTERNAL:CalcControlSize(*perlcs, add_x, add_y)
# Used by some control to automatically set width and height at creation
# time.
*/
void CalcControlSize(
NOTXSPROC
LPPERLWIN32GUI_CREATESTRUCT perlcs,
int add_x,
int add_y) {
SIZE mySize;
HDC hdc;
SV** font;
HFONT hfont, oldhfont;
if(perlcs->cs.lpszName != NULL) {
if(perlcs->cs.cx == 0 || perlcs->cs.cy == 0) {
hdc = GetDC(perlcs->cs.hwndParent);
if(perlcs->hFont != NULL) {
hfont = perlcs->hFont;
} else {
hfont = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
if(perlcs->hvParent != NULL) {
font = hv_fetch_mg(NOTXSCALL perlcs->hvParent, "-font", 5, FALSE);
if(font != NULL && SvOK(*font)) {
hfont = (HFONT) handle_From(NOTXSCALL *font);
}
}
}
oldhfont = (HFONT)SelectObject(hdc, hfont);
if(GetTextExtentPoint32(
hdc, perlcs->cs.lpszName, strlen(perlcs->cs.lpszName), &mySize
)) {
if(perlcs->cs.cx == 0) perlcs->cs.cx = mySize.cx + add_x;
if(perlcs->cs.cy == 0) perlcs->cs.cy = mySize.cy + add_y;
}
SelectObject(hdc, oldhfont);
ReleaseDC(perlcs->cs.hwndParent, hdc);
}
}
}
/*
##########################################################################
# (@)INTERNAL:GetObjectName(hwnd, *name)
# Gets the object's name;
# returns FALSE if no name found.
*/
BOOL GetObjectName(NOTXSPROC HWND hwnd, char *Name) {
LPPERLWIN32GUI_USERDATA perlud;
perlud = (LPPERLWIN32GUI_USERDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if( ValidUserData(perlud) ) {
if(NULL != perlud->szWindowName) {
strcat(Name, (char *) perlud->szWindowName);
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
/*
##########################################################################
# (@)INTERNAL:GetObjectNameAndClass(hwnd, *name, *class)
# Gets the object's name AND class (integer);
# returns FALSE if no name found.
*/
BOOL GetObjectNameAndClass(NOTXSPROC HWND hwnd, char *Name, int *obj_class) {
LPPERLWIN32GUI_USERDATA perlud;
perlud = (LPPERLWIN32GUI_USERDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if( ValidUserData(perlud) ) {
if(NULL != perlud->szWindowName) {
strcat(Name, (char *) perlud->szWindowName);
*obj_class = perlud->iClass;
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
/*
##########################################################################
# (@)INTERNAL:CreateObjectWithHandle(char* class_name, HWND handle)
# Create a bless object in specified class with -handle property set.
*/
SV* CreateObjectWithHandle(NOTXSPROC char* class_name, HWND handle) {
HV* hv = newHV();
hv_store(hv, "-handle", 7, newSViv(PTR2IV(handle)), 0);
SV* cv = sv_2mortal(newRV((SV*)hv));
sv_bless(cv, gv_stashpv(class_name, 0));
SvREFCNT_dec(hv);
return cv;
}
/*
##########################################################################
# (@)INTERNAL:GetMenuFromID(ID, *name)
# Gets the menu handle (HMENU) from the ID, searching in Perl's global
# %Win32::GUI::Menus hash; returns NULL if the handle is not found.
*/
HMENU GetMenuFromID(NOTXSPROC int nID) {
HV* hash;
SV** handle;
char temp[80];
hash = perl_get_hv("Win32::GUI::Menus", FALSE);
itoa(nID, temp, 10);
handle = hv_fetch(hash, temp, strlen(temp), FALSE);
if(handle == NULL) return NULL;
return INT2PTR(HMENU,SvIV(*handle));
}
/*
##########################################################################
# (@)INTERNAL:GetMenuName(ID, *name)
# Gets the menu name from the ID;
# returns FALSE if no name found.
*/
BOOL GetMenuName(NOTXSPROC HWND hwnd, int nID, char *Name) {
MENUITEMINFO mii;
HMENU hmenu;
LPPERLWIN32GUI_MENUITEMDATA perlmid;
ZeroMemory(&mii, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA;
/* HEURISTIC: assume the message was from the window's own menu */
hmenu = GetMenu(hwnd);
/* HEURISTIC: no, it wasn't, search in Perl's global hash */
if(hmenu == NULL) hmenu = GetMenuFromID( NOTXSCALL nID );
/* HEURISTIC: if we can get to the item, it's ok, otherwise search in Perl's global hash */
if(GetMenuItemInfo( hmenu, nID, 0, &mii ) == 0) {
hmenu = GetMenuFromID( NOTXSCALL nID );
}
if(GetMenuItemInfo( hmenu, nID, 0, &mii )) {
perlmid = (LPPERLWIN32GUI_MENUITEMDATA) mii.dwItemData;
if(perlmid != NULL && perlmid->dwSize == sizeof(PERLWIN32GUI_MENUITEMDATA)) {
strcpy(Name, perlmid->szName);
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
/*
##########################################################################
# (@)INTERNAL:GetAcceleratorName(ID, *name)
# Gets the accelerator name from the ID;
# returns FALSE if no name found.
*/
BOOL GetAcceleratorName(NOTXSPROC int nID, char *Name) {
HV* hash;
SV** name;
char temp[80];
hash = perl_get_hv("Win32::GUI::Accelerators", FALSE);
itoa(nID, temp, 10);
name = hv_fetch_mg(NOTXSCALL hash, temp, strlen(temp), FALSE);
if(name == NULL) return FALSE;
strcpy(Name, (char *) SvPV_nolen(*name));
return TRUE;
}
/*
##########################################################################
# (@)INTERNAL:GetTimerName(hwnd, id, *name)
# Gets the timer name;
# returns FALSE if no name found.
*/
BOOL GetTimerName(NOTXSPROC HWND hwnd, UINT nID, char *Name) {
HV* parent;
SV** name;
SV** robjarray;
HV* objarray;
SV** robj;
HV* obj;
char temp[80];
parent = HV_SELF_FROM_WINDOW(hwnd);
if(parent == NULL) return FALSE;
itoa(nID, temp, 10);
robjarray = hv_fetch_mg(NOTXSCALL parent, "-timers", 7, FALSE);
if(robjarray == NULL) return FALSE;
objarray = (HV*) SvRV(*robjarray);
robj = hv_fetch_mg(NOTXSCALL objarray, temp, strlen(temp), FALSE);
if(robj == NULL) return FALSE;
obj = (HV*) SvRV(*robj);
if(obj == NULL) return FALSE;
name = hv_fetch_mg(NOTXSCALL obj, "-name", 5, FALSE);
if(name == NULL) return FALSE;
strcpy(Name, (char *) SvPV_nolen(*name));
return TRUE;
}
/*
##########################################################################
# (@)INTERNAL:GetNotifyIconName(hwnd, id, *name)
# Gets the NotifyIcon name;
# returns FALSE if no name found.
*/
BOOL GetNotifyIconName(NOTXSPROC HWND hwnd, UINT nID, char *Name) {
HV* parent;
SV** name;
SV** robjarray;
HV* objarray;
SV** robj;
HV* obj;
char temp[80];
parent = HV_SELF_FROM_WINDOW(hwnd);
if(parent == NULL) return FALSE;
itoa(nID, temp, 10);
robjarray = hv_fetch_mg(NOTXSCALL parent, "-notifyicons", 12, FALSE);
if(robjarray == NULL) return FALSE;
objarray = (HV*) SvRV(*robjarray);
robj = hv_fetch_mg(NOTXSCALL objarray, temp, strlen(temp), FALSE);
if(robj == NULL) return FALSE;
obj = (HV*) SvRV(*robj);
name = hv_fetch_mg(NOTXSCALL obj, "-name", 5, FALSE);
if(name == NULL) return FALSE;
strcpy(Name, (char *) SvPV_nolen(*name));
return TRUE;
}
DWORD CALLBACK RichEditSave(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb) {
HANDLE hfile;
hfile = (HANDLE) dwCookie;
WriteFile(hfile, (LPCVOID) pbBuff, (DWORD) cb, (LPDWORD) pcb, NULL);
return(0);
}
DWORD CALLBACK RichEditLoad(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG FAR *pcb) {
HANDLE hfile;
hfile = (HANDLE) dwCookie;
ReadFile(hfile, (LPVOID) pbBuff, (DWORD) cb, (LPDWORD) pcb, NULL);
return(0);
}
int CALLBACK BrowseForFolderProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) {
UNREFERENCED_PARAMETER(lParam);
if (uMsg == BFFM_INITIALIZED && lpData != 0) {
SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lpData);
}
return(0);
}
/*
##########################################################################
# (@)INTERNAL:AdjustSplitterCoord(self, x)
*/
int AdjustSplitterCoord(NOTXSPROC LPPERLWIN32GUI_USERDATA perlud, int x, int w, HWND phwnd) {
int min, max;
int adjusted;
RECT rc;
adjusted = x;
min = -1;
min = perlud->iMinWidth;
if(min == -1) min = 0;
GetClientRect(phwnd, &rc);
max = -1;
max = perlud->iMaxWidth;
if(max == -1) max = rc.right - w;
if(adjusted < min) adjusted = min;
if(adjusted > max) adjusted = max;
return(adjusted);
}
/*
##########################################################################
# (@)INTERNAL:DrawSplitter(hwnd)
*/
void DrawSplitter(NOTXSPROC HWND hwnd, int x, int y, int w, int h) {
static WORD _dotPatternBmp[8] = { 0x00aa, 0x0055, 0x00aa, 0x0055,
0x00aa, 0x0055, 0x00aa, 0x0055};
HDC hdc;
HBITMAP hbm;
HBRUSH hbr, hbrushOld;
/* create a monochrome checkered pattern */
hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
hbr = CreatePatternBrush(hbm);
/* get a DC on which we can draw, even if the
* class has CS_CLIPCHILDREN or the window
* has WS_CLIPCHILDREN
*/
hdc = GetDCEx(hwnd, NULL, DCX_PARENTCLIP);
SetBrushOrgEx(hdc, x, y, NULL);
hbrushOld = (HBRUSH)SelectObject(hdc, hbr);
/* draw the checkered rectangle to the screen */
PatBlt(hdc, x, y, w, h, PATINVERT);
SelectObject(hdc, hbrushOld);
ReleaseDC(hwnd, hdc);
DeleteObject(hbr);
DeleteObject(hbm);
}
/*
##########################################################################
# (@)INTERNAL:EnumMyWindowsProc(hwnd, lparam)
*/
BOOL CALLBACK EnumMyWindowsProc(HWND hwnd, LPARAM lparam) {
dTHX; /* fetch context */
AV* ary;
DWORD pid;
ary = (AV*) lparam;
GetWindowThreadProcessId(hwnd, &pid);
if(pid == GetCurrentProcessId()) {
av_push(ary, newSViv(PTR2IV(hwnd)));
}
return TRUE;
}
/*
##########################################################################
# (@)INTERNAL:CountMyWindowsProc(hwnd, lparam)
# specialized version of EnumMyWindowsProc for DoModal
*/
BOOL CALLBACK CountMyWindowsProc(HWND hwnd, LPARAM lparam) {
DWORD pid;
DWORD style;
int * i;
i = (int *) lparam;
GetWindowThreadProcessId(hwnd, &pid);
if(pid == GetCurrentProcessId()) {
style = (DWORD) GetWindowLongPtr(hwnd, GWL_STYLE);
if(!(style & GW_CHILD)) {
*i += 1;
}
}
return TRUE;
}
/*
##########################################################################
# (@)INTERNAL:EnableWindowsProc(hwnd, lparam)
# Activate or Deactivate current thread top window.
*/
BOOL CALLBACK EnableWindowsProc(HWND hwnd, LPARAM lParam) {
EnableWindow (hwnd, (BOOL) lParam);
return TRUE;
}
/*
##########################################################################
# (@)INTERNAL:FindChildWindowsProc(hwnd, lparam)
# Activate or Deactivate current thread top window.
*/
BOOL CALLBACK FindChildWindowsProc(HWND hwnd, LPARAM lParam) {
st_FindChildWindow * st = (st_FindChildWindow*) lParam;
LPPERLWIN32GUI_USERDATA perlud = (LPPERLWIN32GUI_USERDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
if( !ValidUserData(perlud) )
return TRUE;
if (strcmp (perlud->szWindowName, st->Name) == 0) {
st->perlchild = perlud;
return FALSE;
}
return TRUE;
}
/*
##########################################################################
# (@)INTERNAL:WindowsHookMsgProc(code, wparam, lparam)
# Callback set by SetWindowsHookEx in TrackPopupMenu()
*/
LRESULT CALLBACK WindowsHookMsgProc(int code, WPARAM wParam, LPARAM lParam) {
SV* perlsub;
SV** arrayref;
SV** arrayval;
AV* array;
MSG* pmsg;
LPPERLWIN32GUI_USERDATA perlud;
I32 count;
int PerlResult;
int i;
if(code == MSGF_MENU) {
PerlResult = 1;
pmsg = (MSG *)lParam;
perlud = (LPPERLWIN32GUI_USERDATA) GetWindowLongPtr(pmsg->hwnd, GWLP_USERDATA);
if(ValidUserData(perlud)) {
PERLUD_FETCH; /* fetch context */
//Tracker 1941264: Check if perlud->avHooks contains NULL. This was causing
//a crash although it should not be possible that this is zero. It's likely
//a bug elsewhere...No harm in the null pointer check though.
if (perlud->avHooks != NULL) {
arrayref = av_fetch(perlud->avHooks, WM_TRACKPOPUP_MSGHOOK, 0);
if(arrayref != NULL) {
array = (AV*) SvRV(*arrayref);
SvREFCNT_inc((SV*) array);
for(i = 0; i <= (int) av_len(array); i++) {
arrayval = av_fetch(array,(I32) i,0);
if(arrayval != NULL) {
perlsub = *arrayval;
SvREFCNT_inc(perlsub);
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(perlud->svSelf);
XPUSHs(sv_2mortal(newSViv(pmsg->message)));
XPUSHs(sv_2mortal(newSViv(pmsg->wParam)));
XPUSHs(sv_2mortal(newSViv(pmsg->lParam)));
PUTBACK;
count = call_sv(perlsub, G_ARRAY|G_EVAL);
SPAGAIN;
if(SvTRUE(ERRSV)) {
ProcessEventError(NOTXSCALL "TrackPopupMenu(WindowsHookMsgProc)", &PerlResult);
} else {
if(count > 0) { PerlResult = POPi; }
}
PUTBACK;
FREETMPS;
LEAVE;
SvREFCNT_dec(perlsub);
}
}
SvREFCNT_dec((SV*) array);
// PerlResult = 0: do not pass event to rest of chain or target windows procedure
// PerlResult = -1: as 0, and terminate application
// PerlResult = anything else, pass event on
if(PerlResult == 0) {
return 1; // stops message being passed along hook chain and to target windows procedure
} else if (PerlResult == -1) {
//send a WM_CANCELMODE to get menu to close
SendMessage(pmsg->hwnd, WM_CANCELMODE, 0, 0);
//post a message to get the main loop to exit
PostMessage(pmsg->hwnd, WM_EXITLOOP, (WPARAM) -1, 0);
return 1; // stops message being passed along hook chain and to target windows procedure
}
}
}
}
}
// pass message along hook chain
return CallNextHookEx(0, code, wParam, lParam);
}