summaryrefslogtreecommitdiff
path: root/src/mir_core
diff options
context:
space:
mode:
Diffstat (limited to 'src/mir_core')
-rw-r--r--src/mir_core/commonheaders.cpp2
-rw-r--r--src/mir_core/commonheaders.h63
-rw-r--r--src/mir_core/db.cpp191
-rw-r--r--src/mir_core/langpack.cpp631
-rw-r--r--src/mir_core/lists.cpp278
-rw-r--r--src/mir_core/md5.cpp358
-rw-r--r--src/mir_core/memory.cpp280
-rw-r--r--src/mir_core/mir_core.def126
-rw-r--r--src/mir_core/mir_core_10.vcxproj238
-rw-r--r--src/mir_core/mir_core_10.vcxproj.filters76
-rw-r--r--src/mir_core/miranda.cpp97
-rw-r--r--src/mir_core/miranda.h131
-rw-r--r--src/mir_core/modules.cpp601
-rw-r--r--src/mir_core/path.cpp210
-rw-r--r--src/mir_core/sha1.cpp155
-rw-r--r--src/mir_core/threads.cpp372
-rw-r--r--src/mir_core/utf.cpp406
-rw-r--r--src/mir_core/utils.cpp150
18 files changed, 4365 insertions, 0 deletions
diff --git a/src/mir_core/commonheaders.cpp b/src/mir_core/commonheaders.cpp
new file mode 100644
index 0000000000..95b2201163
--- /dev/null
+++ b/src/mir_core/commonheaders.cpp
@@ -0,0 +1,2 @@
+#include "commonheaders.h"
+
diff --git a/src/mir_core/commonheaders.h b/src/mir_core/commonheaders.h
new file mode 100644
index 0000000000..2d04e12f4b
--- /dev/null
+++ b/src/mir_core/commonheaders.h
@@ -0,0 +1,63 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#define MIRANDA_VER 0x0A00
+
+#define WINVER 0x0700
+#define _WIN32_WINNT 0x0700
+#define _WIN32_IE 0x0601
+
+#define INCL_WINSOCK_API_TYPEDEFS 1
+
+#include "m_stdhdr.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+#include <uxtheme.h>
+#include <commctrl.h>
+#include <vssym32.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <limits.h>
+#include <string.h>
+#include <locale.h>
+#include <direct.h>
+
+#include <win2k.h>
+
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <m_database.h>
+#include <newpluginapi.h>
+
+#include "miranda.h"
+
+#include <m_ssl.h>
+#include <m_xml.h>
diff --git a/src/mir_core/db.cpp b/src/mir_core/db.cpp
new file mode 100644
index 0000000000..37b89d8399
--- /dev/null
+++ b/src/mir_core/db.cpp
@@ -0,0 +1,191 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+MIR_CORE_DLL(int) db_get_b(HANDLE hContact, const char *szModule, const char *szSetting, int errorValue)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = szModule;
+ cgs.szSetting = szSetting;
+ cgs.pValue = &dbv;
+ if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs))
+ return errorValue;
+ return dbv.bVal;
+}
+
+MIR_CORE_DLL(int) db_get_w(HANDLE hContact, const char *szModule, const char *szSetting, int errorValue)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = szModule;
+ cgs.szSetting = szSetting;
+ cgs.pValue = &dbv;
+ if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs))
+ return errorValue;
+ return dbv.wVal;
+}
+
+MIR_CORE_DLL(DWORD) db_get_dw(HANDLE hContact, const char *szModule, const char *szSetting, DWORD errorValue)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = szModule;
+ cgs.szSetting = szSetting;
+ cgs.pValue = &dbv;
+ if (CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs))
+ return errorValue;
+ return dbv.dVal;
+}
+
+MIR_CORE_DLL(INT_PTR) db_get(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv)
+{
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = szModule;
+ cgs.szSetting = szSetting;
+ cgs.pValue = dbv;
+
+ return CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&cgs);
+}
+
+MIR_CORE_DLL(INT_PTR) db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType)
+{
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = szModule;
+ cgs.szSetting = szSetting;
+ cgs.pValue = dbv;
+ dbv->type = (BYTE)nType;
+ return CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&cgs);
+}
+
+MIR_CORE_DLL(char*) db_get_sa(HANDLE hContact, const char *szModule, const char *szSetting)
+{
+ char *str = NULL;
+ DBVARIANT dbv = {0};
+ db_get_s(hContact, szModule, szSetting, &dbv, DBVT_ASCIIZ);
+ if (dbv.type == DBVT_ASCIIZ)
+ str = mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ return str;
+}
+
+MIR_CORE_DLL(wchar_t*) db_get_wsa(HANDLE hContact, const char *szModule, const char *szSetting)
+{
+ wchar_t *str = NULL;
+ DBVARIANT dbv={0};
+ db_get_s(hContact, szModule, szSetting, &dbv, DBVT_WCHAR);
+ if (dbv.type == DBVT_WCHAR)
+ str = mir_wstrdup(dbv.pwszVal);
+ DBFreeVariant(&dbv);
+ return str;
+}
+
+MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv)
+{
+ return CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)dbv);
+}
+
+MIR_CORE_DLL(INT_PTR) db_unset(HANDLE hContact, const char *szModule, const char *szSetting)
+{
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = szModule;
+ cgs.szSetting = szSetting;
+ return CallService(MS_DB_CONTACT_DELETESETTING, (WPARAM)hContact, (LPARAM)&cgs);
+}
+
+MIR_CORE_DLL(INT_PTR) db_set_b(HANDLE hContact, const char *szModule, const char *szSetting, BYTE val)
+{
+ DBCONTACTWRITESETTING cws;
+ cws.szModule = szModule;
+ cws.szSetting = szSetting;
+ cws.value.type = DBVT_BYTE;
+ cws.value.bVal = val;
+ return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws);
+}
+
+MIR_CORE_DLL(INT_PTR) db_set_w(HANDLE hContact, const char *szModule, const char *szSetting, WORD val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule = szModule;
+ cws.szSetting = szSetting;
+ cws.value.type = DBVT_WORD;
+ cws.value.wVal = val;
+ return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws);
+}
+
+MIR_CORE_DLL(INT_PTR) db_set_dw(HANDLE hContact, const char *szModule, const char *szSetting, DWORD val)
+{
+ DBCONTACTWRITESETTING cws;
+ cws.szModule = szModule;
+ cws.szSetting = szSetting;
+ cws.value.type = DBVT_DWORD;
+ cws.value.dVal = val;
+ return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws);
+}
+
+MIR_CORE_DLL(INT_PTR) db_set_s(HANDLE hContact, const char *szModule, const char *szSetting, const char *val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule = szModule;
+ cws.szSetting = szSetting;
+ cws.value.type = DBVT_ASCIIZ;
+ cws.value.pszVal = (char*)val;
+ return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws);
+}
+
+MIR_CORE_DLL(INT_PTR) db_set_ws(HANDLE hContact, const char *szModule, const char *szSetting, const WCHAR *val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule = szModule;
+ cws.szSetting = szSetting;
+ cws.value.type = DBVT_WCHAR;
+ cws.value.pwszVal = (WCHAR*)val;
+ return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws);
+}
+
+MIR_CORE_DLL(INT_PTR) db_set_utf(HANDLE hContact, const char *szModule, const char *szSetting, const char *val)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule = szModule;
+ cws.szSetting = szSetting;
+ cws.value.type = DBVT_UTF8;
+ cws.value.pszVal = (char*)val;
+ return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws);
+}
+
+MIR_CORE_DLL(INT_PTR) db_set_blob(HANDLE hContact, const char *szModule, const char *szSetting, void *val, unsigned len)
+{
+ DBCONTACTWRITESETTING cws;
+
+ cws.szModule = szModule;
+ cws.szSetting = szSetting;
+ cws.value.type = DBVT_BLOB;
+ cws.value.cpbVal = (WORD)len;
+ cws.value.pbVal = (unsigned char*)val;
+ return CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)hContact, (LPARAM)&cws);
+}
diff --git a/src/mir_core/langpack.cpp b/src/mir_core/langpack.cpp
new file mode 100644
index 0000000000..015af8f469
--- /dev/null
+++ b/src/mir_core/langpack.cpp
@@ -0,0 +1,631 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+#define LANGPACK_BUF_SIZE 4000
+
+static int CompareMuuids(const MUUID* p1, const MUUID* p2)
+{
+ return memcmp(p1, p2, sizeof(MUUID));
+}
+
+static LIST<MUUID> lMuuids(10, CompareMuuids);
+static MUUID* pCurrentMuuid = NULL;
+
+static BOOL bModuleInitialized = FALSE;
+
+struct LangPackEntry {
+ DWORD englishHash;
+ char *local;
+ wchar_t *wlocal;
+ MUUID* pMuuid;
+ LangPackEntry* pNext; // for langpack items with the same hash value
+};
+
+struct LangPackStruct {
+ TCHAR filename[MAX_PATH];
+ TCHAR filePath[MAX_PATH];
+ char language[64];
+ char lastModifiedUsing[64];
+ char authors[256];
+ char authorEmail[128];
+ LangPackEntry *entry;
+ int entryCount, entriesAlloced;
+ LCID localeID;
+ UINT defaultANSICp;
+} static langPack;
+
+static int IsEmpty(char *str)
+{
+ int i = 0;
+
+ while (str[i])
+ {
+ if (str[i] != ' ' && str[i] != '\r' && str[i] != '\n')
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+static void ConvertBackslashes(char *str, UINT fileCp)
+{
+ char *pstr;
+ for (pstr = str; *pstr; pstr = CharNextExA(fileCp, pstr, 0)) {
+ if (*pstr == '\\') {
+ switch(pstr[1]) {
+ case 'n': *pstr = '\n'; break;
+ case 't': *pstr = '\t'; break;
+ case 'r': *pstr = '\r'; break;
+ default: *pstr = pstr[1]; break;
+ }
+ memmove(pstr+1, pstr+2, strlen(pstr+2) + 1);
+} } }
+
+#ifdef _DEBUG
+//#pragma optimize("gt", on)
+#endif
+
+// MurmurHash2
+MIR_CORE_DLL(unsigned int) mir_hash(const void * key, unsigned int len)
+{
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ unsigned int h = len;
+
+ // Mix 4 bytes at a time into the hash
+ const unsigned char * data = (const unsigned char *)key;
+
+ while (len >= 4)
+ {
+ unsigned int k = *(unsigned int *)data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+static unsigned int __fastcall hashstrW(const char * key)
+{
+ if (key == NULL) return 0;
+ const unsigned int len = (unsigned int)wcslen((const wchar_t*)key);
+ char* buf = (char*)alloca(len + 1);
+ for (unsigned i = 0; i <= len ; ++i)
+ buf[i] = key[i << 1];
+ return mir_hash(buf, len);
+}
+
+static int SortLangPackHashesProc(LangPackEntry *arg1, LangPackEntry *arg2)
+{
+ if (arg1->englishHash < arg2->englishHash) return -1;
+ if (arg1->englishHash > arg2->englishHash) return 1;
+
+ return (arg1->pMuuid < arg2->pMuuid) ? -1 : 1;
+}
+
+static void swapBytes(void* p, size_t iSize)
+{
+ char *head = (char *)p; // here
+ char *tail = head + iSize - 1;
+
+ for (; tail > head; --tail, ++head) {
+ char temp = *head;
+ *head = *tail;
+ *tail = temp;
+ }
+}
+
+static bool EnterMuuid(const char* p, MUUID& result)
+{
+ if (*p++ != '{')
+ return false;
+
+ BYTE* d = (BYTE*)&result;
+
+ for (int nBytes = 0; *p && nBytes < 24; p++) {
+ if (*p == '-')
+ continue;
+
+ if (*p == '}')
+ break;
+
+ if ( !isxdigit(*p))
+ return false;
+
+ if ( !isxdigit(p[1]))
+ return false;
+
+ int c = 0;
+ if (sscanf(p, "%2x", &c) != 1)
+ return false;
+
+ *d++ = (BYTE)c;
+ nBytes++;
+ p++;
+ }
+
+ if (*p != '}')
+ return false;
+
+ swapBytes(&result.a, sizeof(result.a));
+ swapBytes(&result.b, sizeof(result.b));
+ swapBytes(&result.c, sizeof(result.c));
+ return true;
+}
+
+static void LoadLangPackFile(FILE* fp, char* line, UINT fileCp)
+{
+ while ( !feof(fp)) {
+ if (fgets(line, LANGPACK_BUF_SIZE, fp) == NULL)
+ break;
+
+ if (IsEmpty(line) || line[0] == ';' || line[0] == 0)
+ continue;
+
+ rtrim(line);
+
+ if (line[0] == '#') {
+ strlwr(line);
+
+ if ( !memcmp(line+1, "include", 7)) {
+ TCHAR tszFileName[ MAX_PATH ];
+ TCHAR* fileName = mir_a2t(ltrim(line+9));
+ mir_sntprintf(tszFileName, SIZEOF(tszFileName), _T("%s%s"), langPack.filePath, fileName);
+ mir_free(fileName);
+
+ FILE* p = _tfopen(tszFileName, _T("r"));
+ if (p) {
+ line[0] = 0;
+ fgets(line, SIZEOF(line), p);
+
+ UINT fileCp = CP_ACP;
+ if (strlen(line) >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf') {
+ fileCp = CP_UTF8;
+ fseek(p, 3, SEEK_SET);
+ }
+ else {
+ fileCp = langPack.defaultANSICp;
+ fseek(p, 0, SEEK_SET);
+ }
+
+ LoadLangPackFile(p, line, fileCp);
+ fclose(p);
+ }
+ }
+ else if ( !memcmp(line+1, "muuid", 5)) {
+ MUUID t;
+ if ( !EnterMuuid(line+7, t))
+ continue;
+
+ MUUID* pNew = (MUUID*)mir_alloc(sizeof(MUUID));
+ memcpy(pNew, &t, sizeof(t));
+ lMuuids.insert(pNew);
+ pCurrentMuuid = pNew;
+ }
+
+ continue;
+ }
+
+ ConvertBackslashes(line, fileCp);
+
+ if (line[0] == '[' && line[ lstrlenA(line)-1 ] == ']') {
+ if (langPack.entryCount && langPack.entry[ langPack.entryCount-1].local == NULL)
+ langPack.entryCount--;
+
+ char* pszLine = line+1;
+ line[ lstrlenA(line)-1 ] = '\0';
+ if (++langPack.entryCount > langPack.entriesAlloced) {
+ langPack.entriesAlloced += 128;
+ langPack.entry = (LangPackEntry*)mir_realloc(langPack.entry, sizeof(LangPackEntry)*langPack.entriesAlloced);
+ }
+
+ LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ];
+ E->englishHash = mir_hashstr(pszLine);
+ E->local = NULL;
+ E->wlocal = NULL;
+ E->pMuuid = pCurrentMuuid;
+ E->pNext = NULL;
+ continue;
+ }
+
+ if ( !langPack.entryCount)
+ continue;
+
+ LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ];
+ if (E->local == NULL) {
+ E->local = mir_strdup(line);
+ if (fileCp == CP_UTF8)
+ Utf8DecodeCP(E->local, langPack.defaultANSICp, NULL);
+
+ int iNeeded = MultiByteToWideChar(fileCp, 0, line, -1, 0, 0);
+ E->wlocal = (wchar_t *)mir_alloc((iNeeded+1) * sizeof(wchar_t));
+ MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal, iNeeded);
+ }
+ else {
+ size_t iOldLenA = strlen(E->local);
+ E->local = (char*)mir_realloc(E->local, iOldLenA + strlen(line) + 2);
+ strcat(E->local, "\n");
+ strcat(E->local, line);
+
+ if (fileCp == CP_UTF8)
+ Utf8DecodeCP(E->local + iOldLenA + 1, langPack.defaultANSICp, NULL);
+
+ int iNeeded = MultiByteToWideChar(fileCp, 0, line, -1, 0, 0);
+ size_t iOldLen = wcslen(E->wlocal);
+ E->wlocal = (wchar_t*)mir_realloc(E->wlocal, (sizeof(wchar_t) * (iOldLen + iNeeded + 2)));
+ wcscat(E->wlocal, L"\n");
+ MultiByteToWideChar(fileCp, 0, line, -1, E->wlocal + iOldLen + 1, iNeeded);
+ }
+ }
+}
+
+MIR_CORE_DLL(int) LoadLangPack(const TCHAR *szLangPack)
+{
+ int startOfLine=0;
+ USHORT langID;
+
+ lstrcpy(langPack.filename, szLangPack);
+ lstrcpy(langPack.filePath, szLangPack);
+ TCHAR* p = _tcsrchr(langPack.filePath, '\\');
+ if (p)
+ p[1] = 0;
+
+ FILE *fp = _tfopen(szLangPack, _T("rt"));
+ if (fp == NULL)
+ return 1;
+
+ char line[ LANGPACK_BUF_SIZE ] = "";
+ fgets(line, SIZEOF(line), fp);
+
+ UINT fileCp = CP_ACP;
+ size_t lineLen = strlen(line);
+ if (lineLen >= 3 && line[0] == '\xef' && line[1] == '\xbb' && line[2] == '\xbf')
+ {
+ fileCp = CP_UTF8;
+ memmove(line, line + 3, lineLen - 2);
+ }
+
+ lrtrim(line);
+ if (lstrcmpA(line, "Miranda Language Pack Version 1")) {
+ fclose(fp);
+ return 2;
+ }
+
+ //headers
+ while ( !feof(fp)) {
+ startOfLine = ftell(fp);
+ if (fgets(line, SIZEOF(line), fp) == NULL)
+ break;
+
+ lrtrim(line);
+ if (IsEmpty(line) || line[0] == ';' || line[0] == 0)
+ continue;
+
+ if (line[0] == '[' || line[0] == '#')
+ break;
+
+ char* pszColon = strchr(line, ':');
+ if (pszColon == NULL) {
+ fclose(fp);
+ return 3;
+ }
+
+ *pszColon++ = 0;
+ if ( !lstrcmpA(line, "Language")) {mir_snprintf(langPack.language, sizeof(langPack.language), "%s", pszColon); lrtrim(langPack.language);}
+ else if ( !lstrcmpA(line, "Last-Modified-Using")) {mir_snprintf(langPack.lastModifiedUsing, sizeof(langPack.lastModifiedUsing), "%s", pszColon); lrtrim(langPack.lastModifiedUsing);}
+ else if ( !lstrcmpA(line, "Authors")) {mir_snprintf(langPack.authors, sizeof(langPack.authors), "%s", pszColon); lrtrim(langPack.authors);}
+ else if ( !lstrcmpA(line, "Author-email")) {mir_snprintf(langPack.authorEmail, sizeof(langPack.authorEmail), "%s", pszColon); lrtrim(langPack.authorEmail);}
+ else if ( !lstrcmpA(line, "Locale")) {
+ char szBuf[20], *stopped;
+
+ lrtrim(pszColon + 1);
+ langID = (USHORT)strtol(pszColon, &stopped, 16);
+ langPack.localeID = MAKELCID(langID, 0);
+ GetLocaleInfoA(langPack.localeID, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10);
+ szBuf[5] = 0; // codepages have max. 5 digits
+ langPack.defaultANSICp = atoi(szBuf);
+ if (fileCp == CP_ACP)
+ fileCp = langPack.defaultANSICp;
+ }
+ }
+
+ //body
+ fseek(fp, startOfLine, SEEK_SET);
+ langPack.entriesAlloced = 0;
+
+ LoadLangPackFile(fp, line, fileCp);
+ fclose(fp);
+ pCurrentMuuid = NULL;
+
+ qsort(langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int SortLangPackHashesProc2(LangPackEntry *arg1, LangPackEntry *arg2)
+{
+ if (arg1->englishHash < arg2->englishHash) return -1;
+ if (arg1->englishHash > arg2->englishHash) return 1;
+ return 0;
+}
+
+static char *LangPackTranslateString(MUUID* pUuid, const char *szEnglish, const int W)
+{
+ if (langPack.entryCount == 0 || szEnglish == NULL)
+ return (char*)szEnglish;
+
+ LangPackEntry key, *entry;
+ key.englishHash = W ? hashstrW(szEnglish) : mir_hashstr(szEnglish);
+ entry = (LangPackEntry*)bsearch(&key, langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc2);
+ if (entry == NULL)
+ return (char*)szEnglish;
+
+ // try to find the exact match, otherwise the first entry will be returned
+ if (pUuid) {
+ for (LangPackEntry* p = entry->pNext; p != NULL; p = p->pNext) {
+ if (p->pMuuid == pUuid) {
+ entry = p;
+ break;
+ } } }
+
+ return W ? (char *)entry->wlocal : entry->local;
+}
+
+MIR_CORE_DLL(int) Langpack_GetDefaultCodePage()
+{
+ return langPack.defaultANSICp;
+}
+
+MIR_CORE_DLL(int) Langpack_GetDefaultLocale()
+{
+ return (langPack.localeID == 0) ? LOCALE_USER_DEFAULT : langPack.localeID;
+}
+
+MIR_CORE_DLL(TCHAR*) Langpack_PcharToTchar(const char* pszStr)
+{
+ if (pszStr == NULL)
+ return NULL;
+
+ int len = (int)strlen(pszStr);
+ TCHAR* result = (TCHAR*)alloca((len+1)*sizeof(TCHAR));
+ MultiByteToWideChar(Langpack_GetDefaultCodePage(), 0, pszStr, -1, result, len);
+ result[len] = 0;
+ return mir_wstrdup(TranslateW(result));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(char*) TranslateA_LP(const char* str, int hLangpack)
+{
+ return (char*)LangPackTranslateString(Langpack_LookupUuid(hLangpack), str, FALSE);
+}
+
+MIR_CORE_DLL(WCHAR*) TranslateW_LP(const WCHAR* str, int hLangpack)
+{
+ return (WCHAR*)LangPackTranslateString(Langpack_LookupUuid(hLangpack), (LPCSTR)str, TRUE);
+}
+
+MIR_CORE_DLL(void) TranslateMenu_LP(HMENU hMenu, int hLangpack)
+{
+ MUUID* uuid = Langpack_LookupUuid(hLangpack);
+
+ MENUITEMINFO mii;
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ for (int i = GetMenuItemCount(hMenu)-1; i >= 0; i--) {
+ TCHAR str[256];
+ mii.fMask = MIIM_TYPE|MIIM_SUBMENU;
+ mii.dwTypeData = (TCHAR*)str;
+ mii.cch = SIZEOF(str);
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+
+ if (mii.cch && mii.dwTypeData) {
+ TCHAR* result = (TCHAR*)LangPackTranslateString(uuid, (const char*)mii.dwTypeData, TRUE);
+ if (result != mii.dwTypeData) {
+ mii.dwTypeData = result;
+ mii.fMask = MIIM_TYPE;
+ SetMenuItemInfo(hMenu, i, TRUE, &mii);
+ } }
+
+ if (mii.hSubMenu != NULL) TranslateMenu_LP(mii.hSubMenu, hLangpack);
+ }
+}
+
+static void TranslateWindow(MUUID* pUuid, HWND hwnd)
+{
+ TCHAR title[2048];
+ GetWindowText(hwnd, title, SIZEOF(title));
+
+ TCHAR* result = (TCHAR*)LangPackTranslateString(pUuid, (const char*)title, TRUE);
+ if (result != title)
+ SetWindowText(hwnd, result);
+}
+
+struct LANGPACKTRANSLATEDIALOG
+{
+ HWND hwndDlg;
+ int hLangpack;
+};
+
+static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd, LPARAM lParam)
+{
+ int hLangpack = (int)lParam;
+ TCHAR szClass[32];
+ int id = GetDlgCtrlID(hwnd);
+
+ MUUID* uuid = Langpack_LookupUuid(hLangpack);
+
+ GetClassName(hwnd, szClass, SIZEOF(szClass));
+ if ( !lstrcmpi(szClass, _T("static")) || !lstrcmpi(szClass, _T("hyperlink")) || !lstrcmpi(szClass, _T("button")) || !lstrcmpi(szClass, _T("MButtonClass")) || !lstrcmpi(szClass, _T("MHeaderbarCtrl")))
+ TranslateWindow(uuid, hwnd);
+ else if ( !lstrcmpi(szClass, _T("edit"))) {
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & ES_READONLY)
+ TranslateWindow(uuid, hwnd);
+ }
+ return TRUE;
+}
+
+MIR_CORE_DLL(void) TranslateDialog_LP(HWND hDlg, int hLangpack)
+{
+ TranslateWindow( Langpack_LookupUuid(hLangpack), hDlg);
+ EnumChildWindows(hDlg, TranslateDialogEnumProc, hLangpack);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(MUUID*) Langpack_LookupUuid(WPARAM wParam)
+{
+ int idx = (wParam >> 16) & 0xFFFF;
+ return (idx > 0 && idx <= lMuuids.getCount()) ? lMuuids[ idx-1 ] : NULL;
+}
+
+MIR_CORE_DLL(int) Langpack_MarkPluginLoaded(PLUGININFOEX* pInfo)
+{
+ int idx = lMuuids.getIndex(&pInfo->uuid);
+ if (idx == -1)
+ return 0;
+
+ return (idx+1) << 16;
+}
+
+MIR_CORE_DLL(void) Langpack_SortDuplicates(void)
+{
+ if (langPack.entryCount == 0)
+ return;
+
+ LangPackEntry *s = langPack.entry+1, *d = s, *pLast = langPack.entry;
+ DWORD dwSavedHash = langPack.entry->englishHash;
+ bool bSortNeeded = false;
+
+ for (int i=1; i < langPack.entryCount; i++, s++) {
+ if (s->englishHash != dwSavedHash) {
+ pLast = d;
+ if (s != d)
+ *d++ = *s;
+ else
+ d++;
+ dwSavedHash = s->englishHash;
+ }
+ else {
+ bSortNeeded = true;
+ LangPackEntry* p = (LangPackEntry*)mir_alloc(sizeof(LangPackEntry));
+ *p = *s;
+ pLast->pNext = p; pLast = p;
+ }
+ }
+
+ if (bSortNeeded) {
+ langPack.entryCount = (int)(d - langPack.entry);
+ qsort(langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*, const void*))SortLangPackHashesProc);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(int) LoadLangPackModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ ZeroMemory(&langPack, sizeof(langPack));
+
+ TCHAR szSearch[MAX_PATH];
+ PathToAbsoluteT(_T("langpack_*.txt"), szSearch, NULL);
+
+ WIN32_FIND_DATA fd;
+ HANDLE hFind = FindFirstFile(szSearch, &fd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ PathToAbsoluteT(fd.cFileName, szSearch, NULL);
+ FindClose(hFind);
+ LoadLangPack(szSearch);
+ }
+ return 0;
+}
+
+void UnloadLangPackModule()
+{
+ if ( !bModuleInitialized) return;
+
+ int i;
+ for (i=0; i < lMuuids.getCount(); i++)
+ mir_free(lMuuids[i]);
+ lMuuids.destroy();
+
+ LangPackEntry* p = langPack.entry;
+ for (i=0; i < langPack.entryCount; i++, p++) {
+ if (p->pNext != NULL) {
+ for (LangPackEntry* p1 = p->pNext; p1 != NULL;) {
+ LangPackEntry* p2 = p1; p1 = p1->pNext;
+ mir_free(p2->local);
+ mir_free(p2->wlocal);
+ mir_free(p2);
+ } }
+
+ mir_free(p->local);
+ mir_free(p->wlocal);
+ }
+
+ if (langPack.entryCount) {
+ mir_free(langPack.entry);
+ langPack.entry=0;
+ langPack.entryCount=0;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(void) ReloadLangpack(TCHAR *pszStr)
+{
+ if (pszStr == NULL)
+ pszStr = langPack.filename;
+
+ UnloadLangPackModule();
+ LoadLangPack(pszStr);
+ Langpack_SortDuplicates();
+}
diff --git a/src/mir_core/lists.cpp b/src/mir_core/lists.cpp
new file mode 100644
index 0000000000..e4996fc156
--- /dev/null
+++ b/src/mir_core/lists.cpp
@@ -0,0 +1,278 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+/* a simple sorted list implementation */
+
+MIR_CORE_DLL(SortedList*) List_Create(int p_limit, int p_increment)
+{
+ SortedList* result = (SortedList*)mir_calloc(sizeof(SortedList));
+ if (result == NULL)
+ return(NULL);
+
+ result->increment = p_increment;
+ result->limit = p_limit;
+ return(result);
+}
+
+MIR_CORE_DLL(void) List_Destroy(SortedList* p_list)
+{
+ if (p_list == NULL)
+ return;
+
+ if (p_list->items != NULL) {
+ mir_free(p_list->items);
+ p_list->items = NULL;
+ }
+
+ p_list->realCount = p_list->limit = 0;
+}
+
+MIR_CORE_DLL(void*) List_Find(SortedList* p_list, void* p_value)
+{
+ int index;
+
+ if ( !List_GetIndex(p_list, p_value, &index))
+ return(NULL);
+
+ return(p_list->items[ index ]);
+}
+
+#ifdef _DEBUG
+#pragma optimize("gt", on)
+#endif
+
+MIR_CORE_DLL(int) List_GetIndex(SortedList* p_list, void* p_value, int* p_index)
+{
+ if (p_value == NULL)
+ {
+ *p_index = -1;
+ return 0;
+ }
+
+ switch ((INT_PTR)p_list->sortFunc)
+ {
+ case 0:
+ break;
+
+ case HandleKeySort:
+#ifdef _WIN64
+ {
+ const unsigned __int64 val = *(unsigned __int64 *)p_value;
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ unsigned __int64 vali = *(unsigned __int64 *)p_list->items[i];
+ if (vali == val)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < val)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+#endif
+
+ case NumericKeySort:
+ {
+ const unsigned val = *(unsigned *)p_value;
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ unsigned vali = *(unsigned *)p_list->items[i];
+ if (vali == val)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < val)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+
+ case PtrKeySort:
+ {
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ const void* vali = p_list->items[i];
+ if (vali == p_value)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < p_value)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+
+ default:
+ {
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ int result = p_list->sortFunc(p_list->items[i], p_value);
+ if (result == 0)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (result < 0)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+MIR_CORE_DLL(int) List_IndexOf(SortedList* p_list, void* p_value)
+{
+ if (p_value == NULL)
+ return -1;
+
+ int i;
+ for (i=0; i < p_list->realCount; i++)
+ if (p_list->items[i] == p_value)
+ return i;
+
+ return -1;
+}
+
+#ifdef _DEBUG
+#pragma optimize("", on)
+#endif
+
+MIR_CORE_DLL(int) List_Insert(SortedList* p_list, void* p_value, int p_index)
+{
+ if (p_value == NULL || p_index > p_list->realCount)
+ return 0;
+
+ if (p_list->realCount == p_list->limit)
+ {
+ p_list->items = (void**)mir_realloc(p_list->items, sizeof(void*)*(p_list->realCount + p_list->increment));
+ p_list->limit += p_list->increment;
+ }
+
+ if (p_index < p_list->realCount)
+ memmove(p_list->items+p_index+1, p_list->items+p_index, sizeof(void*)*(p_list->realCount-p_index));
+
+ p_list->realCount++;
+
+ p_list->items[ p_index ] = p_value;
+ return 1;
+}
+
+MIR_CORE_DLL(int) List_InsertPtr(SortedList* list, void* p)
+{
+ if (p == NULL)
+ return -1;
+
+ int idx = list->realCount;
+ List_GetIndex(list, p, &idx);
+ return List_Insert(list, p, idx);
+}
+
+MIR_CORE_DLL(int) List_Remove(SortedList* p_list, int index)
+{
+ if (index < 0 || index > p_list->realCount)
+ return(0);
+
+ p_list->realCount--;
+ if (p_list->realCount > index)
+ {
+ memmove(p_list->items+index, p_list->items+index+1, sizeof(void*)*(p_list->realCount-index));
+ p_list->items[ p_list->realCount ] = NULL;
+ }
+
+ return 1;
+}
+
+MIR_CORE_DLL(int) List_RemovePtr(SortedList* list, void* p)
+{
+ int idx = -1;
+ if (List_GetIndex(list, p, &idx))
+ List_Remove(list, idx);
+
+ return idx;
+}
+
+MIR_CORE_DLL(void) List_Copy(SortedList* s, SortedList* d, size_t itemSize)
+{
+ d->increment = s->increment;
+ d->limit = s->limit;
+ d->realCount = s->realCount;
+ d->items = (void**)mir_alloc( sizeof(void*) * d->realCount);
+ memcpy(d->items, s->items, sizeof(void*) * d->realCount);
+}
+
+MIR_CORE_DLL(void) List_ObjCopy(SortedList* s, SortedList* d, size_t itemSize)
+{
+ int i;
+
+ d->increment = s->increment;
+ d->sortFunc = s->sortFunc;
+
+ for (i = 0; i < s->realCount; i++) {
+ void* item = new char[ itemSize ];
+ memcpy(item, s->items[i], itemSize);
+ List_Insert(d, item, i);
+} }
diff --git a/src/mir_core/md5.cpp b/src/mir_core/md5.cpp
new file mode 100644
index 0000000000..a7d7a641e3
--- /dev/null
+++ b/src/mir_core/md5.cpp
@@ -0,0 +1,358 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+// (C) 2005 Joe @ Whale - changed to compile with Miranda
+
+#include "commonheaders.h"
+
+#define T_MASK ((mir_md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+//gfd*
+static void md5_process(mir_md5_state_t *pms, const mir_md5_byte_t *data /*[64]*/)
+{
+ mir_md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ mir_md5_word_t t;
+ /* Define storage for little-endian or both types of CPUs. */
+ mir_md5_word_t xbuf[16];
+ const mir_md5_word_t *X;
+
+ {
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const mir_md5_byte_t *)&w)) /* dynamic little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if ( !((data - (const mir_md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const mir_md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+ else /* dynamic big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const mir_md5_byte_t *xp = data;
+ int i;
+
+ X = xbuf; /* (dynamic only) */
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b, c, d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET1(a, b, c, d, k, s, Ti)\
+ t = a + F(b, c, d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET1(a, b, c, d, 0, 7, T1);
+ SET1(d, a, b, c, 1, 12, T2);
+ SET1(c, d, a, b, 2, 17, T3);
+ SET1(b, c, d, a, 3, 22, T4);
+ SET1(a, b, c, d, 4, 7, T5);
+ SET1(d, a, b, c, 5, 12, T6);
+ SET1(c, d, a, b, 6, 17, T7);
+ SET1(b, c, d, a, 7, 22, T8);
+ SET1(a, b, c, d, 8, 7, T9);
+ SET1(d, a, b, c, 9, 12, T10);
+ SET1(c, d, a, b, 10, 17, T11);
+ SET1(b, c, d, a, 11, 22, T12);
+ SET1(a, b, c, d, 12, 7, T13);
+ SET1(d, a, b, c, 13, 12, T14);
+ SET1(c, d, a, b, 14, 17, T15);
+ SET1(b, c, d, a, 15, 22, T16);
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b, c, d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET2(a, b, c, d, k, s, Ti)\
+ t = a + G(b, c, d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET2(a, b, c, d, 1, 5, T17);
+ SET2(d, a, b, c, 6, 9, T18);
+ SET2(c, d, a, b, 11, 14, T19);
+ SET2(b, c, d, a, 0, 20, T20);
+ SET2(a, b, c, d, 5, 5, T21);
+ SET2(d, a, b, c, 10, 9, T22);
+ SET2(c, d, a, b, 15, 14, T23);
+ SET2(b, c, d, a, 4, 20, T24);
+ SET2(a, b, c, d, 9, 5, T25);
+ SET2(d, a, b, c, 14, 9, T26);
+ SET2(c, d, a, b, 3, 14, T27);
+ SET2(b, c, d, a, 8, 20, T28);
+ SET2(a, b, c, d, 13, 5, T29);
+ SET2(d, a, b, c, 2, 9, T30);
+ SET2(c, d, a, b, 7, 14, T31);
+ SET2(b, c, d, a, 12, 20, T32);
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b, c, d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET3(a, b, c, d, k, s, Ti)\
+ t = a + H(b, c, d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET3(a, b, c, d, 5, 4, T33);
+ SET3(d, a, b, c, 8, 11, T34);
+ SET3(c, d, a, b, 11, 16, T35);
+ SET3(b, c, d, a, 14, 23, T36);
+ SET3(a, b, c, d, 1, 4, T37);
+ SET3(d, a, b, c, 4, 11, T38);
+ SET3(c, d, a, b, 7, 16, T39);
+ SET3(b, c, d, a, 10, 23, T40);
+ SET3(a, b, c, d, 13, 4, T41);
+ SET3(d, a, b, c, 0, 11, T42);
+ SET3(c, d, a, b, 3, 16, T43);
+ SET3(b, c, d, a, 6, 23, T44);
+ SET3(a, b, c, d, 9, 4, T45);
+ SET3(d, a, b, c, 12, 11, T46);
+ SET3(c, d, a, b, 15, 16, T47);
+ SET3(b, c, d, a, 2, 23, T48);
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b, c, d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET4(a, b, c, d, k, s, Ti)\
+ t = a + I(b, c, d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET4(a, b, c, d, 0, 6, T49);
+ SET4(d, a, b, c, 7, 10, T50);
+ SET4(c, d, a, b, 14, 15, T51);
+ SET4(b, c, d, a, 5, 21, T52);
+ SET4(a, b, c, d, 12, 6, T53);
+ SET4(d, a, b, c, 3, 10, T54);
+ SET4(c, d, a, b, 10, 15, T55);
+ SET4(b, c, d, a, 1, 21, T56);
+ SET4(a, b, c, d, 8, 6, T57);
+ SET4(d, a, b, c, 15, 10, T58);
+ SET4(c, d, a, b, 6, 15, T59);
+ SET4(b, c, d, a, 13, 21, T60);
+ SET4(a, b, c, d, 4, 6, T61);
+ SET4(d, a, b, c, 11, 10, T62);
+ SET4(c, d, a, b, 2, 15, T63);
+ SET4(b, c, d, a, 9, 21, T64);
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+MIR_CORE_DLL(void) mir_md5_init(mir_md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+MIR_CORE_DLL(void) mir_md5_append(mir_md5_state_t *pms, const mir_md5_byte_t *data, int nbytes)
+{
+ const mir_md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ mir_md5_word_t nbits = (mir_md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+MIR_CORE_DLL(void) mir_md5_finish(mir_md5_state_t *pms, mir_md5_byte_t digest[16])
+{
+ static const mir_md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ mir_md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (mir_md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ mir_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ mir_md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (mir_md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+MIR_CORE_DLL(void) mir_md5_hash(const mir_md5_byte_t *data, int len, mir_md5_byte_t digest[16])
+{
+ mir_md5_state_t state;
+ mir_md5_init(&state);
+ mir_md5_append(&state, data, len);
+ mir_md5_finish(&state, digest);
+}
diff --git a/src/mir_core/memory.cpp b/src/mir_core/memory.cpp
new file mode 100644
index 0000000000..0ecddc6717
--- /dev/null
+++ b/src/mir_core/memory.cpp
@@ -0,0 +1,280 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+#define BLOCK_ALLOCED 0xABBABABA
+#define BLOCK_FREED 0xDEADBEEF
+
+static int CheckBlock(void* blk)
+{
+ int result = FALSE;
+ char* p = (char*)blk - sizeof(DWORD)*2;
+ DWORD size, *b, *e;
+
+ __try
+ {
+ size = *(DWORD*)p;
+ b = (DWORD*)&p[ sizeof(DWORD) ];
+ e = (DWORD*)&p[ sizeof(DWORD)*2 + size ];
+
+ if (*b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED)
+ {
+ if (*b == BLOCK_FREED && *e == BLOCK_FREED)
+ OutputDebugStringA("memory block is already deleted\n");
+ else
+ OutputDebugStringA("memory block is corrupted\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ }
+ else result = TRUE;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ OutputDebugStringA("access violation during checking memory block\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+MIR_C_CORE_DLL(void*) mir_alloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+ {
+ char* p = (char*)malloc(size + sizeof(DWORD)*3);
+ if (p == NULL) {
+ OutputDebugStringA("memory overflow\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *(DWORD*)p = (DWORD)size;
+ *(DWORD*)&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *(DWORD*)&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof(DWORD)*2;
+} }
+
+/******************************************************************************/
+
+MIR_C_CORE_DLL(void*) mir_calloc(size_t size)
+{
+ void* p = mir_alloc(size);
+ if (p != NULL)
+ memset(p, 0, size);
+ return p;
+}
+
+/******************************************************************************/
+
+MIR_C_CORE_DLL(void*) mir_realloc(void* ptr, size_t size)
+{
+ char* p;
+
+ if (ptr != NULL) {
+ if ( !CheckBlock(ptr))
+ return NULL;
+ p = (char*)ptr - sizeof(DWORD)*2;
+ }
+ else p = NULL;
+
+ p = (char*)realloc(p, size + sizeof(DWORD)*3);
+ if (p == NULL) {
+ OutputDebugStringA("memory overflow\n");
+ #if defined(_DEBUG)
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *(DWORD*)p = (DWORD)size;
+ *(DWORD*)&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *(DWORD*)&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof(DWORD)*2;
+}
+
+/******************************************************************************/
+
+MIR_C_CORE_DLL(void) mir_free(void* ptr)
+{
+ char* p;
+ DWORD size;
+
+ if (ptr == NULL)
+ return;
+ if ( !CheckBlock(ptr))
+ return;
+
+ p = (char*)ptr - sizeof(DWORD)*2;
+ size = *(DWORD*)p;
+ *(DWORD*)&p[ sizeof(DWORD) ] = BLOCK_FREED;
+ *(DWORD*)&p[ size + sizeof(DWORD)*2 ] = BLOCK_FREED;
+ free(p);
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_strdup(const char* str)
+{
+ if (str != NULL) {
+ char* p = (char*)mir_alloc(strlen(str)+1);
+ if (p)
+ strcpy(p, str);
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_strndup(const char* str, size_t len)
+{
+ if (str != NULL && len != 0) {
+ char* p = (char*)mir_alloc(len + 1);
+ if ( !p) {
+ memcpy(p, str, len);
+ p[ len ] = 0;
+ }
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(WCHAR*) mir_wstrdup(const WCHAR* str)
+{
+ if (str != NULL) {
+ WCHAR* p = (WCHAR*)mir_alloc(sizeof(WCHAR)*(wcslen(str)+1));
+ if (p)
+ wcscpy(p, str);
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_snprintf(char *buffer, size_t count, const char* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va)
+{
+ int len;
+
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(int) mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va)
+{
+ int len;
+
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage)
+{
+ if (src == NULL)
+ return NULL;
+
+ int cbLen = MultiByteToWideChar(codepage, 0, src, -1, NULL, 0);
+ wchar_t* result = (wchar_t*)mir_alloc(sizeof(wchar_t)*(cbLen+1));
+ if (result == NULL)
+ return NULL;
+
+ MultiByteToWideChar(codepage, 0, src, -1, result, cbLen);
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src)
+{
+ return mir_a2u_cp(src, Langpack_GetDefaultCodePage());
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage)
+{
+ if (src == NULL)
+ return NULL;
+
+ int cbLen = WideCharToMultiByte(codepage, 0, src, -1, NULL, 0, NULL, NULL);
+ char* result = (char*)mir_alloc(cbLen+1);
+ if (result == NULL)
+ return NULL;
+
+ WideCharToMultiByte(codepage, 0, src, -1, result, cbLen, NULL, NULL);
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src)
+{
+ return mir_u2a_cp(src, Langpack_GetDefaultCodePage());
+}
diff --git a/src/mir_core/mir_core.def b/src/mir_core/mir_core.def
new file mode 100644
index 0000000000..43dd94d7ac
--- /dev/null
+++ b/src/mir_core/mir_core.def
@@ -0,0 +1,126 @@
+LIBRARY mir_core
+
+EXPORTS
+CallContactService @1
+CallProtoService @2
+Langpack_LookupUuid @3
+Langpack_MarkPluginLoaded @4
+CallFunctionAsync @5
+CallPluginEventHook @7
+CallService @8
+CallServiceSync @9
+CreateDirectoryTree @10
+CreateDirectoryTreeW @11
+CreateHookableEvent @12
+CreatePathToFile @13
+CreatePathToFileW @14
+CreateServiceFunction @15
+CreateServiceFunctionObj @16
+CreateServiceFunctionObjParam @17
+CreateServiceFunctionParam @18
+DestroyHookableEvent @19
+DestroyServiceFunction @20
+GetExceptionFilter @21
+GetInstByAddress @22
+HookEvent @23
+HookEventMessage @24
+HookEventObj @25
+HookEventObjParam @26
+HookEventParam @27
+KillModuleEventHooks @28
+KillModuleServices @29
+KillObjectEventHooks @30
+KillObjectServices @31
+KillObjectThreads @32
+Langpack_SortDuplicates @33
+Langpack_GetDefaultCodePage @34
+Langpack_GetDefaultLocale @35
+Langpack_PcharToTchar @36
+List_Copy @37
+List_Create @38
+List_Destroy @39
+List_Find @40
+List_GetIndex @41
+List_IndexOf @42
+List_Insert @43
+List_InsertPtr @44
+List_ObjCopy @45
+List_Remove @46
+List_RemovePtr @47
+LoadLangPack @48
+LoadLangPackModule @49
+NotifyEventHooks @50
+PathToAbsolute @51
+PathToAbsoluteW @52
+PathToRelative @53
+PathToRelativeW @54
+RegisterModule @55
+ReloadLangpack @56
+ServiceExists @57
+SetExceptionFilter @58
+SetHookDefaultForHookableEvent @59
+Thread_Pop @60
+Thread_Push @61
+Thread_Wait @62
+TranslateA_LP @63
+TranslateDialog_LP @64
+TranslateMenu_LP @65
+TranslateW_LP @66
+Ucs2toUtf8Len @67
+UnhookEvent @68
+UnregisterModule @69
+Utf8Decode @70
+Utf8DecodeCP @71
+Utf8DecodeW @72
+Utf8Encode @73
+Utf8EncodeCP @74
+Utf8EncodeW @75
+forkthread @76
+forkthreadex @77
+ltrim @78
+ltrimp @79
+mir_a2u @80
+mir_a2u_cp @81
+mir_alloc @82
+mir_calloc @83
+mir_free @84
+mir_hash @85
+mir_md5_append @86
+mir_md5_finish @87
+mir_md5_hash @88
+mir_md5_init @89
+mir_realloc @90
+mir_sha1_append @91
+mir_sha1_finish @92
+mir_sha1_hash @93
+mir_sha1_init @94
+mir_strdup @95
+mir_strndup @96
+mir_u2a @97
+mir_u2a_cp @98
+mir_vsnprintf @99
+mir_vsntprintf @100
+mir_wstrdup @101
+rtrim @102
+wildcmp @103
+wrtrim @104
+mir_snprintf @105
+mir_sntprintf @106
+db_unset @107
+db_free @108
+db_get @109
+db_get_b @110
+db_get_dw @111
+db_get_s @112
+db_get_sa @113
+db_get_w @114
+db_get_wsa @115
+db_set_b @116
+db_set_blob @117
+db_set_dw @118
+db_set_s @119
+db_set_utf @120
+db_set_w @121
+db_set_ws @122
+UnloadCoreModule @123
+Thread_SetName @124
diff --git a/src/mir_core/mir_core_10.vcxproj b/src/mir_core/mir_core_10.vcxproj
new file mode 100644
index 0000000000..e5f452eb61
--- /dev/null
+++ b/src/mir_core/mir_core_10.vcxproj
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\..\include\m_core.h" />
+ <ClInclude Include="..\..\include\m_database.h" />
+ <ClInclude Include="..\..\include\m_system.h" />
+ <ClInclude Include="commonheaders.h" />
+ <ClInclude Include="forkthread.h" />
+ <ClInclude Include="miranda.h" />
+ <ClInclude Include="modules.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="commonheaders.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="db.cpp" />
+ <ClCompile Include="langpack.cpp" />
+ <ClCompile Include="lists.cpp" />
+ <ClCompile Include="md5.cpp" />
+ <ClCompile Include="memory.cpp" />
+ <ClCompile Include="miranda.cpp" />
+ <ClCompile Include="modules.cpp" />
+ <ClCompile Include="path.cpp" />
+ <ClCompile Include="sha1.cpp" />
+ <ClCompile Include="threads.cpp" />
+ <ClCompile Include="utf.cpp" />
+ <ClCompile Include="utils.cpp" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>mir_core</ProjectName>
+ <ProjectGuid>{D9EFEA4B-B817-4DE1-BD62-68A5DB8F5F60}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>mir_core.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda32.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>
+ </Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>mir_core.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName)64.lib</ImportLibrary>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ <AdditionalOptions>/ignore:4197 %(AdditionalOptions)</AdditionalOptions>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>mir_core.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda32.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>
+ </Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;MIR_CORE_EXPORTS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include\msapi</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <ModuleDefinitionFile>mir_core.def</ModuleDefinitionFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName)64.lib</ImportLibrary>
+ <SubSystem>Windows</SubSystem>
+ <AdditionalDependencies>miranda64.lib;ws2_32.lib;comctl32.lib;winmm.lib;version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalLibraryDirectories>$(SolutionDir)\lib</AdditionalLibraryDirectories>
+ <AdditionalOptions>/ignore:4197 %(AdditionalOptions)</AdditionalOptions>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/mir_core/mir_core_10.vcxproj.filters b/src/mir_core/mir_core_10.vcxproj.filters
new file mode 100644
index 0000000000..27b6a42604
--- /dev/null
+++ b/src/mir_core/mir_core_10.vcxproj.filters
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{bf74d1c9-acd8-4fba-837d-734f024521c9}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{a578a180-0eb9-4c3e-b4ae-0eaefa01d207}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="commonheaders.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="memory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="miranda.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="modules.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lists.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="langpack.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utf.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="utils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="path.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="md5.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sha1.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="db.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="threads.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="commonheaders.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="modules.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="forkthread.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\m_core.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="miranda.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\m_system.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\include\m_database.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/mir_core/miranda.cpp b/src/mir_core/miranda.cpp
new file mode 100644
index 0000000000..b059e11cb7
--- /dev/null
+++ b/src/mir_core/miranda.cpp
@@ -0,0 +1,97 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "commonheaders.h"
+
+HWND hAPCWindow = NULL;
+
+int InitPathUtils(void);
+void (*RecalculateTime)(void);
+
+int hLangpack = 0;
+HINSTANCE hInst = 0;
+
+HANDLE hStackMutex, hThreadQueueEmpty;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// module init
+
+static LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_NULL) SleepEx(0, TRUE);
+ if (msg == WM_TIMECHANGE && RecalculateTime)
+ RecalculateTime();
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+static void LoadCoreModule(void)
+{
+ INITCOMMONCONTROLSEX icce = {0};
+ icce.dwSize = sizeof(icce);
+ icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES;
+ InitCommonControlsEx(&icce);
+
+ if ( IsWinVerXPPlus()) {
+ hAPCWindow=CreateWindowEx(0, _T("ComboLBox"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW);
+ DestroyWindow(hAPCWindow);
+ hAPCWindow = NULL;
+ }
+
+ hAPCWindow = CreateWindowEx(0, _T("STATIC"), NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ SetWindowLongPtr(hAPCWindow, GWLP_WNDPROC, (LONG_PTR)APCWndProc);
+ hStackMutex = CreateMutex(NULL, FALSE, NULL);
+ hThreadQueueEmpty = CreateEvent(NULL, TRUE, TRUE, NULL);
+
+ #ifdef WIN64
+ HMODULE mirInst = GetModuleHandleA("miranda64.exe");
+ #else
+ HMODULE mirInst = GetModuleHandleA("miranda32.exe");
+ #endif
+ RecalculateTime = (void (*)()) GetProcAddress(mirInst, "RecalculateTime");
+
+ InitPathUtils();
+ InitialiseModularEngine();
+}
+
+MIR_CORE_DLL(void) UnloadCoreModule(void)
+{
+ DestroyWindow(hAPCWindow);
+ CloseHandle(hStackMutex);
+
+ DestroyModularEngine();
+ UnloadLangPackModule();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// entry point
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ if (fdwReason == DLL_PROCESS_ATTACH) {
+ hInst = hinstDLL;
+ LoadCoreModule();
+ }
+ return TRUE;
+}
diff --git a/src/mir_core/miranda.h b/src/mir_core/miranda.h
new file mode 100644
index 0000000000..af71276ac4
--- /dev/null
+++ b/src/mir_core/miranda.h
@@ -0,0 +1,131 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#define NEWSTR_ALLOCA(A) (A == NULL)?NULL:strcpy((char*)alloca(strlen(A)+1), A)
+#define NEWTSTR_ALLOCA(A) (A == NULL)?NULL:_tcscpy((TCHAR*)alloca((_tcslen(A)+1)* sizeof(TCHAR)), A)
+
+extern "C"
+{
+ MIR_CORE_DLL(int) Langpack_MarkPluginLoaded(PLUGININFOEX* pInfo);
+};
+
+MIR_CORE_DLL(MUUID*) Langpack_LookupUuid(WPARAM wParam);
+
+void UnloadLangPackModule(void);
+
+int InitialiseModularEngine(void);
+void DestroyModularEngine(void);
+
+int InitPathUtils(void);
+
+extern HINSTANCE hInst;
+extern HWND hAPCWindow;
+extern HANDLE hStackMutex, hThreadQueueEmpty;
+
+/**** modules.cpp **********************************************************************/
+
+struct THookSubscriber
+{
+ HINSTANCE hOwner;
+ int type;
+ union {
+ struct {
+ union {
+ MIRANDAHOOK pfnHook;
+ MIRANDAHOOKPARAM pfnHookParam;
+ MIRANDAHOOKOBJ pfnHookObj;
+ MIRANDAHOOKOBJPARAM pfnHookObjParam;
+ };
+ void* object;
+ LPARAM lParam;
+ };
+ struct {
+ HWND hwnd;
+ UINT message;
+ };
+ };
+};
+
+#define HOOK_SECRET_SIGNATURE 0xDEADBABA
+
+struct THook
+{
+ char name[ MAXMODULELABELLENGTH ];
+ int id;
+ int subscriberCount;
+ THookSubscriber* subscriber;
+ MIRANDAHOOK pfnHook;
+ DWORD secretSignature;
+ CRITICAL_SECTION csHook;
+};
+
+extern LIST<HINSTANCE__> pluginListAddr;
+
+/**** langpack.cpp *********************************************************************/
+
+char* LangPackTranslateString(MUUID* pUuid, const char *szEnglish, const int W);
+TCHAR* LangPackTranslateStringT(int hLangpack, const TCHAR* tszEnglish);
+
+/**** options.cpp **********************************************************************/
+
+HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name);
+
+/**** utils.cpp ************************************************************************/
+
+void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key);
+WORD GetHotkeyValue(INT_PTR idHotkey);
+
+HBITMAP ConvertIconToBitmap(HICON hIcon, HIMAGELIST hIml, int iconId);
+
+class StrConvUT
+{
+private:
+ wchar_t* m_body;
+
+public:
+ StrConvUT(const char* pSrc) :
+ m_body(mir_a2u(pSrc)) {}
+
+ ~StrConvUT() { mir_free(m_body); }
+ operator const wchar_t* () const { return m_body; }
+};
+
+class StrConvAT
+{
+private:
+ char* m_body;
+
+public:
+ StrConvAT(const wchar_t* pSrc) :
+ m_body(mir_u2a(pSrc)) {}
+
+ ~StrConvAT() { mir_free(m_body); }
+ operator const char* () const { return m_body; }
+ operator const wchar_t* () const { return (wchar_t*)m_body; } // type cast to fake the interface definition
+ operator const LPARAM () const { return (LPARAM)m_body; }
+};
+
+#define StrConvT(x) StrConvUT(x)
+#define StrConvTu(x) x
+#define StrConvA(x) StrConvAT(x)
+#define StrConvU(x) x
diff --git a/src/mir_core/modules.cpp b/src/mir_core/modules.cpp
new file mode 100644
index 0000000000..f87c7bb192
--- /dev/null
+++ b/src/mir_core/modules.cpp
@@ -0,0 +1,601 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+#include <m_plugins.h>
+
+// list of hooks
+
+static int compareHooks(const THook* p1, const THook* p2)
+{
+ return strcmp(p1->name, p2->name);
+}
+
+static LIST<THook> hooks(50, compareHooks);
+
+struct THookToMainThreadItem
+{
+ THook* hook;
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+};
+
+// list of services
+
+struct TService
+{
+ DWORD nameHash;
+ HINSTANCE hOwner;
+ union {
+ MIRANDASERVICE pfnService;
+ MIRANDASERVICEPARAM pfnServiceParam;
+ MIRANDASERVICEOBJ pfnServiceObj;
+ MIRANDASERVICEOBJPARAM pfnServiceObjParam;
+ };
+ int flags;
+ LPARAM lParam;
+ void* object;
+ char name[1];
+};
+
+LIST<TService> services(100, NumericKeySortT);
+
+typedef struct
+{
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+ const char *name;
+}
+ TServiceToMainThreadItem;
+
+// other static variables
+static BOOL bServiceMode = FALSE;
+static CRITICAL_SECTION csHooks, csServices;
+static DWORD mainThreadId;
+static int hookId = 1;
+static HANDLE hMainThread;
+static HANDLE hMissingService;
+static THook *pLastHook = NULL;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int QueueMainThread(PAPCFUNC pFunc, void* pParam, HANDLE hDoneEvent)
+{
+ int result = QueueUserAPC(pFunc, hMainThread, (ULONG_PTR)pParam);
+ PostMessage(hAPCWindow, WM_NULL, 0, 0); // let this get processed in its own time
+ if (hDoneEvent) {
+ WaitForSingleObject(hDoneEvent, INFINITE);
+ CloseHandle(hDoneEvent);
+ }
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// HOOKS
+
+MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name)
+{
+ if (name == NULL)
+ return NULL;
+
+ mir_cslock lck(csHooks);
+
+ int idx;
+ if ((idx = hooks.getIndex((THook*)name)) != -1)
+ return hooks[idx];
+
+ THook* newItem = (THook*)mir_alloc(sizeof(THook));
+ strncpy(newItem->name, name, sizeof(newItem->name)); newItem->name[ MAXMODULELABELLENGTH-1 ] = 0;
+ newItem->id = hookId++;
+ newItem->subscriberCount = 0;
+ newItem->subscriber = NULL;
+ newItem->pfnHook = NULL;
+ newItem->secretSignature = HOOK_SECRET_SIGNATURE;
+ InitializeCriticalSection(&newItem->csHook);
+ hooks.insert(newItem);
+ return (HANDLE)newItem;
+}
+
+MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent)
+{
+ if (pLastHook == (THook*)hEvent)
+ pLastHook = NULL;
+
+ mir_cslock lck(csHooks);
+
+ int idx;
+ if ((idx = hooks.getIndex((THook*)hEvent)) == -1)
+ return 1;
+
+ THook* p = hooks[idx];
+ p->secretSignature = 0;
+ if (p->subscriberCount) {
+ mir_free(p->subscriber);
+ p->subscriber = NULL;
+ p->subscriberCount = 0;
+ }
+ hooks.remove(idx);
+ DeleteCriticalSection(&p->csHook);
+ mir_free(p);
+ return 0;
+}
+
+MIR_CORE_DLL(int) SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook)
+{
+ THook* p = (THook*)hEvent;
+
+ mir_cslock lck(csHooks);
+ if (hooks.getIndex(p) != -1)
+ p->pfnHook = pfnHook;
+ return 0;
+}
+
+MIR_CORE_DLL(int) CallPluginEventHook(HINSTANCE hInst, HANDLE hEvent, WPARAM wParam, LPARAM lParam)
+{
+ THook* p = (THook*)hEvent;
+ if (p == NULL)
+ return -1;
+
+ mir_cslock lck(p->csHook);
+ for (int i = 0; i < p->subscriberCount; i++) {
+ THookSubscriber* s = &p->subscriber[i];
+ if (s->hOwner != hInst)
+ continue;
+
+ int returnVal;
+ switch (s->type) {
+ case 1: returnVal = s->pfnHook(wParam, lParam); break;
+ case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break;
+ case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break;
+ case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break;
+ case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break;
+ default: continue;
+ }
+ if (returnVal)
+ return returnVal;
+ }
+
+ if (p->subscriberCount == 0 && p->pfnHook != 0)
+ return p->pfnHook(wParam, lParam);
+
+ return 0;
+}
+
+static int CallHookSubscribers(THook* p, WPARAM wParam, LPARAM lParam)
+{
+ if (p == NULL)
+ return -1;
+
+ mir_cslock lck(p->csHook);
+
+ // NOTE: We've got the critical section while all this lot are called. That's mostly safe, though.
+ for (int i = 0; i < p->subscriberCount; i++) {
+ THookSubscriber* s = &p->subscriber[i];
+
+ int returnVal;
+ switch (s->type) {
+ case 1: returnVal = s->pfnHook(wParam, lParam); break;
+ case 2: returnVal = s->pfnHookParam(wParam, lParam, s->lParam); break;
+ case 3: returnVal = s->pfnHookObj(s->object, wParam, lParam); break;
+ case 4: returnVal = s->pfnHookObjParam(s->object, wParam, lParam, s->lParam); break;
+ case 5: returnVal = SendMessage(s->hwnd, s->message, wParam, lParam); break;
+ default: continue;
+ }
+ if (returnVal)
+ return returnVal;
+ }
+
+ // call the default hook if any
+ if (p->pfnHook != 0)
+ return p->pfnHook(wParam, lParam);
+
+ return 0;
+}
+
+enum { hookOk, hookEmpty, hookInvalid };
+
+__forceinline int checkHook(THook* p)
+{
+ if (p == NULL)
+ return hookInvalid;
+
+ int ret;
+ __try
+ {
+ if (p->secretSignature != HOOK_SECRET_SIGNATURE)
+ ret = hookInvalid;
+ else if (p->subscriberCount == 0 && p->pfnHook == NULL)
+ ret = hookEmpty;
+ else
+ ret = hookOk;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ret = hookInvalid;
+ }
+
+ return ret;
+}
+
+static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam)
+{
+ THookToMainThreadItem* item = (THookToMainThreadItem*)dwParam;
+ item->result = CallHookSubscribers(item->hook, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam, LPARAM lParam)
+{
+ switch ( checkHook((THook*)hEvent)) {
+ case hookInvalid: return -1;
+ case hookEmpty: return 0;
+ }
+
+ if ( GetCurrentThreadId() == mainThreadId)
+ return CallHookSubscribers((THook*)hEvent, wParam, lParam);
+
+ mir_ptr<THookToMainThreadItem> item;
+ item->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ item->hook = (THook*)hEvent;
+ item->wParam = wParam;
+ item->lParam = lParam;
+ QueueMainThread(HookToMainAPCFunc, item, item->hDoneEvent);
+ return item->result;
+}
+
+static HANDLE HookEventInt(int type, const char* name, MIRANDAHOOK hookProc, void* object, LPARAM lParam)
+{
+ mir_cslock lck(csHooks);
+
+ int idx;
+ if ((idx = hooks.getIndex((THook*)name)) == -1)
+ return NULL;
+
+ THook* p = hooks[ idx ];
+ p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1));
+ p->subscriber[ p->subscriberCount ].type = type;
+ p->subscriber[ p->subscriberCount ].pfnHook = hookProc;
+ p->subscriber[ p->subscriberCount ].object = object;
+ p->subscriber[ p->subscriberCount ].lParam = lParam;
+ p->subscriber[ p->subscriberCount ].hOwner = GetInstByAddress(hookProc);
+ p->subscriberCount++;
+
+ return (HANDLE)((p->id << 16) | p->subscriberCount);
+}
+
+MIR_CORE_DLL(HANDLE) HookEvent(const char* name, MIRANDAHOOK hookProc)
+{
+ return HookEventInt(1, name, hookProc, 0, 0);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventParam(const char* name, MIRANDAHOOKPARAM hookProc, LPARAM lParam)
+{
+ return HookEventInt(2, name, (MIRANDAHOOK)hookProc, 0, lParam);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventObj(const char* name, MIRANDAHOOKOBJ hookProc, void* object)
+{
+ return HookEventInt(3, name, (MIRANDAHOOK)hookProc, object, 0);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventObjParam(const char* name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam)
+{
+ return HookEventInt(4, name, (MIRANDAHOOK)hookProc, object, lParam);
+}
+
+MIR_CORE_DLL(HANDLE) HookEventMessage(const char* name, HWND hwnd, UINT message)
+{
+ mir_cslock lck(csHooks);
+
+ int idx;
+ if ((idx = hooks.getIndex((THook*)name)) == -1)
+ return NULL;
+
+ THook* p = hooks[ idx ];
+ p->subscriber = (THookSubscriber*)mir_realloc(p->subscriber, sizeof(THookSubscriber)*(p->subscriberCount+1));
+ p->subscriber[ p->subscriberCount ].type = 5;
+ p->subscriber[ p->subscriberCount ].hwnd = hwnd;
+ p->subscriber[ p->subscriberCount ].message = message;
+ p->subscriberCount++;
+ return (HANDLE)((p->id << 16) | p->subscriberCount);
+}
+
+MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook)
+{
+ if (hHook == NULL)
+ return 0;
+
+ int hookId = (int)hHook >> 16;
+ int subscriberId = ((int)hHook & 0xFFFF) - 1;
+
+ mir_cslock lck(csHooks);
+
+ THook* p = NULL;
+ for (int i = 0; i < hooks.getCount(); i++)
+ if (hooks[i]->id == hookId) {
+ p = hooks[i];
+ break;
+ }
+
+ if (p == NULL)
+ return 1;
+
+ if (subscriberId >= p->subscriberCount || subscriberId < 0)
+ return 1;
+
+ p->subscriber[subscriberId].type = 0;
+ p->subscriber[subscriberId].pfnHook = NULL;
+ p->subscriber[subscriberId].hOwner = NULL;
+ while (p->subscriberCount && p->subscriber[p->subscriberCount-1].type == 0)
+ p->subscriberCount--;
+ if (p->subscriberCount == 0) {
+ if (p->subscriber) mir_free(p->subscriber);
+ p->subscriber = NULL;
+ }
+ return 0;
+}
+
+MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE hInst)
+{
+ mir_cslock lck(csHooks);
+
+ for (int i = hooks.getCount()-1; i >= 0; i--) {
+ if (hooks[i]->subscriberCount == 0)
+ continue;
+
+ for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) {
+ if (hooks[i]->subscriber[j].hOwner != hInst)
+ continue;
+
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
+ UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1));
+ if (hooks[i]->subscriberCount == 0)
+ break;
+ }
+ }
+}
+
+MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject)
+{
+ mir_cslock lck(csHooks);
+
+ for (int i = hooks.getCount()-1; i >= 0; i--) {
+ if (hooks[i]->subscriberCount == 0)
+ continue;
+
+ for (int j = hooks[i]->subscriberCount-1; j >= 0; j--) {
+ if (hooks[i]->subscriber[j].object == pObject) {
+ UnhookEvent((HANDLE)((hooks[i]->id << 16) + j + 1));
+ if (hooks[i]->subscriberCount == 0)
+ break;
+ }
+ }
+ }
+}
+
+static void DestroyHooks()
+{
+ mir_cslock lck(csHooks);
+
+ for (int i=0; i < hooks.getCount(); i++) {
+ THook* p = hooks[i];
+ if (p->subscriberCount)
+ mir_free(p->subscriber);
+ DeleteCriticalSection(&p->csHook);
+ mir_free(p);
+ }
+}
+
+/////////////////////SERVICES
+
+static __inline TService* FindServiceByName(const char *name)
+{
+ unsigned hash = mir_hashstr(name);
+ return services.find((TService*)&hash);
+}
+
+static HANDLE CreateServiceInt(int type, const char *name, MIRANDASERVICE serviceProc, void* object, LPARAM lParam)
+{
+ if (name == NULL)
+ return NULL;
+
+ TService tmp;
+ tmp.nameHash = mir_hashstr(name);
+
+ mir_cslock lck(csServices);
+
+ if (services.getIndex(&tmp) != -1)
+ return NULL;
+
+ TService* p = (TService*)mir_alloc(sizeof(*p) + strlen(name));
+ strcpy(p->name, name);
+ p->nameHash = tmp.nameHash;
+ p->pfnService = serviceProc;
+ p->hOwner = GetInstByAddress(serviceProc);
+ p->flags = type;
+ p->lParam = lParam;
+ p->object = object;
+ services.insert(p);
+
+ return (HANDLE)tmp.nameHash;
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunction(const char *name, MIRANDASERVICE serviceProc)
+{
+ return CreateServiceInt(0, name, serviceProc, 0, 0);
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunctionParam(const char *name, MIRANDASERVICEPARAM serviceProc, LPARAM lParam)
+{
+ return CreateServiceInt(1, name, (MIRANDASERVICE)serviceProc, 0, lParam);
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunctionObj(const char *name, MIRANDASERVICEOBJ serviceProc, void* object)
+{
+ return CreateServiceInt(2, name, (MIRANDASERVICE)serviceProc, object, 0);
+}
+
+MIR_CORE_DLL(HANDLE) CreateServiceFunctionObjParam(const char *name, MIRANDASERVICEOBJPARAM serviceProc, void* object, LPARAM lParam)
+{
+ return CreateServiceInt(3, name, (MIRANDASERVICE)serviceProc, object, lParam);
+}
+
+MIR_CORE_DLL(int) DestroyServiceFunction(HANDLE hService)
+{
+ mir_cslock lck(csServices);
+
+ int idx;
+ if ((idx = services.getIndex((TService*)&hService)) != -1) {
+ mir_free(services[idx]);
+ services.remove(idx);
+ }
+
+ return 0;
+}
+
+MIR_CORE_DLL(int) ServiceExists(const char *name)
+{
+ if (name == NULL)
+ return FALSE;
+
+ mir_cslock lck(csServices);
+ return FindServiceByName(name) != NULL;
+}
+
+MIR_CORE_DLL(INT_PTR) CallService(const char *name, WPARAM wParam, LPARAM lParam)
+{
+ if (name == NULL)
+ return CALLSERVICE_NOTFOUND;
+
+ TService *pService;
+ {
+ mir_cslock lck(csServices);
+ if ((pService = FindServiceByName(name)) == NULL)
+ return CALLSERVICE_NOTFOUND;
+ }
+
+ MIRANDASERVICE pfnService = pService->pfnService;
+ int flags = pService->flags;
+ LPARAM fnParam = pService->lParam;
+ void* object = pService->object;
+ switch(flags) {
+ case 1: return ((MIRANDASERVICEPARAM)pfnService)(wParam, lParam, fnParam);
+ case 2: return ((MIRANDASERVICEOBJ)pfnService)(object, wParam, lParam);
+ case 3: return ((MIRANDASERVICEOBJPARAM)pfnService)(object, wParam, lParam, fnParam);
+ default: return pfnService(wParam, lParam);
+} }
+
+static void CALLBACK CallServiceToMainAPCFunc(ULONG_PTR dwParam)
+{
+ TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam;
+ item->result = CallService(item->name, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+MIR_CORE_DLL(INT_PTR) CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam)
+{
+ if (name == NULL)
+ return CALLSERVICE_NOTFOUND;
+
+ // the service is looked up within the main thread, since the time it takes
+ // for the APC queue to clear the service being called maybe removed.
+ // even thou it may exists before the call, the critsec can't be locked between calls.
+ if (GetCurrentThreadId() == mainThreadId)
+ return CallService(name, wParam, lParam);
+
+ mir_ptr<TServiceToMainThreadItem> item;
+ item->wParam = wParam;
+ item->lParam = lParam;
+ item->name = name;
+ item->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueMainThread(CallServiceToMainAPCFunc, item, item->hDoneEvent);
+ return item->result;
+}
+
+MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg)
+{
+ QueueMainThread((PAPCFUNC)func, arg, 0);
+ return 0;
+}
+
+MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst)
+{
+ mir_cslock lck(csServices);
+
+ for (int i = services.getCount()-1; i >= 0; i--) {
+ if (services[i]->hOwner == hInst) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(services[i]->hOwner, szModuleName, sizeof(szModuleName));
+ DestroyServiceFunction((HANDLE)services[i]->nameHash);
+ }
+ }
+}
+
+MIR_CORE_DLL(void) KillObjectServices(void* pObject)
+{
+ mir_cslock lck(csServices);
+
+ for (int i = services.getCount()-1; i >= 0; i--)
+ if (services[i]->object == pObject)
+ DestroyServiceFunction((HANDLE)services[i]->nameHash);
+}
+
+static void DestroyServices()
+{
+ mir_cslock lck(csServices);
+
+ for (int j=0; j < services.getCount(); j++)
+ mir_free(services[j]);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int InitialiseModularEngine(void)
+{
+ InitializeCriticalSection(&csHooks);
+ InitializeCriticalSection(&csServices);
+
+ mainThreadId = GetCurrentThreadId();
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+
+ hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE);
+ return 0;
+}
+
+void DestroyModularEngine(void)
+{
+ DestroyHooks();
+ hooks.destroy();
+ DeleteCriticalSection(&csHooks);
+
+ DestroyServices();
+ services.destroy();
+ DeleteCriticalSection(&csServices);
+
+ CloseHandle(hMainThread);
+}
diff --git a/src/mir_core/path.cpp b/src/mir_core/path.cpp
new file mode 100644
index 0000000000..fada3dcd18
--- /dev/null
+++ b/src/mir_core/path.cpp
@@ -0,0 +1,210 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "commonheaders.h"
+
+static char szMirandaPath[MAX_PATH];
+static char szMirandaPathLower[MAX_PATH];
+static TCHAR szMirandaPathW[MAX_PATH];
+static TCHAR szMirandaPathWLower[MAX_PATH];
+
+static int pathIsAbsolute(const char *path)
+{
+ if (strlen(path) <= 2)
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+MIR_CORE_DLL(int) PathToRelative(const char *pSrc, char *pOut)
+{
+ if ( !pSrc || !strlen(pSrc) || strlen(pSrc)>MAX_PATH) return 0;
+ if ( !pathIsAbsolute(pSrc)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return (int)strlen(pOut);
+ }
+
+ char szTmp[MAX_PATH];
+ mir_snprintf(szTmp, SIZEOF(szTmp), "%s", pSrc);
+ _strlwr(szTmp);
+ if (strstr(szTmp, szMirandaPathLower)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc+strlen(szMirandaPathLower));
+ return (int)strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return (int)strlen(pOut);
+ }
+}
+
+MIR_CORE_DLL(int) PathToAbsolute(const char *pSrc, char *pOut, char* base)
+{
+ if ( !pSrc || !strlen(pSrc) || strlen(pSrc) > MAX_PATH)
+ return 0;
+
+ if (base == NULL)
+ base = szMirandaPath;
+
+ char buf[MAX_PATH];
+ if (pSrc[0] < ' ')
+ return mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ else if (pathIsAbsolute(pSrc))
+ return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL);
+ else if (pSrc[0] != '\\')
+ mir_snprintf(buf, MAX_PATH, "%s%s", base, pSrc);
+ else
+ mir_snprintf(buf, MAX_PATH, "%s%s", base, pSrc+1);
+
+ return GetFullPathNameA(buf, MAX_PATH, pOut, NULL);
+}
+
+MIR_CORE_DLL(void) CreatePathToFile(char* szFilePath)
+{
+ char* pszLastBackslash = strrchr(szFilePath, '\\');
+ if (pszLastBackslash == NULL)
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree(szFilePath);
+ *pszLastBackslash = '\\';
+}
+
+MIR_CORE_DLL(int) CreateDirectoryTree(const char *szDir)
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynA(szTestDir, szDir, SIZEOF(szTestDir));
+ if ((dwAttributes = GetFileAttributesA(szTestDir)) != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ return 0;
+
+ pszLastBackslash = strrchr(szTestDir, '\\');
+ if (pszLastBackslash == NULL)
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree(szTestDir);
+ *pszLastBackslash = '\\';
+ return (CreateDirectoryA(szTestDir, NULL) == 0) ? GetLastError() : 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int pathIsAbsoluteW(const TCHAR *path)
+{
+ if (lstrlen(path) <= 2)
+ return 0;
+ if ((path[1] == ':' && path[2] == '\\') || (path[0] == '\\' && path[1] == '\\'))
+ return 1;
+ return 0;
+}
+
+MIR_CORE_DLL(int) PathToRelativeW(const WCHAR *pSrc, WCHAR *pOut)
+{
+ if ( !pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH)
+ return 0;
+
+ if ( !pathIsAbsoluteW(pSrc))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else {
+ TCHAR szTmp[MAX_PATH];
+
+ mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
+ _tcslwr(szTmp);
+ if (_tcsstr(szTmp, szMirandaPathWLower))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc+lstrlen(szMirandaPathWLower));
+ else
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ }
+ return lstrlen(pOut);
+}
+
+MIR_CORE_DLL(int) PathToAbsoluteW(const TCHAR *pSrc, TCHAR *pOut, TCHAR* base)
+{
+ if ( !pSrc || !wcslen(pSrc) || wcslen(pSrc) > MAX_PATH)
+ return 0;
+
+ if (base == NULL)
+ base = szMirandaPathW;
+
+ TCHAR buf[MAX_PATH];
+ if (pSrc[0] < ' ')
+ return mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else if (pathIsAbsoluteW(pSrc))
+ return GetFullPathName(pSrc, MAX_PATH, pOut, NULL);
+ else if (pSrc[0] != '\\')
+ mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc);
+ else
+ mir_sntprintf(buf, MAX_PATH, _T("%s%s"), base, pSrc+1);
+
+ return GetFullPathName(buf, MAX_PATH, pOut, NULL);
+}
+
+MIR_CORE_DLL(void) CreatePathToFileW(WCHAR* wszFilePath)
+{
+ WCHAR* pszLastBackslash = wcsrchr(wszFilePath, '\\');
+ if (pszLastBackslash == NULL)
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW(wszFilePath);
+ *pszLastBackslash = '\\';
+}
+
+MIR_CORE_DLL(int) CreateDirectoryTreeW(const WCHAR* szDir)
+{
+ DWORD dwAttributes;
+ WCHAR* pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynW(szTestDir, szDir, SIZEOF(szTestDir));
+ if ((dwAttributes = GetFileAttributesW(szTestDir)) != INVALID_FILE_ATTRIBUTES && (dwAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ return 0;
+
+ pszLastBackslash = wcsrchr(szTestDir, '\\');
+ if (pszLastBackslash == NULL)
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW(szTestDir);
+ *pszLastBackslash = '\\';
+ return (CreateDirectoryW(szTestDir, NULL) == 0) ? GetLastError() : 0;
+}
+
+int InitPathUtils(void)
+{
+ char *p = 0;
+ GetModuleFileNameA(hInst, szMirandaPath, SIZEOF(szMirandaPath));
+ p = strrchr(szMirandaPath, '\\');
+ if (p)
+ p[1] = 0;
+ mir_snprintf(szMirandaPathLower, MAX_PATH, "%s", szMirandaPath);
+ _strlwr(szMirandaPathLower);
+
+ GetModuleFileName(hInst, szMirandaPathW, SIZEOF(szMirandaPathW));
+ TCHAR *tp = _tcsrchr(szMirandaPathW, '\\');
+ if (tp)
+ tp[1] = 0;
+ mir_sntprintf(szMirandaPathWLower, SIZEOF(szMirandaPathWLower), _T("%s"), szMirandaPathW);
+ _tcslwr(szMirandaPathWLower);
+ return 0;
+}
diff --git a/src/mir_core/sha1.cpp b/src/mir_core/sha1.cpp
new file mode 100644
index 0000000000..9e1b376d92
--- /dev/null
+++ b/src/mir_core/sha1.cpp
@@ -0,0 +1,155 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SHA 180-1 Reference Implementation (Compact version).
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Kocher of Cryptography Research.
+ * Portions created by the Initial Developer are Copyright (C) 1995-9
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "commonheaders.h"
+
+#define SHA_ROTL(X, n) (((X) << (n)) | ((X) >> (32-(n))))
+
+static void shaHashBlock(mir_sha1_ctx *ctx)
+{
+ int t;
+ unsigned long A, B, C, D, E, TEMP;
+
+ for (t = 16; t <= 79; t++)
+ ctx->W[t] =
+ SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
+
+ A = ctx->H[0];
+ B = ctx->H[1];
+ C = ctx->H[2];
+ D = ctx->H[3];
+ E = ctx->H[4];
+
+ for (t = 0; t <= 19; t++) {
+ TEMP = SHA_ROTL(A, 5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 20; t <= 39; t++) {
+ TEMP = SHA_ROTL(A, 5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 40; t <= 59; t++) {
+ TEMP = SHA_ROTL(A, 5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 60; t <= 79; t++) {
+ TEMP = SHA_ROTL(A, 5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+
+ ctx->H[0] += A;
+ ctx->H[1] += B;
+ ctx->H[2] += C;
+ ctx->H[3] += D;
+ ctx->H[4] += E;
+}
+
+MIR_CORE_DLL(void) mir_sha1_init(mir_sha1_ctx *ctx)
+{
+ ctx->lenW = 0;
+ ctx->sizeHi = ctx->sizeLo = 0;
+
+ /* Initialize H with the magic constants (see FIPS180 for constants)
+ */
+ ctx->H[0] = 0x67452301L;
+ ctx->H[1] = 0xefcdab89L;
+ ctx->H[2] = 0x98badcfeL;
+ ctx->H[3] = 0x10325476L;
+ ctx->H[4] = 0xc3d2e1f0L;
+
+ for (int i = 0; i < 80; i++)
+ ctx->W[i] = 0;
+}
+
+MIR_CORE_DLL(void) mir_sha1_append(mir_sha1_ctx *ctx, mir_sha1_byte_t *dataIn, int len)
+{
+ /* Read the data into W and process blocks as they get full
+ */
+ for (int i = 0; i < len; i++) {
+ ctx->W[ctx->lenW / 4] <<= 8;
+ ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i];
+ if ((++ctx->lenW) % 64 == 0) {
+ shaHashBlock(ctx);
+ ctx->lenW = 0;
+ }
+ ctx->sizeLo += 8;
+ ctx->sizeHi += (ctx->sizeLo < 8);
+ }
+}
+
+MIR_CORE_DLL(void) mir_sha1_finish(mir_sha1_ctx *ctx, mir_sha1_byte_t hashout[20])
+{
+ unsigned char pad0x80 = 0x80;
+ unsigned char pad0x00 = 0x00;
+ unsigned char padlen[8];
+ int i;
+
+ /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
+ */
+ padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
+ padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
+ padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
+ padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
+ padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
+ padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
+ padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
+ padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
+ mir_sha1_append(ctx, &pad0x80, 1);
+ while (ctx->lenW != 56)
+ mir_sha1_append(ctx, &pad0x00, 1);
+ mir_sha1_append(ctx, padlen, 8);
+
+ /* Output hash
+ */
+ for (i = 0; i < 20; i++) {
+ hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
+ ctx->H[i / 4] <<= 8;
+ }
+
+ /*
+ * Re-initialize the context (also zeroizes contents)
+ */
+ mir_sha1_init(ctx);
+}
+
+MIR_CORE_DLL(void) mir_sha1_hash(mir_sha1_byte_t *dataIn, int len, mir_sha1_byte_t hashout[20])
+{
+ mir_sha1_ctx ctx;
+
+ mir_sha1_init(&ctx);
+ mir_sha1_append(&ctx, dataIn, len);
+ mir_sha1_finish(&ctx, hashout);
+}
diff --git a/src/mir_core/threads.cpp b/src/mir_core/threads.cpp
new file mode 100644
index 0000000000..90dcdaaf5d
--- /dev/null
+++ b/src/mir_core/threads.cpp
@@ -0,0 +1,372 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "commonheaders.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// APC and mutex functions
+
+static void __stdcall DummyAPCFunc(ULONG_PTR)
+{
+ /* called in the context of thread that cleared it's APC queue */
+ return;
+}
+
+static int MirandaWaitForMutex(HANDLE hEvent)
+{
+ for (;;) {
+ // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
+ DWORD rc = MsgWaitForMultipleObjectsEx(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if (rc == WAIT_OBJECT_0 + 1) {
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (IsDialogMessage(msg.hwnd, &msg)) continue;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ else if (rc == WAIT_OBJECT_0) { // got object
+ return 1;
+ }
+ else if (rc == WAIT_ABANDONED_0 || rc == WAIT_FAILED)
+ return 0;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// exception handling
+
+static DWORD __cdecl sttDefaultFilter(DWORD, EXCEPTION_POINTERS*)
+{
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter;
+
+MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter()
+{
+ return pMirandaExceptFilter;
+}
+
+MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter)
+{
+ pfnExceptionFilter oldOne = pMirandaExceptFilter;
+ if (pMirandaExceptFilter != 0)
+ pMirandaExceptFilter = pMirandaExceptFilter;
+ return oldOne;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// thread support functions
+
+struct THREAD_WAIT_ENTRY
+{
+ DWORD dwThreadId; // valid if hThread isn't signalled
+ HANDLE hThread;
+ HINSTANCE hOwner;
+ void* pObject;
+ //PVOID addr;
+};
+
+static LIST<THREAD_WAIT_ENTRY> threads(10, NumericKeySortT);
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ pThreadFuncEx threadcodeex;
+ void *arg, *owner;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthread - starts a new thread
+
+void __cdecl forkthread_r(void * arg)
+{
+ struct FORK_ARG * fa = (struct FORK_ARG *) arg;
+ void (*callercode)(void*)=fa->threadcode;
+ void * cookie=fa->arg;
+ Thread_Push(( HINSTANCE)callercode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ callercode(cookie);
+ }
+ __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ Thread_Pop();
+ return;
+}
+
+MIR_CORE_DLL(UINT_PTR) forkthread( void (__cdecl *threadcode)(void*), unsigned long stacksize, void *arg)
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa;
+ fa.hEvent=CreateEvent(NULL, FALSE, FALSE, NULL);
+ fa.threadcode=threadcode;
+ fa.arg=arg;
+ rc=_beginthread(forkthread_r, stacksize, &fa);
+ if ((UINT_PTR)-1L != rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthreadex - starts a new thread with the extended info and returns the thread id
+
+unsigned __stdcall forkthreadex_r(void * arg)
+{
+ struct FORK_ARG *fa = (struct FORK_ARG *)arg;
+ pThreadFuncEx threadcode = fa->threadcodeex;
+ pThreadFuncOwner threadcodeex = (pThreadFuncOwner)fa->threadcodeex;
+ void *cookie = fa->arg;
+ void *owner = fa->owner;
+ unsigned long rc = 0;
+
+ Thread_Push((HINSTANCE)threadcode, fa->owner);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ if (owner)
+ rc = threadcodeex(owner, cookie);
+ else
+ rc = threadcode(cookie);
+ }
+ __except(pMirandaExceptFilter(GetExceptionCode(), GetExceptionInformation()))
+ {
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ Thread_Pop();
+ return rc;
+}
+
+MIR_CORE_DLL(UINT_PTR) forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void* owner,
+ void *arg,
+ unsigned *thraddr)
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa = { 0 };
+ fa.threadcodeex = threadcode;
+ fa.arg = arg;
+ fa.owner = owner;
+ fa.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ rc = _beginthreadex(sec, stacksize, forkthreadex_r, (void *)&fa, 0, thraddr);
+ if (rc)
+ WaitForSingleObject(fa.hEvent, INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(void) KillObjectThreads(void* owner)
+{
+ if (owner == NULL)
+ return;
+
+ WaitForSingleObject(hStackMutex, INFINITE);
+
+ HANDLE* threadPool = (HANDLE*)alloca(threads.getCount()*sizeof(HANDLE));
+ int threadCount = 0;
+
+ for (int j = threads.getCount(); j--;) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->pObject == owner)
+ threadPool[ threadCount++ ] = p->hThread;
+ }
+ ReleaseMutex(hStackMutex);
+
+ // is there anything to kill?
+ if (threadCount > 0) {
+ if ( WaitForMultipleObjects(threadCount, threadPool, TRUE, 5000) == WAIT_TIMEOUT) {
+ // forcibly kill all remaining threads after 5 secs
+ WaitForSingleObject(hStackMutex, INFINITE);
+ for (int j = threads.getCount()-1; j >= 0; j--) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->pObject == owner) {
+ TerminateThread(p->hThread, 9999);
+ CloseHandle(p->hThread);
+ threads.remove(j);
+ mir_free(p);
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD)
+{
+ if ( MirandaWaitForMutex(hStackMutex)) {
+ for (int j=0; j < threads.getCount(); j++) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA(p->hOwner, szModuleName, sizeof(szModuleName));
+ TerminateThread(p->hThread, 9999);
+ CloseHandle(p->hThread);
+ mir_free(p);
+ }
+
+ threads.destroy();
+
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty);
+ }
+}
+
+MIR_CORE_DLL(void) Thread_Wait(void)
+{
+ // acquire the list and wake up any alertable threads
+ if ( MirandaWaitForMutex(hStackMutex)) {
+ for (int j=0; j < threads.getCount(); j++)
+ QueueUserAPC(DummyAPCFunc, threads[j]->hThread, 0);
+ ReleaseMutex(hStackMutex);
+ }
+
+ // give all unclosed threads 5 seconds to close
+ SetTimer(NULL, 0, 5000, KillAllThreads);
+
+ // wait til the thread list is empty
+ MirandaWaitForMutex(hThreadQueueEmpty);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
+#define ThreadQuerySetWin32StartAddress 9
+
+static void* GetCurrentThreadEntryPoint()
+{
+ LONG ntStatus;
+ HANDLE hDupHandle, hCurrentProcess;
+ DWORD_PTR dwStartAddress;
+
+ pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" );
+ if(NtQueryInformationThread == NULL) return 0;
+
+ hCurrentProcess = GetCurrentProcess();
+ if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){
+ SetLastError(ERROR_ACCESS_DENIED);
+ return NULL;
+ }
+ ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL);
+ CloseHandle(hDupHandle);
+
+ if(ntStatus != ERROR_SUCCESS) return 0;
+ return ( void* )dwStartAddress;
+}
+
+MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
+ THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY));
+
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ p->dwThreadId = GetCurrentThreadId();
+ p->pObject = pOwner;
+ if (pluginListAddr.getIndex(hInst) != -1)
+ p->hOwner = hInst;
+ else
+ p->hOwner = GetInstByAddress(( hInst != NULL ) ? (PVOID)hInst : GetCurrentThreadEntryPoint());
+
+ threads.insert(p);
+
+ ReleaseMutex(hStackMutex);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+MIR_CORE_DLL(INT_PTR) Thread_Pop()
+{
+ if ( WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0) {
+ DWORD dwThreadId = GetCurrentThreadId();
+ for (int j=0; j < threads.getCount(); j++) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if (p->dwThreadId == dwThreadId) {
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CloseHandle(p->hThread);
+ threads.remove(j);
+ mir_free(p);
+
+ if ( !threads.getCount()) {
+ threads.destroy();
+ ReleaseMutex(hStackMutex);
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ }
+
+ ReleaseMutex(hStackMutex);
+ return 0;
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+const DWORD MS_VC_EXCEPTION=0x406D1388;
+
+#pragma pack(push,8)
+typedef struct tagTHREADNAME_INFO
+{
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+#pragma pack(pop)
+
+MIR_CORE_DLL(void) Thread_SetName(const char *szThreadName)
+{
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = szThreadName;
+ info.dwThreadID = GetCurrentThreadId();
+ info.dwFlags = 0;
+
+ __try
+ {
+ RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+}
diff --git a/src/mir_core/utf.cpp b/src/mir_core/utf.cpp
new file mode 100644
index 0000000000..ddf2d1ca9f
--- /dev/null
+++ b/src/mir_core/utf.cpp
@@ -0,0 +1,406 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+ Copyright 2000 Alexandre Julliard of Wine project
+ (UTF-8 conversion routines)
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
+static const char utf8_length[128] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xc0-0xcf */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xd0-0xdf */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xe0-0xef */
+ 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0-0xff */
+};
+
+/* first byte mask depending on UTF-8 sequence length */
+static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
+
+/* minimum Unicode value depending on UTF-8 sequence length */
+static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
+
+/* get the next char value taking surrogates into account */
+static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen)
+{
+ if (src[0] >= 0xd800 && src[0] <= 0xdfff) { /* surrogate pair */
+ if (src[0] > 0xdbff || /* invalid high surrogate */
+ srclen <= 1 || /* missing low surrogate */
+ src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */
+ return 0;
+ return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff);
+ }
+ return src[0];
+}
+
+/* query necessary dst length for src string */
+static int Ucs2toUtf8Len(const wchar_t *src, unsigned int srclen)
+{
+ int len;
+ unsigned int val;
+
+ for (len = 0; srclen; srclen--, src++) {
+ if (*src < 0x80) { /* 0x00-0x7f: 1 byte */
+ len++;
+ continue;
+ }
+ if (*src < 0x800) { /* 0x80-0x7ff: 2 bytes */
+ len += 2;
+ continue;
+ }
+ if ( !(val = getSurrogateValue(src, srclen)))
+ return -2;
+
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ len += 3;
+ else { /* 0x10000-0x10ffff: 4 bytes */
+ len += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return len;
+}
+
+MIR_CORE_DLL(int) Ucs2toUtf8Len(const wchar_t *src)
+{
+ if (src == 0)
+ return 0;
+
+ return Ucs2toUtf8Len(src, (int)wcslen(src));
+}
+
+/* wide char to UTF-8 string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen)
+{
+ int len;
+
+ for (len = dstlen; srclen; srclen--, src++)
+ {
+ WCHAR ch = *src;
+ unsigned int val;
+
+ if (ch < 0x80) /* 0x00-0x7f: 1 byte */
+ {
+ if ( !len--) return -1; /* overflow */
+ *dst++ = ch;
+ continue;
+ }
+
+ if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */
+ {
+ if ((len -= 2) < 0) return -1; /* overflow */
+ dst[1] = 0x80 | (ch & 0x3f);
+ ch >>= 6;
+ dst[0] = 0xc0 | ch;
+ dst += 2;
+ continue;
+ }
+
+ if ( !(val = getSurrogateValue(src, srclen)))
+ {
+ return -2;
+ }
+
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ {
+ if ((len -= 3) < 0) return -1; /* overflow */
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xe0 | val;
+ dst += 3;
+ }
+ else /* 0x10000-0x10ffff: 4 bytes */
+ {
+ if ((len -= 4) < 0) return -1; /* overflow */
+ dst[3] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xf0 | val;
+ dst += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return dstlen - len;
+}
+
+/* helper for the various utf8 mbstowcs functions */
+static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend)
+{
+ unsigned int len = utf8_length[ch-0x80];
+ unsigned int res = ch & utf8_mask[len];
+ const char *end = *str + len;
+
+ if (end > strend) return ~0;
+ switch(len)
+ {
+ case 3:
+ if ((ch = end[-3] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 2:
+ if ((ch = end[-2] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 1:
+ if ((ch = end[-1] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ if (res < utf8_minval[len]) break;
+ return res;
+ }
+ return ~0;
+}
+
+/* query necessary dst length for src string */
+static inline int Utf8toUcs2Len(const char *src, int srclen)
+{
+ int ret = 0;
+ unsigned int res;
+ const char *srcend = src + srclen;
+
+ while (src < srcend)
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ ret++;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff)
+ {
+ if (res > 0xffff) ret++;
+ ret++;
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ return ret;
+}
+
+/* UTF-8 to wide char string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Utf8toUcs2(const char *src, int srclen, wchar_t *dst, int dstlen)
+{
+ unsigned int res;
+ const char *srcend = src + srclen;
+ wchar_t *dstend = dst + dstlen;
+
+ while ((dst < dstend) && (src < srcend))
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ *dst++ = ch;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff)
+ {
+ *dst++ = res;
+ }
+ else if (res <= 0x10ffff) /* we need surrogates */
+ {
+ if (dst == dstend - 1) return -1; /* overflow */
+ res -= 0x10000;
+ *dst++ = 0xd800 | (res >> 10);
+ *dst++ = 0xdc00 | (res & 0x3ff);
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ if (src < srcend) return -1; /* overflow */
+ return dstlen - (dstend - dst);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+MIR_CORE_DLL(char*) Utf8DecodeCP(char* str, int codepage, wchar_t** ucs2)
+{
+ int len;
+ bool needs_free = false;
+ wchar_t* tempBuf = NULL;
+ if (ucs2)
+ *ucs2 = NULL;
+
+ if (str == NULL)
+ return NULL;
+
+ len = (int)strlen(str);
+
+ if (len < 2) {
+ if (ucs2 != NULL) {
+ *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ MultiByteToWideChar(codepage, 0, str, len, tempBuf, len);
+ tempBuf[len] = 0;
+ }
+ return str;
+ }
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0)
+ return NULL;
+
+ if (ucs2 == NULL) {
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = NULL;
+ needs_free = true;
+ }
+ }
+
+ if (tempBuf == NULL) {
+ tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if (tempBuf == NULL)
+ return NULL;
+ }
+
+ Utf8toUcs2(str, len, tempBuf, destlen);
+ tempBuf[destlen] = 0;
+ WideCharToMultiByte(codepage, 0, tempBuf, -1, str, len + 1, "?", NULL);
+
+ if (ucs2)
+ *ucs2 = tempBuf;
+ else if (needs_free)
+ mir_free(tempBuf);
+
+ return str;
+}
+
+MIR_CORE_DLL(char*) Utf8Decode(char* str, wchar_t** ucs2)
+{
+ return Utf8DecodeCP(str, Langpack_GetDefaultCodePage(), ucs2);
+}
+
+MIR_CORE_DLL(wchar_t*) Utf8DecodeW(const char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ int len = (int)strlen(str);
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0) return NULL;
+
+ wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if (ucs2 == NULL) return NULL;
+
+ if (Utf8toUcs2(str, len, ucs2, destlen) >= 0)
+ {
+ ucs2[destlen] = 0;
+ return ucs2;
+ }
+
+ mir_free(ucs2);
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts MBCS string to the UTF8-encoded format
+
+MIR_CORE_DLL(char*) Utf8EncodeCP(const char* src, int codepage)
+{
+ int len;
+ bool needs_free = false;
+ char* result = NULL;
+ wchar_t* tempBuf;
+
+ if (src == NULL)
+ return NULL;
+
+ len = (int)strlen(src);
+
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ if (tempBuf == NULL) return NULL;
+ needs_free = true;
+ }
+
+ len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1);
+
+ int destlen = Ucs2toUtf8Len(tempBuf, len);
+ if (destlen >= 0)
+ {
+ result = (char*)mir_alloc(destlen + 1);
+ if (result)
+ {
+ Ucs2toUtf8(tempBuf, len, result, destlen);
+ result[destlen] = 0;
+ }
+ }
+
+ if (needs_free)
+ mir_free(tempBuf);
+
+ return result;
+}
+
+MIR_CORE_DLL(char*) Utf8Encode(const char* src)
+{
+ return Utf8EncodeCP(src, Langpack_GetDefaultCodePage());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+
+MIR_CORE_DLL(char*) Utf8EncodeW(const wchar_t* src)
+{
+ if (src == NULL)
+ return NULL;
+
+ int len = (int)wcslen(src);
+
+ int destlen = Ucs2toUtf8Len(src, len);
+ if (destlen < 0) return NULL;
+
+ char* result = (char*)mir_alloc(destlen + 1);
+ if (result == NULL)
+ return NULL;
+
+ Ucs2toUtf8(src, len, result, destlen);
+ result[destlen] = 0;
+
+ return result;
+}
diff --git a/src/mir_core/utils.cpp b/src/mir_core/utils.cpp
new file mode 100644
index 0000000000..4ebba2f293
--- /dev/null
+++ b/src/mir_core/utils.cpp
@@ -0,0 +1,150 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "commonheaders.h"
+
+MIR_CORE_DLL(char*) rtrim(char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ char* p = strchr(str, 0);
+ while (--p >= str) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+
+MIR_CORE_DLL(WCHAR*) wrtrim(WCHAR *str)
+{
+ if (str == NULL)
+ return NULL;
+
+ WCHAR* p = _tcschr(str, 0);
+ while (--p >= str) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+
+MIR_CORE_DLL(char*) ltrim(char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ char* p = str;
+ for (;;) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ memmove(str, p, strlen(p) + 1);
+ return str;
+ }
+ }
+}
+
+MIR_CORE_DLL(char*) ltrimp(char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ char* p = str;
+ for (;;) {
+ switch (*p) {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ return p;
+ }
+ }
+}
+
+MIR_CORE_DLL(int) wildcmp(char * name, char * mask)
+{
+ char * last='\0';
+ for (;; mask++, name++) {
+ if (*mask != '?' && *mask != *name) break;
+ if (*name == '\0') return ((BOOL)!*mask);
+ }
+ if (*mask != '*') return FALSE;
+ for (;; mask++, name++){
+ while (*mask == '*') {
+ last = mask++;
+ if (*mask == '\0') return ((BOOL)!*mask); /* true */
+ }
+ if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */
+ if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int sttComparePlugins(const HINSTANCE__* p1, const HINSTANCE__* p2)
+{
+ if (p1 == p2)
+ return 0;
+
+ return (p1 < p2) ? -1 : 1;
+}
+
+LIST<HINSTANCE__> pluginListAddr(10, sttComparePlugins);
+
+MIR_CORE_DLL(void) RegisterModule(HINSTANCE hInst)
+{
+ pluginListAddr.insert(hInst);
+}
+
+MIR_CORE_DLL(void) UnregisterModule(HINSTANCE hInst)
+{
+ pluginListAddr.remove(hInst);
+}
+
+MIR_CORE_DLL(HINSTANCE) GetInstByAddress(void* codePtr)
+{
+ if (pluginListAddr.getCount() == 0)
+ return NULL;
+
+ int idx;
+ List_GetIndex((SortedList*)&pluginListAddr, codePtr, &idx);
+ if (idx > 0)
+ idx--;
+
+ HINSTANCE result = pluginListAddr[idx];
+ if (result < hInst && codePtr > hInst)
+ result = hInst;
+ else if (idx == 0 && codePtr < (void*)result)
+ result = NULL;
+
+ return result;
+}