summaryrefslogtreecommitdiff
path: root/plugins/ContextHelp/src/utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ContextHelp/src/utils.cpp')
-rw-r--r--plugins/ContextHelp/src/utils.cpp430
1 files changed, 430 insertions, 0 deletions
diff --git a/plugins/ContextHelp/src/utils.cpp b/plugins/ContextHelp/src/utils.cpp
new file mode 100644
index 0000000000..51d643c774
--- /dev/null
+++ b/plugins/ContextHelp/src/utils.cpp
@@ -0,0 +1,430 @@
+/*
+Miranda IM Help Plugin
+Copyright (C) 2002 Richard Hughes, 2005-2007 H. Herkenrath
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program (Help-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "stdafx.h"
+
+#include <m_button.h>
+
+#define CHARBUFFER_ALLOCSTEP 512 // allocated buffer increase in bytes
+
+#ifdef EDITOR
+extern const TCHAR *szControlTypeNames[] = {
+ _T("Unknown"), _T("Dialog Box"), _T("Button"), _T("Check Box"), _T("Radio Button"),
+ _T("Text"), _T("Image"), _T("Edit Box"), _T("Group Box"), _T("Combo Box"),
+ _T("List Box"), _T("Spin Edit Box"), _T("Progress Bar"), _T("Slider"), _T("List View"),
+ _T("Tree View"), _T("Date/Time Picker"), _T("IP Address"), _T("Status Bar"), _T("Hyperlink"),
+ _T("Contact List"), _T("Scroll Bar"), _T("Animation"), _T("Hotkey"), _T("Tabs"),
+ _T("Colour Picker"), _T("Tool Bar"), _T("Combo Edit Box"), _T("Size Grip") };
+#endif
+
+int GetControlType(HWND hwndCtl)
+{
+ TCHAR szClassName[32];
+ DWORD style;
+
+ if (GetClassLong(hwndCtl, GCW_ATOM) == 32770)
+ return CTLTYPE_DIALOG;
+ if (!GetClassName(hwndCtl, szClassName, sizeof(szClassName)))
+ return CTLTYPE_UNKNOWN;
+ if (!lstrcmpi(szClassName, _T("MDIClient")))
+ return CTLTYPE_DIALOG;
+ else if (!lstrcmpi(szClassName, _T("Static"))) {
+ if (GetClassName(GetParent(hwndCtl), szClassName, sizeof(szClassName)) && !lstrcmpi(szClassName, _T("ComboBox")) || !lstrcmpi(szClassName, WC_COMBOBOXEX))
+ return CTLTYPE_COMBO;
+ style = GetWindowLongPtr(hwndCtl, GWL_STYLE);
+ switch (style&SS_TYPEMASK) {
+ case SS_BITMAP:
+ case SS_BLACKFRAME:
+ case SS_BLACKRECT:
+ case SS_ENHMETAFILE:
+ case SS_ETCHEDFRAME:
+ case SS_ETCHEDHORZ:
+ case SS_ETCHEDVERT:
+ case SS_WHITEFRAME:
+ case SS_WHITERECT:
+ case SS_GRAYFRAME:
+ case SS_GRAYRECT:
+ case SS_ICON:
+ case SS_OWNERDRAW:
+ return CTLTYPE_IMAGE;
+ }
+ return CTLTYPE_TEXT;
+ }
+ else if (GetClassLong(hwndCtl, GCW_ATOM) == 32772) // WinNT/2000/XP: icon titles
+ return CTLTYPE_IMAGE; // class="#32772"
+ else if (!lstrcmpi(szClassName, _T("Button"))) {
+ style = GetWindowLongPtr(hwndCtl, GWL_STYLE);
+ switch (style & 0x24) {
+ case BS_CHECKBOX:
+ case BS_AUTOCHECKBOX:
+ case BS_3STATE:
+ case BS_AUTO3STATE:
+ if (style&BS_PUSHLIKE)
+ break;
+ return CTLTYPE_CHECKBOX;
+ case BS_RADIOBUTTON:
+ case BS_AUTORADIOBUTTON:
+ if (style&BS_PUSHLIKE)
+ break;
+ return CTLTYPE_RADIO;
+ case BS_GROUPBOX:
+ return CTLTYPE_GROUP;
+ }
+ return CTLTYPE_BUTTON;
+ }
+ else if (!lstrcmpi(szClassName, MIRANDABUTTONCLASS))
+ return CTLTYPE_BUTTON;
+ else if (!lstrcmpi(szClassName, _T("Edit"))) {
+ if (GetClassName(GetParent(hwndCtl), szClassName, sizeof(szClassName)) && !lstrcmpi(szClassName, _T("ComboBox")))
+ return CTLTYPE_COMBO;
+ if (GetClassName(GetWindow(hwndCtl, GW_HWNDNEXT), szClassName, sizeof(szClassName)) && !lstrcmpi(szClassName, UPDOWN_CLASS))
+ if ((HWND)SendMessage(GetWindow(hwndCtl, GW_HWNDNEXT), UDM_GETBUDDY, 0, 0) == hwndCtl)
+ return CTLTYPE_SPINEDIT;
+ return CTLTYPE_EDIT;
+ }
+ else if (!_tcsnicmp(szClassName, _T("RichEdit"), 8))
+ return CTLTYPE_EDIT; // RICHEDIT,RichEdit20A,RichEdit20W,RichEdit50W and future versions
+ else if (!lstrcmpi(szClassName, _T("ListBox"))) {
+ style = GetWindowLongPtr(hwndCtl, GWL_STYLE);
+ if (style&LBS_COMBOBOX)
+ return CTLTYPE_COMBO;
+ return CTLTYPE_LIST;
+ }
+ else if (!lstrcmpi(szClassName, _T("ComboLBox")) || !lstrcmpi(szClassName, _T("ComboBox")) || !lstrcmpi(szClassName, WC_COMBOBOXEX))
+ return CTLTYPE_COMBO;
+ else if (!lstrcmpi(szClassName, _T("ScrollBar"))) {
+ style = GetWindowLongPtr(hwndCtl, GWL_STYLE);
+ if (style&SBS_SIZEBOX)
+ return CTLTYPE_SIZEGRIP;
+ return CTLTYPE_SCROLL;
+ }
+ else if (!lstrcmpi(szClassName, WC_PAGESCROLLER))
+ return CTLTYPE_SCROLL;
+ else if (!lstrcmpi(szClassName, UPDOWN_CLASS)) {
+ if (GetClassName((HWND)SendMessage(hwndCtl, UDM_GETBUDDY, 0, 0), szClassName, sizeof(szClassName)) && !lstrcmpi(szClassName, _T("Edit")))
+ return CTLTYPE_SPINEDIT;
+ return CTLTYPE_SCROLL;
+ }
+ else if (!lstrcmpi(szClassName, PROGRESS_CLASS))
+ return CTLTYPE_PROGRESS;
+ else if (!lstrcmpi(szClassName, TRACKBAR_CLASS))
+ return CTLTYPE_SLIDER;
+ else if (!lstrcmpi(szClassName, WC_LISTVIEW) || !lstrcmpi(szClassName, WC_HEADER))
+ return CTLTYPE_LISTVIEW;
+ else if (!lstrcmpi(szClassName, WC_TREEVIEW))
+ return CTLTYPE_TREEVIEW;
+ else if (!lstrcmpi(szClassName, DATETIMEPICK_CLASS) || !lstrcmpi(szClassName, MONTHCAL_CLASS))
+ return CTLTYPE_DATETIME;
+ else if (!lstrcmpi(szClassName, WC_IPADDRESS))
+ return CTLTYPE_IP;
+ else if (!lstrcmpi(szClassName, STATUSCLASSNAME))
+ return CTLTYPE_STATUSBAR;
+ else if (!lstrcmpi(szClassName, (LPCWSTR)CLISTCONTROL_CLASS))
+ return CTLTYPE_CLC; // look at !! casting
+ else if (!lstrcmpi(szClassName, WNDCLASS_HYPERLINK) || !lstrcmpi(szClassName, _T("SysLink")))
+ return CTLTYPE_HYPERLINK;
+ else if (!lstrcmpi(szClassName, ANIMATE_CLASS))
+ return CTLTYPE_ANIMATION;
+ else if (!lstrcmpi(szClassName, HOTKEY_CLASS))
+ return CTLTYPE_HOTKEY;
+ else if (!lstrcmpi(szClassName, WC_TABCONTROL))
+ return CTLTYPE_TABS;
+ else if (!lstrcmpi(szClassName, (LPCWSTR)WNDCLASS_COLOURPICKER))
+ return CTLTYPE_COLOUR; // look at !! casting
+ else if (!lstrcmpi(szClassName, TOOLBARCLASSNAME) || !lstrcmpi(szClassName, REBARCLASSNAME))
+ return CTLTYPE_TOOLBAR;
+ switch (SendMessage(hwndCtl, WM_GETDLGCODE, 0, (LPARAM)NULL) & 0x2070) {
+ case DLGC_RADIOBUTTON:
+ return CTLTYPE_RADIO;
+ case DLGC_DEFPUSHBUTTON:
+ case DLGC_UNDEFPUSHBUTTON:
+ case DLGC_BUTTON:
+ return CTLTYPE_BUTTON;
+ }
+ hwndCtl = GetWindow(hwndCtl, GW_CHILD); // check for owner-extended control
+ if (hwndCtl != NULL)
+ return GetControlType(hwndCtl);
+
+ return CTLTYPE_UNKNOWN;
+}
+
+HWND GetControlDialog(HWND hwndCtl)
+{
+ TCHAR szClassName[32];
+ while (hwndCtl != NULL) {
+ if (GetClassLong(hwndCtl, GCW_ATOM) == 32770)
+ return hwndCtl;
+ if (GetClassName(hwndCtl, szClassName, sizeof(szClassName)))
+ if (!lstrcmpi(szClassName, _T("MDIClient")))
+ return hwndCtl;
+ hwndCtl = GetParent(hwndCtl);
+ }
+
+ return hwndCtl;
+}
+
+// never fails
+int GetControlTitle(HWND hwndCtl, TCHAR *pszTitle, int cchTitle)
+{
+ TCHAR *p;
+ int res = 0;
+ if (cchTitle)
+ pszTitle[0] = _T('\0');
+ switch (GetControlType(hwndCtl)) {
+ case CTLTYPE_DIALOG:
+ case CTLTYPE_BUTTON:
+ case CTLTYPE_CHECKBOX:
+ case CTLTYPE_RADIO:
+ case CTLTYPE_GROUP:
+ case CTLTYPE_TEXT:
+ case CTLTYPE_HYPERLINK:
+ res = GetWindowText(hwndCtl, pszTitle, cchTitle);
+ }
+ hwndCtl = GetWindow(hwndCtl, GW_HWNDPREV);
+ if (hwndCtl)
+ switch (GetControlType(hwndCtl)) {
+ case CTLTYPE_TEXT:
+ case CTLTYPE_GROUP:
+ res = GetWindowText(hwndCtl, pszTitle, cchTitle);
+ }
+ if (res)
+ for (p = pszTitle; *p != 0; p++) {
+ // strip-off ampersand (&) prefix character
+ if (*p == _T('&') && *(p + 1) != _T('&')) {
+ MoveMemory(p, p + 1, (lstrlen(p + 1) + 1)*sizeof(TCHAR));
+ res--;
+ if (*(p + 1) == 0)
+ break;
+ }
+ // strip-off last ':'
+ if (*p == _T(':') && *(p + 1) == 0) {
+ *p = 0;
+ res--;
+ break;
+ }
+ }
+
+ return res;
+}
+
+// mir_free() the return value
+char *GetControlModuleName(HWND hwndCtl)
+{
+ char szModule[512], szMainModule[512];
+ char *pszFile, *buf;
+
+ if (!GetModuleFileNameA(NULL, szMainModule, sizeof(szMainModule)))
+ return NULL;
+ buf = strrchr(szMainModule, '\\');
+ if (buf != NULL)
+ *buf = '\0';
+ else
+ buf = szMainModule;
+
+ do {
+ if (!GetModuleFileNameA((HINSTANCE)GetWindowLongPtr(hwndCtl, GWLP_HINSTANCE), szModule, sizeof(szModule)))
+ return NULL;
+ pszFile = strrchr(szModule, '\\');
+ if (pszFile != NULL) {
+ *pszFile = '\0';
+ pszFile++;
+ }
+ else
+ pszFile = szModule;
+ if (lstrlenA(szModule)>lstrlenA(szMainModule))
+ szModule[lstrlenA(szMainModule)] = '\0';
+ if (!lstrcmpiA(szModule, szMainModule))
+ break; // found miranda module
+ hwndCtl = GetParent(hwndCtl);
+ } while (hwndCtl != NULL);
+
+ buf = strrchr(pszFile, '.');
+ if (buf != NULL)
+ *buf++ = '\0';
+
+ return mir_strdup(pszFile);
+}
+
+
+struct CreateControlIdData {
+ int id;
+ HWND hwndCtl;
+};
+
+static BOOL CALLBACK CreateCtlIdEnumProc(HWND hwnd, LPARAM lParam)
+{
+ struct CreateControlIdData* ccid = (struct CreateControlIdData*)lParam;
+ TCHAR szClassName[32];
+ if (GetClassLong(hwnd, GCW_ATOM) == 32770) // class="#32770"
+ return TRUE;
+ if (GetClassName(hwnd, szClassName, sizeof(szClassName)))
+ if (!lstrcmpi(szClassName, _T("MDIClient")))
+ return TRUE;
+ if (GetWindowLongPtr(hwnd, GWL_ID) <= 0 || GetWindowLongPtr(hwnd, GWL_ID) == 0xFFFF)
+ ccid->id--;
+ if (hwnd == ccid->hwndCtl)
+ ccid->hwndCtl = NULL;
+
+ return ccid->hwndCtl != NULL;
+}
+
+int GetControlID(HWND hwndCtl)
+{
+ struct CreateControlIdData ccid;
+ TCHAR szClassName[32];
+
+ // obey context ID when set (rarely)
+ ccid.id = GetWindowContextHelpId(hwndCtl);
+ if (ccid.id != 0)
+ return ccid.id;
+
+ if (GetClassName(hwndCtl, szClassName, sizeof(szClassName))) {
+ if (!lstrcmpi(szClassName, UPDOWN_CLASS)) { // handle spinner controls as a whole
+ DWORD style;
+ HWND hwndBuddy;
+ style = GetWindowLongPtr(hwndCtl, GWL_STYLE);
+ if (style&UDS_ALIGNRIGHT || style&UDS_ALIGNLEFT) {
+ hwndBuddy = (HWND)SendMessage(hwndCtl, UDM_GETBUDDY, 0, 0);
+ if (hwndBuddy != NULL)
+ hwndCtl = hwndBuddy;
+ }
+ }
+ else if (GetClassLong(hwndCtl, GCW_ATOM) == 32770 || !lstrcmpi(szClassName, _T("MDIClient")))
+ return 0; // ensure this is always unset
+ }
+ ccid.id = GetWindowLongPtr(hwndCtl, GWL_ID);
+ if (ccid.id <= 0 || ccid.id == 0xFFFF) {
+ ccid.id = -1;
+ ccid.hwndCtl = hwndCtl;
+ EnumChildWindows(GetParent(hwndCtl), CreateCtlIdEnumProc, (LPARAM)&ccid);
+ if (ccid.hwndCtl != NULL)
+ return -1;
+ }
+ return ccid.id;
+}
+
+// mir_free() the return value
+static char *Base64Encode(PBYTE pBuf, int cbBuf)
+{
+ /*NETLIBBASE64 nlb64;
+ nlb64.pbDecoded=pBuf;
+ nlb64.cbDecoded=cbBuf;
+ nlb64.cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded=(char*)mir_alloc(nlb64.cchEncoded);
+ if(nlb64.pszEncoded==NULL || !CallService(MS_NETLIB_BASE64ENCODE,0,(LPARAM)&nlb64)) {
+ mir_free(nlb64.pszEncoded); // does NULL check
+ return NULL;
+ }
+ return nlb64.pszEncoded;*/
+
+ return (char*)mir_base64_encode(pBuf, cbBuf);
+}
+
+struct CreateDialogIdBinaryData {
+ int alloced, count;
+ PBYTE buf;
+ HWND hwndParent;
+};
+
+static INT_PTR CALLBACK CreateDlgIdBinEnumProc(HWND hwnd, LPARAM lParam)
+{
+ struct CreateDialogIdBinaryData *cdib = (struct CreateDialogIdBinaryData*)lParam;
+ int type;
+
+ if (GetParent(hwnd) != cdib->hwndParent)
+ return TRUE;
+ type = GetControlType(hwnd);
+ if (type == CTLTYPE_DIALOG || type == CTLTYPE_TEXT || type == CTLTYPE_GROUP)
+ return TRUE;
+ if (cdib->count + 3>cdib->alloced) {
+ PBYTE buf2;
+ buf2 = (PBYTE)mir_realloc(cdib->buf, cdib->alloced + 32);
+ if (buf2 == NULL)
+ return FALSE;
+ cdib->alloced += 32;
+ cdib->buf = buf2;
+ }
+ cdib->buf[cdib->count] = (BYTE)type;
+ *(PWORD)(cdib->buf + cdib->count + 1) = (WORD)GetWindowLongPtr(hwnd, GWL_ID);
+ cdib->count += 3;
+
+ return TRUE;
+}
+
+// mir_free() the return value
+char *CreateDialogIdString(HWND hwndDlg)
+{
+ struct CreateDialogIdBinaryData cdib;
+ char *szRet;
+
+ ZeroMemory(&cdib, sizeof(cdib));
+ if (hwndDlg == NULL)
+ return NULL;
+ cdib.hwndParent = hwndDlg;
+ EnumChildWindows(hwndDlg, (WNDENUMPROC)CreateDlgIdBinEnumProc, (LPARAM)&cdib);
+ if (cdib.buf == NULL)
+ return NULL;
+ szRet = Base64Encode(cdib.buf, cdib.count);
+ mir_free(cdib.buf);
+
+ return szRet;
+}
+
+
+void AppendCharToCharBuffer(struct ResizableCharBuffer *rcb, char c)
+{
+ if (rcb->cbAlloced <= rcb->iEnd + 1) {
+ char* buf = (char*)mir_realloc(rcb->sz, (rcb->cbAlloced + CHARBUFFER_ALLOCSTEP));
+ if (buf == NULL)
+ return;
+ rcb->sz = buf;
+ rcb->cbAlloced += CHARBUFFER_ALLOCSTEP;
+ }
+ rcb->sz[rcb->iEnd++] = c;
+ rcb->sz[rcb->iEnd] = '\0';
+}
+
+void AppendToCharBuffer(struct ResizableCharBuffer *rcb, const char *fmt, ...)
+{
+ va_list va;
+ int charsDone;
+ char *buf;
+
+ if (rcb->cbAlloced == 0) {
+ buf = (char*)mir_alloc(CHARBUFFER_ALLOCSTEP);
+ if (buf == NULL)
+ return;
+ rcb->sz = buf;
+ rcb->cbAlloced = CHARBUFFER_ALLOCSTEP;
+ }
+ va_start(va, fmt);
+ for (;;) {
+ charsDone = mir_vsnprintf(rcb->sz + rcb->iEnd, rcb->cbAlloced - rcb->iEnd, fmt, va);
+ if (charsDone >= 0)
+ break; // returns -1 when buffer not large enough
+ buf = (char*)mir_realloc(rcb->sz, rcb->cbAlloced + CHARBUFFER_ALLOCSTEP);
+ if (buf == NULL) {
+ charsDone = 0;
+ break;
+ }
+ rcb->sz = buf;
+ rcb->cbAlloced += CHARBUFFER_ALLOCSTEP;
+ }
+ va_end(va);
+ rcb->iEnd += charsDone;
+}