diff options
| -rw-r--r-- | plugins/ShellExt/src/shlcom.cpp | 1280 | ||||
| -rw-r--r-- | plugins/ShellExt/src/shlcom.h | 21 | ||||
| -rw-r--r-- | plugins/ShellExt/src/stdafx.h | 6 | 
3 files changed, 532 insertions, 775 deletions
diff --git a/plugins/ShellExt/src/shlcom.cpp b/plugins/ShellExt/src/shlcom.cpp index a77b382f22..8d7103a5a0 100644 --- a/plugins/ShellExt/src/shlcom.cpp +++ b/plugins/ShellExt/src/shlcom.cpp @@ -497,7 +497,6 @@ BOOL __stdcall ProcessRequest(HWND hwnd, LPARAM param)  	char szBuf[MAX_PATH];
  	TEnumData *lParam = (TEnumData*)param;
 -	BOOL Result = true;
  	DWORD pid = 0;
  	GetWindowThreadProcessId(hwnd, &pid);
  	if (pid != 0) {
 @@ -511,7 +510,7 @@ BOOL __stdcall ProcessRequest(HWND hwnd, LPARAM param)  			if ( lstrcmpA(szBuf, MIRANDANAME) != 0) {
  				// opened but not valid.
  				CloseHandle(hMirandaWorkEvent);
 -				return Result;
 +				return true;
  			}
  		}
  		// if the event object exists,  a shlext.dll running in the instance must of created it.
 @@ -547,6 +546,7 @@ BOOL __stdcall ProcessRequest(HWND hwnd, LPARAM param)  			CloseHandle(hMirandaWorkEvent);
  		}
  	}
 +	return true;
  }
  /////////////////////////////////////////////////////////////////////////////////////////
 @@ -655,6 +655,7 @@ HRESULT TShlComRec::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj  	// store the new one && AddRef() it
  	pDataObject = pdtobj;
  	pDataObject->AddRef();
 +	return S_OK;
  }
  /////////////////////////////////////////////////////////////////////////////////////////
 @@ -1038,822 +1039,571 @@ HRESULT TClassFactoryRec::LockServer(BOOL)  // IPC part
  //
 -type
 -  PFileList = ^TFileList;
 -  TFileList = array [0 .. 0] of LPSTR;
 -  PAddArgList = ^TAddArgList;
 -
 -  TAddArgList = record
 -    szFile: LPSTR; // file being processed
 -    cch: Cardinal; // it's length (with space for NULL char)
 -    count: Cardinal; // number we have so far
 -    files: PFileList;
 -    hContact: HANDLE;
 -    hEvent: HANDLE;
 -  }
 -
 -function AddToList( args: TAddArgList): LongBool;
 -
 -  attr: Cardinal;
 -  p: Pointer;
 -  hFind: HANDLE;
 -  fd: TWIN32FINDDATA;
 -  szBuf: array [0 .. MAX_PATH] of Char;
 -  szThis: LPSTR;
 -  cchThis: Cardinal;
 +struct TAddArgList
  {
 -  Result = false;
 -  attr = GetFileAttributes(args.szFile);
 -  if (attr != 0xFFFFFFFF) && ((attr && FILE_ATTRIBUTE_HIDDEN) = 0) 
 -  {
 -    if args.count mod 10 = 5 
 -    {
 -      if CallService(MS_SYSTEM_TERMINATED, 0, 0) != 0 
 -      {
 -        Result = true;
 -        Exit;
 -      } // if
 -    }
 -    if attr && FILE_ATTRIBUTE_DIRECTORY != 0 
 -    {
 -      // add the directory
 -      lstrcpyA(szBuf, args.szFile);
 -      ReAllocMem(args.files, (args.count + 1) * sizeof(LPSTR));
 -      GetMem(p, strlen(szBuf) + 1);
 -      lstrcpyA(p, szBuf);
 -      args.files^[args.count] = p;
 -      inc(args.count);
 -      // tack on ending search token
 -      lstrcata(szBuf, '\*');
 -      hFind = FindFirstFile(szBuf, fd);
 -      while true do
 -      {
 -        if fd.cFileName[0] != '.' 
 -        {
 -          lstrcpyA(szBuf, args.szFile);
 -          lstrcata(szBuf, '\');
 -          lstrcata(szBuf, fd.cFileName);
 -          // keep a copy of the current thing being processed
 -          szThis = args.szFile;
 -          args.szFile = szBuf;
 -          cchThis = args.cch;
 -          args.cch = strlen(szBuf) + 1;
 -          // recurse
 -          Result = AddToList(args);
 -          // restore
 -          args.szFile = szThis;
 -          args.cch = cchThis;
 -          if Result 
 -            break;
 -        } // if
 -        if not FindNextFile(hFind, fd) 
 -          break;
 -      } // while
 -      FindClose(hFind);
 -    }
 -    else
 -    {
 -      // add the file
 -      ReAllocMem(args.files, (args.count + 1) * sizeof(LPSTR));
 -      GetMem(p, args.cch);
 -      lstrcpyA(p, args.szFile);
 -      args.files^[args.count] = p;
 -      inc(args.count);
 -    } // if
 -  }
 -}
 +	LPSTR szFile; // file being processed
 +	int cch; // it's length (with space for NULL char)
 +	int count; // number we have so far
 +	LPSTR *files;
 +	HANDLE hContact, hEvent;
 +};
 -procedure MainThreadIssueTransfer(p: PAddArgList); stdcall;
 -{$DEFINE SHL_IDC}
 -{$DEFINE SHL_KEYS}
 -{$INCLUDE shlc.inc}
 -{$UNDEF SHL_KEYS}
 -{$UNDEF SHL_IDC}
 +BOOL AddToList(TAddArgList& args)
  {
 -  DBWriteContactSettingByte(p->hContact, SHLExt_Name, SHLExt_MRU, 1);
 -  CallService(MS_FILE_SENDSPECIFICFILES, p->hContact, lParam(p->files));
 -  SetEvent(p->hEvent);
 +	char szBuf[MAX_PATH];
 +	LPSTR szThis;
 +
 +	DWORD attr = GetFileAttributesA(args.szFile);
 +	if (attr != 0xFFFFFFFF && (attr & FILE_ATTRIBUTE_HIDDEN) == 0) {
 +		if ((args.count % 10) == 5)
 +			if (CallService(MS_SYSTEM_TERMINATED, 0, 0) != 0)
 +				return true;
 +
 +		if (attr & FILE_ATTRIBUTE_DIRECTORY) {
 +			// add the directory
 +			lstrcpyA(szBuf, args.szFile);
 +			args.files = (LPSTR*)mir_realloc(args.files, (args.count + 1) * sizeof(LPSTR));
 +			char *p = mir_strdup(szBuf);
 +			args.files[args.count] = p;
 +			args.count++;
 +			// tack on ending search token
 +			lstrcatA(szBuf, "\\*");
 +
 +			WIN32_FIND_DATAA fd;
 +			HANDLE hFind = FindFirstFileA(szBuf, &fd);
 +			while (true) {
 +				if (fd.cFileName[0] != '.') {
 +					lstrcpyA(szBuf, args.szFile);
 +					lstrcatA(szBuf, "\\");
 +					lstrcatA(szBuf, fd.cFileName);
 +					// keep a copy of the current thing being processed
 +					szThis = args.szFile;
 +					args.szFile = szBuf;
 +					int cchThis = args.cch;
 +					args.cch = (int)strlen(szBuf) + 1;
 +					// recurse
 +					BOOL Result = AddToList(args);
 +					// restore
 +					args.szFile = szThis;
 +					args.cch = cchThis;
 +					if (Result)
 +						return true;
 +				} 
 +				if (!FindNextFileA(hFind, &fd))
 +					break;
 +			}
 +			FindClose(hFind);
 +		}
 +		else {
 +			// add the file
 +			args.files = (LPSTR*)mir_realloc(args.files, (args.count + 1) * sizeof(LPSTR));
 +			args.files[args.count] = mir_strdup(args.szFile);
 +			args.count++;
 +		}
 +	}
 +	return false;
  }
 -procedure IssueTransferThread(pipch: THeaderIPC *); cdecl;
 -
 -  szBuf: array [0 .. MAX_PATH] of Char;
 -  pct: TSlotIPC *;
 -  args: TAddArgList;
 -  bQuit: LongBool;
 -  j, c: Cardinal;
 -  p: Pointer;
 -  hMainThread: HANDLE;
 +void NTAPI MainThreadIssueTransfer(ULONG_PTR param)
  {
 -  hMainThread = HANDLE(pipch->Param);
 -  GetCurrentDirectory(sizeof(szBuf), szBuf);
 -  args.count = 0;
 -  args.files = NULL;
 -  pct = pipch->DataPtr;
 -  bQuit = false;
 -  while pct != NULL do
 -  {
 -    if (pct->cbSize != sizeof(TSlotIPC)) 
 -      break;
 -    args.szFile = LPSTR(UINT_PTR(pct) + sizeof(TSlotIPC));
 -    args.hContact = pct->hContact;
 -    args.cch = pct->cbStrSection + 1;
 -    bQuit = AddToList(args);
 -    if bQuit 
 -      break;
 -    pct = pct->Next;
 -  } // while
 -  if args.files != NULL 
 -  {
 -    ReAllocMem(args.files, (args.count + 1) * sizeof(LPSTR));
 -    args.files^[args.count] = NULL;
 -    inc(args.count);
 -    if (not bQuit) 
 -    {
 -      args.hEvent = CreateEvent(NULL, true, false, NULL);
 -      QueueUserAPC(@MainThreadIssueTransfer, hMainThread, UINT_PTR(@args));
 -      while true do
 -      {
 -        if WaitForSingleObjectEx(args.hEvent, INFINITE, true) != WAIT_IO_COMPLETION 
 -          break;
 -      }
 -      CloseHandle(args.hEvent);
 -    } // if
 -    c = args.count - 1;
 -    for j = 0 to c do
 -    {
 -      p = args.files^[j];
 -      if p != NULL 
 -        FreeMem(p);
 -    }
 -    FreeMem(args.files);
 -  }
 -  SetCurrentDirectory(szBuf);
 -  FreeMem(pipch);
 -  CloseHandle(hMainThread);
 +	TAddArgList *p = (TAddArgList *)param;
 +	db_set_b(p->hContact, SHLExt_Name, SHLExt_MRU, 1);
 +	CallService(MS_FILE_SENDSPECIFICFILES, (WPARAM)p->hContact, LPARAM(p->files));
 +	SetEvent(p->hEvent);
  }
 -type
 +void __cdecl IssueTransferThread(void *param)
 +{
 +	THeaderIPC *pipch = (THeaderIPC *)param;
 +	HANDLE hMainThread = HANDLE(pipch->Param);
 -  PSlotInfo = ^TSlotInfo;
 +	char szBuf[MAX_PATH];
 +	GetCurrentDirectoryA(sizeof(szBuf), szBuf);
 -  TSlotInfo = record
 -    hContact: HANDLE;
 -    hProto: Cardinal;
 -    dwStatus: Integer; // will be aligned anyway
 -  }
 +	TAddArgList args;
 +	args.count = 0;
 +	args.files = NULL;
 +	TSlotIPC *pct = pipch->DataPtr;
 +	BOOL bQuit = false;
 +	while (pct != NULL) {
 +		if (pct->cbSize != sizeof(TSlotIPC)) 
 +			break;
 +		args.szFile = LPSTR(UINT_PTR(pct) + sizeof(TSlotIPC));
 +		args.hContact = pct->hContact;
 +		args.cch = pct->cbStrSection + 1;
 +		bQuit = AddToList(args);
 +		if (bQuit)
 +			break;
 +		pct = pct->Next;
 +	} // while
 +
 +	if (args.files != NULL) {
 +		args.files = (LPSTR*)mir_realloc(args.files, (args.count + 1) * sizeof(LPSTR));
 +		args.files[args.count] = NULL;
 +		args.count++;
 +		if (!bQuit) {
 +			args.hEvent = CreateEvent(NULL, true, false, NULL);
 +			QueueUserAPC(MainThreadIssueTransfer, hMainThread, UINT_PTR(&args));
 +			while (true) {
 +				if (WaitForSingleObjectEx(args.hEvent, INFINITE, true) != WAIT_IO_COMPLETION)
 +					break;
 +			}
 +			CloseHandle(args.hEvent);
 +		}
 +		for (int j = 0; j < args.count; j++)
 +			mir_free(args.files[j]);
 +		mir_free(args.files);
 +	}
 +	SetCurrentDirectoryA(szBuf);
 +	mir_free(pipch);
 +	CloseHandle(hMainThread);
 +}
 -  TSlotArray = array [0 .. $FFFFFF] of TSlotInfo;
 -  PSlotArray = ^TSlotArray;
 +struct TSlotInfo
 +{
 +	HANDLE hContact;
 +	int    hProto;
 +	int    dwStatus; // will be aligned anyway
 +};
 -function SortContact( Item1, Item2: TSlotInfo): Integer; stdcall;
 +int __cdecl SortContact(const void *Item1, const void *Item2)
  {
 -  Result = CallService(MS_CLIST_CONTACTSCOMPARE, Item1.hContact, Item2.hContact);
 +	return CallService(MS_CLIST_CONTACTSCOMPARE, (WPARAM)((TSlotInfo*)Item1)->hContact, (LPARAM)((TSlotInfo*)Item2)->hContact);
  }
 -// from FP FCL
 -
 -procedure QuickSort(FList: PSlotArray; L, R: LongInt);
 -
 -  i, j: LongInt;
 -  p, q: TSlotInfo;
 +void ipcGetSkinIcons(THeaderIPC *ipch)
  {
 -  repeat
 -    i = L;
 -    j = R;
 -    p = FList^[(L + R) div 2];
 -    repeat
 -      while SortContact(p, FList^[i]) > 0 do
 -        inc(i);
 -      while SortContact(p, FList^[j]) < 0 do
 -        dec(j);
 -      if i <= j 
 -      {
 -        q = FList^[i];
 -        FList^[i] = FList^[j];
 -        FList^[j] = q;
 -        inc(i);
 -        dec(j);
 -      } // if
 -    until i > j;
 -    if L < j 
 -      QuickSort(FList, L, j);
 -    L = i;
 -  until i >= R;
 +	TSlotProtoIcons spi;
 +	char szTmp[64];
 +
 +	int protoCount;
 +	PROTOACCOUNT *pp;
 +	if ( CallService(MS_PROTO_ENUMACCOUNTS, WPARAM(&protoCount), LPARAM(&pp)) == 0 && protoCount != 0) {
 +		spi.pid = GetCurrentProcessId();
 +		while (protoCount > 0) {
 +			lstrcpyA(szTmp, pp->szModuleName);
 +			lstrcatA(szTmp, PS_GETCAPS);
 +			DWORD dwCaps = CallService(szTmp, PFLAGNUM_1, 0);
 +			if (dwCaps && PF1_FILESEND) {
 +				TSlotIPC *pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons));
 +				if (pct != NULL) {
 +					// capture all the icons!
 +					spi.hProto = mir_hashstr(pp->szModuleName);
 +					for (int j = 0; j <= 10; j++)
 +						spi.hIcons[j] = LoadSkinnedProtoIcon(pp->szModuleName, ID_STATUS_OFFLINE + j);
 +
 +					pct->fType = REQUEST_NEWICONS;
 +					memcpy(LPSTR(pct) + sizeof(TSlotIPC), &spi, sizeof(TSlotProtoIcons));
 +					if (ipch->NewIconsBegin == NULL)
 +						ipch->NewIconsBegin = pct;
 +				}
 +			}
 +			pp++;
 +			protoCount--;
 +		}
 +	}
 +
 +	// add Miranda icon
 +	TSlotIPC *pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons));
 +	if (pct != NULL) {
 +		ZeroMemory(&spi.hIcons, sizeof(spi.hIcons));
 +		spi.hProto = 0; // no protocol
 +		spi.hIcons[0] = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
 +		pct->fType = REQUEST_NEWICONS;
 +		memcpy(LPSTR(pct) + sizeof(TSlotIPC), &spi, sizeof(TSlotProtoIcons));
 +		if (ipch->NewIconsBegin == NULL)
 +			ipch->NewIconsBegin = pct;
 +	}
  }
 -{$DEFINE SHL_KEYS}
 -{$INCLUDE shlc.inc}
 -{$UNDEF SHL_KEYS}
 +bool ipcGetSortedContacts(THeaderIPC *ipch, int *pSlot, bool bGroupMode)
 +{
 +	DBVARIANT dbv;
 +	int n, rc;
 +
 +	bool Result = false;
 +	// hide offliners?
 +	bool bHideOffline = db_get_b(0, "CList", "HideOffline", 0) == 1;
 +	// do they wanna hide the offline people anyway?
 +	if (db_get_b(0, SHLExt_Name, SHLExt_ShowNoOffline, 0) == 1)
 +		// hide offline people
 +		bHideOffline = true;
 +
 +	// get the number of contacts
 +	int dwContacts = (int)CallService(MS_DB_CONTACT_GETCOUNT, 0, 0);
 +	if (dwContacts == 0)
 +		return false;
 +
 +	// get the contacts in the array to be sorted by status, trim out anyone
 +	// who doesn't wanna be seen.
 +	TSlotInfo *pContacts = (TSlotInfo*)mir_alloc((dwContacts + 2) * sizeof(TSlotInfo));
 +	int i = 0;
 +	int dwOnline = 0;
 +	for (HANDLE hContact = db_find_first(); hContact != 0; hContact = db_find_next(hContact)) {
 +		if (i >= dwContacts)
 +			break;
 -procedure ipcGetSkinIcons(ipch: THeaderIPC *);
 +		// do they have a running protocol? 
 +		char *szProto = GetContactProto(hContact);
 +		if (szProto != NULL) {
 +			// does it support file sends?
 +			DWORD dwCaps = ProtoCallService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
 +			if ((dwCaps && PF1_FILESEND) == 0)
 +				continue;
 +
 +			int dwStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
 +			if (dwStatus != ID_STATUS_OFFLINE)
 +				dwOnline++;
 +			else if (bHideOffline)
 +				continue;
 +
 +			// is HIT on?
 +			if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseHITContacts, BST_UNCHECKED)) {
 +				// don't show people who are "Hidden" "NotOnList" | Ignored
 +				if (db_get_b(hContact, "CList", "Hidden", 0) == 1 ||
 +					 db_get_b(hContact, "CList", "NotOnList", 0) == 1 ||
 +					 CallService(MS_IGNORE_ISIGNORED, (WPARAM)hContact, IGNOREEVENT_MESSAGE | IGNOREEVENT_URL | IGNOREEVENT_FILE) != 0) 
 +					continue;
 +			}
 +			// is HIT2 off?
 +			if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseHIT2Contacts, BST_UNCHECKED))
 +				if (db_get_w(hContact, szProto, "ApparentMode", 0) == ID_STATUS_OFFLINE)
 +					continue;
 +
 +			// store
 +			pContacts[i].hContact = hContact;
 +			pContacts[i].dwStatus = dwStatus;
 +			pContacts[i].hProto = mir_hashstr(szProto);
 +			i++;
 +		}
 +	}
 -  protoCount: Integer;
 -  pp: ^PPROTOCOLDESCRIPTOR;
 -  spi: TSlotProtoIcons;
 -  j: Cardinal;
 -  pct: TSlotIPC *;
 -  szTmp: array [0 .. 63] of Char;
 -  dwCaps: Cardinal;
 -{
 -  if (CallService(MS_PROTO_ENUMACCOUNTS, wParam(@protoCount), lParam(@pp)) = 0) &&
 -    (protoCount != 0) 
 -  {
 -    spi.pid = GetCurrentProcessId();
 -    while protoCount > 0 do
 -    {
 -      lstrcpyA(szTmp, pp->szName);
 -      lstrcata(szTmp, PS_GETCAPS);
 -      dwCaps = CallService(szTmp, PFLAGNUM_1, 0);
 -      if (dwCaps && PF1_FILESEND) != 0 
 -      {
 -        pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons));
 -        if pct != NULL 
 -        {
 -          // capture all the icons!
 -          spi.hProto = StrHash(pp->szName);
 -          for j = 0 to 9 do
 -          {
 -            spi.hIcons[j] = LoadSkinnedProtoIcon(pp->szName, ID_STATUS_OFFLINE + j);
 -          } // for
 -          pct->fType = REQUEST_NEWICONS;
 -          CopyMemory(Pointer(UINT_PTR(pct) + sizeof(TSlotIPC)), @spi, sizeof(TSlotProtoIcons));
 -          if ipch->NewIconsBegin = NULL 
 -            ipch->NewIconsBegin = pct;
 -        } // if
 -      } // if
 -      inc(pp);
 -      dec(protoCount);
 -    } // while
 -  } // if
 -  // add Miranda icon
 -  pct = ipcAlloc(ipch, sizeof(TSlotProtoIcons));
 -  if pct != NULL 
 -  {
 -    ZeroMemory(@spi.hIcons, sizeof(spi.hIcons));
 -    spi.hProto = 0; // no protocol
 -    spi.hIcons[0] = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
 -    pct->fType = REQUEST_NEWICONS;
 -    CopyMemory(Pointer(UINT_PTR(pct) + sizeof(TSlotIPC)), @spi, sizeof(TSlotProtoIcons));
 -    if ipch->NewIconsBegin = NULL 
 -      ipch->NewIconsBegin = pct;
 -  } // if
 -}
 +	// if no one is online && the CList isn't showing offliners, quit
 +	if (dwOnline == 0 && bHideOffline) {
 +		mir_free(pContacts);
 +		return false;
 +	}
 -function ipcGetSortedContacts(ipch: THeaderIPC *; pSlot: pint; bGroupMode: Boolean): Boolean;
 -
 -  dwContacts: Cardinal;
 -  pContacts: PSlotArray;
 -  hContact: HANDLE;
 -  i: Integer;
 -  dwOnline: Cardinal;
 -  szProto: LPSTR;
 -  dwStatus: Integer;
 -  pct: TSlotIPC *;
 -  szContact: LPSTR;
 -  dbv: TDBVariant;
 -  bHideOffline: Boolean;
 -  szTmp: array [0 .. 63] of Char;
 -  dwCaps: Cardinal;
 -  szSlot: LPSTR;
 -  n, rc, cch: Cardinal;
 -{
 -  Result = false;
 -  // hide offliners?
 -  bHideOffline = DBGetContactSettingByte(0, 'CList', 'HideOffline', 0) = 1;
 -  // do they wanna hide the offline people anyway?
 -  if DBGetContactSettingByte(0, SHLExt_Name, SHLExt_ShowNoOffline, 0) = 1 
 -  {
 -    // hide offline people
 -    bHideOffline = true;
 -  }
 -  // get the number of contacts
 -  dwContacts = CallService(MS_DB_CONTACT_GETCOUNT, 0, 0);
 -  if dwContacts = 0 
 -    Exit;
 -  // get the contacts in the array to be sorted by status, trim out anyone
 -  // who doesn't wanna be seen.
 -  GetMem(pContacts, (dwContacts + 2) * sizeof(TSlotInfo));
 -  i = 0;
 -  dwOnline = 0;
 -  hContact = db_find_first();
 -  while (hContact != 0) do
 -  {
 -    if i >= dwContacts 
 -      break;
 -    (* do they have a running protocol? *)
 -    UINT_PTR(szProto) = CallService(MS_PROTO_GETCONTACTBASEPROTO, hContact, 0);
 -    if szProto != NULL 
 -    {
 -      (* does it support file sends? *)
 -      lstrcpyA(szTmp, szProto);
 -      lstrcata(szTmp, PS_GETCAPS);
 -      dwCaps = CallService(szTmp, PFLAGNUM_1, 0);
 -      if (dwCaps && PF1_FILESEND) = 0 
 -      {
 -        hContact = db_find_next(hContact);
 -        continue;
 -      }
 -      dwStatus = DBGetContactSettingWord(hContact, szProto, 'Status', ID_STATUS_OFFLINE);
 -      if dwStatus != ID_STATUS_OFFLINE 
 -        inc(dwOnline)
 -      else if bHideOffline 
 -      {
 -        hContact = db_find_next(hContact);
 -        continue;
 -      } // if
 -      // is HIT on?
 -      if BST_UNCHECKED = DBGetContactSettingByte(0, SHLExt_Name, SHLExt_UseHITContacts,
 -        BST_UNCHECKED) 
 -      {
 -        // don't show people who are "Hidden" "NotOnList" | Ignored
 -        if (DBGetContactSettingByte(hContact, 'CList', 'Hidden', 0) = 1) |
 -          (DBGetContactSettingByte(hContact, 'CList', 'NotOnList', 0) = 1) |
 -          (CallService(MS_IGNORE_ISIGNORED, hContact, IGNOREEVENT_MESSAGE |
 -          IGNOREEVENT_URL | IGNOREEVENT_FILE) != 0) 
 -        {
 -          hContact = db_find_next(hContact);
 -          continue;
 -        } // if
 -      } // if
 -      // is HIT2 off?
 -      if BST_UNCHECKED = DBGetContactSettingByte(0, SHLExt_Name, SHLExt_UseHIT2Contacts,
 -        BST_UNCHECKED) 
 -      {
 -        if DBGetContactSettingWord(hContact, szProto, 'ApparentMode', 0) = ID_STATUS_OFFLINE
 -        
 -        {
 -          hContact = db_find_next(hContact);
 -          continue;
 -        } // if
 -      } // if
 -      // store
 -      pContacts^[i].hContact = hContact;
 -      pContacts^[i].dwStatus = dwStatus;
 -      pContacts^[i].hProto = StrHash(szProto);
 -      inc(i);
 -    }
 -    else
 -    {
 -      // contact has no protocol!
 -    } // if
 -    hContact = db_find_next(hContact);
 -  } // while
 -  // if no one is online && the CList isn't showing offliners, quit
 -  if (dwOnline = 0) && (bHideOffline) 
 -  {
 -    FreeMem(pContacts);
 -    Exit;
 -  } // if
 -  dwContacts = i;
 -  i = 0;
 -  // sort the array
 -  QuickSort(pContacts, 0, dwContacts - 1);
 -  // create an IPC slot for each contact && store display name, etc
 -  while i < dwContacts do
 -  {
 -    UINT_PTR(szContact) = CallService(MS_CLIST_GETCONTACTDISPLAYNAME,pContacts^[i].hContact, 0);
 -    if (szContact != NULL) 
 -    {
 -      n = 0;
 -      rc = 1;
 -      if bGroupMode 
 -      {
 -        rc = DBGetContactSetting(pContacts^[i].hContact, 'CList', 'Group', @dbv);
 -        if rc = 0 
 -        {
 -          n = lstrlenA(dbv.szVal.a) + 1;
 -        }
 -      } // if
 -      cch = lstrlenA(szContact) + 1;
 -      pct = ipcAlloc(ipch, cch + 1 + n);
 -      if pct = NULL 
 -      {
 -        DBFreeVariant(@dbv);
 -        break;
 -      }
 -      // lie about the actual size of the TSlotIPC
 -      pct->cbStrSection = cch;
 -      szSlot = LPSTR(UINT_PTR(pct) + sizeof(TSlotIPC));
 -      lstrcpyA(szSlot, szContact);
 -      pct->fType = REQUEST_CONTACTS;
 -      pct->hContact = pContacts^[i].hContact;
 -      pct->Status = pContacts^[i].dwStatus;
 -      pct->hProto = pContacts^[i].hProto;
 -      pct->MRU = DBGetContactSettingByte(pct->hContact, SHLExt_Name, SHLExt_MRU, 0);
 -      if ipch->ContactsBegin = NULL 
 -        ipch->ContactsBegin = pct;
 -      inc(szSlot, cch + 1);
 -      if rc = 0 
 -      {
 -        pct->hGroup = StrHash(dbv.szVal.a);
 -        lstrcpyA(szSlot, dbv.szVal.a);
 -        DBFreeVariant(@dbv);
 -      }
 -      else
 -      {
 -        pct->hGroup = 0;
 -        szSlot^ = #0;
 -      }
 -      inc(pSlot^);
 -    } // if
 -    inc(i);
 -  } // while
 -  FreeMem(pContacts);
 -  //
 -  Result = true;
 +	dwContacts = i;
 +	qsort(pContacts, dwContacts, sizeof(TSlotInfo), SortContact);
 +
 +	// create an IPC slot for each contact && store display name, etc
 +	for (i=0; i < dwContacts; i++) {
 +		char *szContact = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)pContacts[i].hContact, 0);
 +		if (szContact != NULL) {
 +			n = 0;
 +			rc = 1;
 +			if (bGroupMode) {
 +				rc = db_get_s(pContacts[i].hContact, "CList", "Group", &dbv);
 +				if (!rc)
 +					n = lstrlenA(dbv.pszVal) + 1;
 +			}
 +			int cch = lstrlenA(szContact) + 1;
 +			TSlotIPC *pct = ipcAlloc(ipch, cch + 1 + n);
 +			if (pct == NULL) {
 +				db_free(&dbv);
 +				break;
 +			}
 +			// lie about the actual size of the TSlotIPC
 +			pct->cbStrSection = cch;
 +			LPSTR szSlot = LPSTR(pct) + sizeof(TSlotIPC);
 +			lstrcpyA(szSlot, szContact);
 +			pct->fType = REQUEST_CONTACTS;
 +			pct->hContact = pContacts[i].hContact;
 +			pct->Status = pContacts[i].dwStatus;
 +			pct->hProto = pContacts[i].hProto;
 +			pct->MRU = db_get_b(pct->hContact, SHLExt_Name, SHLExt_MRU, 0);
 +			if (ipch->ContactsBegin == NULL)
 +				ipch->ContactsBegin = pct;
 +			szSlot += cch + 1;
 +			if (rc == 0) {
 +				pct->hGroup = mir_hashstr(dbv.pszVal);
 +				lstrcpyA(szSlot, dbv.pszVal);
 +				db_free(&dbv);
 +			}
 +			else {
 +				pct->hGroup = 0;
 +				*szSlot = 0;
 +			}
 +			pSlot[0]++;
 +		}
 +	}
 +	mir_free(pContacts);
 +	return true;
  }
  // worker thread to clear MRU, called by the IPC bridge
 -procedure ClearMRUThread(notused: Pointer); cdecl;
 -{$DEFINE SHL_IDC}
 -{$DEFINE SHL_KEYS}
 -{$INCLUDE shlc.inc}
 -{$UNDEF SHL_KEYS}
 -{$UNDEF SHL_IDC}
 -
 -  hContact: HANDLE;
 +void __cdecl ClearMRUThread(void*)
  {
 -  {
 -    hContact = db_find_first();
 -    while hContact != 0 do
 -    {
 -      if DBGetContactSettingByte(hContact, SHLExt_Name, SHLExt_MRU, 0) > 0 
 -      {
 -        DBWriteContactSettingByte(hContact, SHLExt_Name, SHLExt_MRU, 0);
 -      }
 -      hContact = db_find_next(hContact);
 -    }
 -  }
 +	for (HANDLE hContact = db_find_first(); hContact != 0; hContact = db_find_next(hContact))
 +		if ( db_get_b(hContact, SHLExt_Name, SHLExt_MRU, 0) > 0)
 +			db_set_b(hContact, SHLExt_Name, SHLExt_MRU, 0);
  }
  // this function is called from an APC into the main thread
 -procedure ipcService(dwParam: DWORD); stdcall;
 -label
 -  Reply;
 -
 -  hMap: HANDLE;
 -  pMMT: THeaderIPC *;
 -  hSignal: HANDLE;
 -  pct: TSlotIPC *;
 -  szBuf: LPSTR;
 -  iSlot: Integer;
 -  szGroupStr: array [0 .. 31] of Char;
 -  dbv: TDBVariant;
 -  bits: pint;
 -  bGroupMode: Boolean;
 -  cloned: THeaderIPC *;
 -  szMiranda: LPSTR;
 +void __stdcall ipcService(ULONG_PTR dwParam)
  {
 -  { try to open the file mapping object the caller must make sure no other
 -    running instance is using this file }
 -  hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, IPC_PACKET_NAME);
 -  if hMap != 0 
 -  {
 -    { map the file to this process }
 -    pMMT = MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 -    { if it fails the caller should of had some timeout in wait }
 -    if (pMMT != NULL) && (pMMT->cbSize = sizeof(THeaderIPC)) &&
 -      (pMMT->dwVersion = PLUGIN_MAKE_VERSION(2, 0, 1, 2)) 
 -    {
 -      // toggle the right bits
 -      bits = @pMMT->fRequests;
 -      // jump right to a worker thread for file processing?
 -      if (bits^ && REQUEST_XFRFILES) = REQUEST_XFRFILES 
 -      {
 -        GetMem(cloned, IPC_PACKET_SIZE);
 -        // translate from client space to cloned heap memory
 -        pMMT->pServerBaseAddress = pMMT->pClientBaseAddress;
 -        pMMT->pClientBaseAddress = cloned;
 -        CopyMemory(cloned, pMMT, IPC_PACKET_SIZE);
 -        ipcFixupAddresses(true, cloned);
 -        DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
 -          @cloned->Param, THREAD_SET_CONTEXT, false, 0);
 -        mir_forkThread(@IssueTransferThread, cloned);
 -        goto Reply;
 -      }
 -      // the request was to clear the MRU entries, we have no return data
 -      if (bits^ && REQUEST_CLEARMRU) = REQUEST_CLEARMRU 
 -      {
 -        mir_forkThread(@ClearMRUThread, NULL);
 -        goto Reply;
 -      }
 -      // the IPC header may have pointers that need to be translated
 -      // in either case the supplied data area pointers has to be
 -      // translated to this address space.
 -      // the server base address is always removed to get an offset
 -      // to which the client base is added, this is what ipcFixupAddresses() does
 -      pMMT->pServerBaseAddress = pMMT->pClientBaseAddress;
 -      pMMT->pClientBaseAddress = pMMT;
 -      // translate to the server space map
 -      ipcFixupAddresses(true, pMMT);
 -      // store the address map offset so the caller can retranslate
 -      pMMT->pServerBaseAddress = pMMT;
 -      // return some options to the client
 -      if DBGetContactSettingByte(0, SHLExt_Name, SHLExt_ShowNoIcons, 0) != 0 
 -      {
 -        pMMT->dwFlags = HIPC_NOICONS;
 -      }
 -      // see if we have a custom string for 'Miranda'
 -      szMiranda = Translate('Miranda');
 -      lstrcpyn(pMMT->MirandaName, szMiranda, sizeof(pMMT->MirandaName) - 1);
 -
 -      // for the MRU menu
 -      szBuf = Translate('Recently');
 -      lstrcpyn(pMMT->MRUMenuName, szBuf, sizeof(pMMT->MRUMenuName) - 1);
 -
 -      // && a custom string for "clear entries"
 -      szBuf = Translate('Clear entries');
 -      lstrcpyn(pMMT->ClearEntries, szBuf, sizeof(pMMT->ClearEntries) - 1);
 -
 -      // if the group mode is on, check if they want the CList setting
 -      bGroupMode = BST_CHECKED = DBGetContactSettingByte(0, SHLExt_Name, SHLExt_UseGroups,
 -        BST_UNCHECKED);
 -      if bGroupMode && (BST_CHECKED = DBGetContactSettingByte(0, SHLExt_Name,
 -        SHLExt_UseCListSetting, BST_UNCHECKED)) 
 -      {
 -        bGroupMode = 1 = DBGetContactSettingByte(0, 'CList', 'UseGroups', 0);
 -      }
 -      iSlot = 0;
 -      // return profile if set
 -      if BST_UNCHECKED = DBGetContactSettingByte(0, SHLExt_Name, SHLExt_ShowNoProfile,
 -        BST_UNCHECKED) 
 -      {
 -        pct = ipcAlloc(pMMT, 50);
 -        if pct != NULL 
 -        {
 -          // will actually return with .dat if there's space for it, not what the docs say
 -          pct->Status = STATUS_PROFILENAME;
 -          CallService(MS_DB_GETPROFILENAME, 49, UINT_PTR(pct) + sizeof(TSlotIPC));
 -        } // if
 -      } // if
 -      if (bits^ && REQUEST_NEWICONS) = REQUEST_NEWICONS 
 -      {
 -        ipcGetSkinIcons(pMMT);
 -      }
 -      if (bits^ && REQUEST_GROUPS = REQUEST_GROUPS) 
 -      {
 -        // return contact's grouping if it's present
 -        while bGroupMode do
 -        {
 -          str(iSlot, szGroupStr);
 -          if DBGetContactSetting(0, 'CListGroups', szGroupStr, @dbv) != 0 
 -            break;
 -          pct = ipcAlloc(pMMT, lstrlenA(dbv.szVal.a + 1) + 1);
 -          // first byte has flags, need null term
 -          if pct != NULL 
 -          {
 -            if pMMT->GroupsBegin = NULL 
 -              pMMT->GroupsBegin = pct;
 -            pct->fType = REQUEST_GROUPS;
 -            pct->hContact = 0;
 -            UINT_PTR(szBuf) = UINT_PTR(pct) + sizeof(TSlotIPC); // get the } of the slot
 -            lstrcpyA(szBuf, dbv.szVal.a + 1);
 -            pct->hGroup = 0;
 -            DBFreeVariant(@dbv); // free the string
 -          }
 -          else
 -          {
 -            // outta space
 -            DBFreeVariant(@dbv);
 -            break;
 -          } // if
 -          inc(iSlot);
 -        } { while }
 -        // if there was no space left, it'll } on null
 -        if pct = NULL 
 -          bits^ = (bits^ | GROUPS_NOTIMPL) && not REQUEST_GROUPS;
 -      } { if: group request }
 -      // SHOULD check slot space.
 -      if (bits^ && REQUEST_CONTACTS = REQUEST_CONTACTS) 
 -      {
 -        if not ipcGetSortedContacts(pMMT, @iSlot, bGroupMode) 
 -        {
 -          // fail if there were no contacts AT ALL
 -          bits^ = (bits^ | CONTACTS_NOTIMPL) && not REQUEST_CONTACTS;
 -        } // if
 -      } // if:contact request
 -      // store the number of slots allocated
 -      pMMT->Slots = iSlot;
 -    Reply:
 -      { get the handle the caller wants to be signalled on }
 -      hSignal = OpenEvent(EVENT_ALL_ACCESS, false, pMMT->SignalEventName);
 -      { did it open? }
 -      if hSignal != 0 
 -      {
 -        { signal && close }
 -        SetEvent(hSignal);
 -        CloseHandle(hSignal);
 -      }
 -      { unmap the shared memory from this process }
 -      UnmapViewOfFile(pMMT);
 -    }
 -    { close the map file }
 -    CloseHandle(hMap);
 -  } { if }
 -  //
 -}
 +	HANDLE hSignal;
 +	TSlotIPC *pct;
 +	LPSTR szBuf;
 +	char szGroupStr[32];
 +	DBVARIANT dbv;
 +	LPSTR szMiranda;
 +
 +	// try to open the file mapping object the caller must make sure no other
 +	// running instance is using this file
 +	HANDLE hMap = OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, IPC_PACKET_NAME);
 +	if (hMap == 0)
 +		return;
 -procedure ThreadServer(hMainThread: Pointer); cdecl;
 +	// map the file to this process
 +	THeaderIPC *pMMT = (THeaderIPC*)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
 +	// if it fails the caller should of had some timeout in wait
 +	if (pMMT != NULL && pMMT->cbSize == sizeof(THeaderIPC) && pMMT->dwVersion == PLUGIN_MAKE_VERSION(2, 0, 1, 2)) {
 +		// toggle the right bits
 +		int *bits = &pMMT->fRequests;
 +		// jump right to a worker thread for file processing?
 +		if (*bits & REQUEST_XFRFILES) {
 +			THeaderIPC *cloned = (THeaderIPC*)mir_alloc(IPC_PACKET_SIZE);
 +			// translate from client space to cloned heap memory
 +			pMMT->pServerBaseAddress = pMMT->pClientBaseAddress;
 +			pMMT->pClientBaseAddress = cloned;
 +			CopyMemory(cloned, pMMT, IPC_PACKET_SIZE);
 +			ipcFixupAddresses(true, cloned);
 +			DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &cloned->Param, THREAD_SET_CONTEXT, false, 0);
 +			mir_forkthread(&IssueTransferThread, cloned);
 +			goto Reply;
 +		}
 +		// the request was to clear the MRU entries, we have no return data
 +		if (*bits & REQUEST_CLEARMRU) {
 +			mir_forkthread(&ClearMRUThread, NULL);
 +			goto Reply;
 +		}
 +		// the IPC header may have pointers that need to be translated
 +		// in either case the supplied data area pointers has to be
 +		// translated to this address space.
 +		// the server base address is always removed to get an offset
 +		// to which the client base is added, this is what ipcFixupAddresses() does
 +		pMMT->pServerBaseAddress = pMMT->pClientBaseAddress;
 +		pMMT->pClientBaseAddress = pMMT;
 +		// translate to the server space map
 +		ipcFixupAddresses(true, pMMT);
 +		// store the address map offset so the caller can retranslate
 +		pMMT->pServerBaseAddress = pMMT;
 +		// return some options to the client
 +		if (db_get_b(0, SHLExt_Name, SHLExt_ShowNoIcons, 0) != 0)
 +			pMMT->dwFlags = HIPC_NOICONS;
 +
 +		// see if we have a custom string for 'Miranda'
 +		szMiranda = Translate("Miranda");
 +		lstrcpynA(pMMT->MirandaName, szMiranda, sizeof(pMMT->MirandaName) - 1);
 +
 +		// for the MRU menu
 +		szBuf = Translate("Recently");
 +		lstrcpynA(pMMT->MRUMenuName, szBuf, sizeof(pMMT->MRUMenuName) - 1);
 +
 +		// && a custom string for "clear entries"
 +		szBuf = Translate("Clear entries");
 +		lstrcpynA(pMMT->ClearEntries, szBuf, sizeof(pMMT->ClearEntries) - 1);
 +
 +		// if the group mode is on, check if they want the CList setting
 +		bool bGroupMode = (BST_CHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseGroups, BST_UNCHECKED));
 +		if (bGroupMode && BST_CHECKED == db_get_b(0, SHLExt_Name, SHLExt_UseCListSetting, BST_UNCHECKED)) 
 +			bGroupMode = (1 == db_get_b(0, "CList", "UseGroups", 0));
 +
 +		int iSlot = 0;
 +		// return profile if set
 +		if (BST_UNCHECKED == db_get_b(0, SHLExt_Name, SHLExt_ShowNoProfile, BST_UNCHECKED)) {
 +			pct = ipcAlloc(pMMT, 50);
 +			if (pct != NULL) {
 +				// will actually return with .dat if there's space for it, not what the docs say
 +				pct->Status = STATUS_PROFILENAME;
 +				CallService(MS_DB_GETPROFILENAME, 49, UINT_PTR(pct) + sizeof(TSlotIPC));
 +			}
 +		}
 +		if (*bits & REQUEST_NEWICONS)
 +			ipcGetSkinIcons(pMMT);
 +
 +		if (*bits & REQUEST_GROUPS) {
 +			// return contact's grouping if it's present
 +			while (bGroupMode) {
 +				_itoa(iSlot, szGroupStr, 10);
 +				if ( db_get_s(0, "CListGroups", szGroupStr, &dbv) != 0)
 +					break;
 +				pct = ipcAlloc(pMMT, lstrlenA(dbv.pszVal + 1) + 1);
 +				// first byte has flags, need null term
 +				if (pct != NULL) {
 +					if (pMMT->GroupsBegin == NULL)
 +						pMMT->GroupsBegin = pct;
 +					pct->fType = REQUEST_GROUPS;
 +					pct->hContact = 0;
 +					szBuf = LPSTR(pct) + sizeof(TSlotIPC); // get the end of the slot
 +					lstrcpyA(szBuf, dbv.pszVal + 1);
 +					pct->hGroup = 0;
 +					db_free(&dbv); // free the string
 +				}
 +				else {
 +					// outta space
 +					db_free(&dbv);
 +					break;
 +				}
 +				iSlot++;
 +			}
 +			// if there was no space left, it'll } on null
 +			if (pct == NULL)
 +				*bits = (*bits | GROUPS_NOTIMPL) & ~REQUEST_GROUPS;
 +		}
 +		// SHOULD check slot space.
 +		if (*bits & REQUEST_CONTACTS) {
 +			if (!ipcGetSortedContacts(pMMT, &iSlot, bGroupMode))
 +				// fail if there were no contacts AT ALL
 +				*bits = (*bits | CONTACTS_NOTIMPL) & ~REQUEST_CONTACTS;
 +		}
 +		// store the number of slots allocated
 +		pMMT->Slots = iSlot;
 +Reply:
 +		// get the handle the caller wants to be signalled on 
 +		hSignal = OpenEventA(EVENT_ALL_ACCESS, false, pMMT->SignalEventName);
 +		if (hSignal != 0) {
 +			SetEvent(hSignal);
 +			CloseHandle(hSignal);
 +		}
 -  hEvent: HANDLE;
 -  retVal: Cardinal;
 -{
 -  hEvent = CreateEvent(NULL, false, false, LPSTR(CreateProcessUID(GetCurrentProcessId())));
 -  while true do
 -  {
 -    retVal = WaitForSingleObjectEx(hEvent, INFINITE, true);
 -    if retVal = WAIT_OBJECT_0 
 -    {
 -      QueueUserAPC(@ipcService, HANDLE(hMainThread), 0);
 -    } // if
 -    if CallService(MS_SYSTEM_TERMINATED, 0, 0) = 1 
 -      break;
 -  } // while
 -  CloseHandle(hEvent);
 -  CloseHandle(HANDLE(hMainThread));
 +		UnmapViewOfFile(pMMT);
 +	}
 +	CloseHandle(hMap);
  }
 -procedure InvokeThreadServer;
 -
 -  hMainThread: HANDLE;
 +void __cdecl ThreadServer(HANDLE hMainThread)
  {
 -  hMainThread = 0;
 -  DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), @hMainThread,
 -    THREAD_SET_CONTEXT, false, 0);
 -  if hMainThread != 0 
 -    mir_forkThread(@ThreadServer, Pointer(hMainThread));
 -}
 -
 -{ exported functions }
 +	HANDLE hEvent = CreateEventA(NULL, false, false, CreateProcessUID(GetCurrentProcessId()).c_str());
 +	while (true) {
 +		int retVal = WaitForSingleObjectEx(hEvent, INFINITE, true);
 +		if (retVal == WAIT_OBJECT_0)
 +			QueueUserAPC(ipcService, hMainThread, 0);
 -function DllGetClassObject(const CLSID: TCLSID; const IID: TIID;  Obj): HResult; stdcall;
 -{
 -  Pointer(Obj) = NULL;
 -  Result = CLASS_E_CLASSNOTAVAILABLE;
 -  if (IsEqualCLSID(CLSID, CLSID_ISHLCOM)) && (IsEqualIID(IID, IID_IClassFactory)) &&
 -    (FindWindow(MirandaName, NULL) != 0) 
 -  {
 -    Pointer(Obj) = TClassFactoryRec_Create;
 -    Result = S_OK;
 -  } // if
 +		if (CallService(MS_SYSTEM_TERMINATED, 0, 0) == 1)
 +			break;
 +	}
 +	CloseHandle(hEvent);
 +	CloseHandle(hMainThread);
  }
 -function DllCanUnloadNow: HResult;
 +void InvokeThreadServer()
  {
 -  if ((dllpublic.FactoryCount = 0) && (dllpublic.ObjectCount = 0)) 
 -  {
 -    Result = S_OK;
 -  }
 -  else
 -  {
 -    Result = S_FALSE;
 -  } // if
 +	HANDLE hMainThread = 0;
 +	DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, THREAD_SET_CONTEXT, false, 0);
 +	if (hMainThread != 0)
 +		mir_forkthread(&ThreadServer, hMainThread);
  }
 -{ helper functions }
 -
 -type
 -
 -  PSHELLEXECUTEINFO = ^TSHELLEXECUTEINFO;
 -
 -  TSHELLEXECUTEINFO = record
 -    cbSize: DWORD;
 -    fMask: LongInt;
 -    hwnd: HANDLE;
 -    lpVerb: LPSTR;
 -    lpFile: LPSTR;
 -    lpParameters: LPSTR;
 -    lpDirectory: LPSTR;
 -    nShow: Integer;
 -    hInstApp: HANDLE;
 -    lpIDLIst: Pointer;
 -    lpClass: LPSTR;
 -    HKEY: HANDLE;
 -    dwHotkey: DWORD;
 -    HICON: HANDLE; // is union
 -    hProcess: HANDLE;
 -  }
 +// exported functions
 -function ShellExecuteEx( se: TSHELLEXECUTEINFO): Boolean; stdcall;
 -  external 'shell32.dll' name 'ShellExecuteExA';
 +const IID CLSID_ISHLCOM = { 0x72013A26, 0xA94C, 0x11d6, {0x85, 0x40, 0xA5, 0xE6, 0x29, 0x32, 0x71, 0x1D }};
 -function wsprintfs(lpOut, lpFmt: LPSTR; args: LPSTR): Integer; cdecl;
 -  external 'user32.dll' name 'wsprintfA';
 +HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
 +{
 +	if (rclsid == CLSID_ISHLCOM && riid == IID_IClassFactory && FindWindowA(MIRANDANAME, NULL) != 0) {
 +		*ppv = new TClassFactoryRec();
 +		return S_OK;
 +	}
 -function RemoveCOMRegistryEntries: HResult;
 +	*ppv = NULL;
 +	return CLASS_E_CLASSNOTAVAILABLE;
 +}
 -  hRootKey: HKEY;
 +HRESULT DllCanUnloadNow()
  {
 -  if RegOpenKeyEx(HKEY_CLASSES_ROOT, 'miranda.shlext', 0, KEY_READ, hRootKey) = ERROR_SUCCESS
 -  
 -  {
 -    (* need to delete the subkey before the parent key is deleted under NT/2000/XP *)
 -    RegDeleteKey(hRootKey, 'CLSID');
 -    (* close the key *)
 -    RegCloseKey(hRootKey);
 -    (* delete it *)
 -    if RegDeleteKey(HKEY_CLASSES_ROOT, 'miranda.shlext') != ERROR_SUCCESS 
 -    {
 -      MessageBox(0,
 -        'Unable to delete registry key for "shlext COM", this key may already be deleted | you may need admin rights.',
 -        'Problem', MB_ICONERROR);
 -    } // if
 -  } // if
 -  if RegOpenKeyEx(HKEY_CLASSES_ROOT, '\*\shellex\ContextMenuHandlers', 0, KEY_ALL_ACCESS,
 -    hRootKey) = ERROR_SUCCESS 
 -  {
 -    if RegDeleteKey(hRootKey, 'miranda.shlext') != ERROR_SUCCESS 
 -    {
 -      MessageBox(0,
 -        'Unable to delete registry key for "File context menu handlers", this key may already be deleted | you may need admin rights.',
 -        'Problem', MB_ICONERROR);
 -    } // if
 -    RegCloseKey(hRootKey);
 -  } // if
 -  if RegOpenKeyEx(HKEY_CLASSES_ROOT, 'Directory\shellex\ContextMenuHandlers', 0, KEY_ALL_ACCESS,
 -    hRootKey) = ERROR_SUCCESS 
 -  {
 -    if RegDeleteKey(hRootKey, 'miranda.shlext') != ERROR_SUCCESS 
 -    {
 -      MessageBox(0,
 -        'Unable to delete registry key for "Directory context menu handlers", this key may already be deleted | you may need admin rights.',
 -        'Problem', MB_ICONERROR);
 -    } // if
 -    RegCloseKey(hRootKey);
 -  } // if
 -  if ERROR_SUCCESS = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
 -    'Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved', 0, KEY_ALL_ACCESS,
 -    hRootKey) 
 -  {
 -    if RegDeleteValue(hRootKey, '{72013A26-A94C-11d6-8540-A5E62932711D}') != ERROR_SUCCESS 
 -    {
 -      MessageBox(0,
 -        'Unable to delete registry entry for "Approved context menu handlers", this key may already be deleted | you may need admin rights.',
 -        'Problem', MB_ICONERROR);
 -    } // if
 -    RegCloseKey(hRootKey);
 -  } // if
 -  Result = S_OK;
 +	if (dllpublic.FactoryCount == 0 && dllpublic.ObjectCount == 0)
 +		return S_OK;
 +	return S_FALSE;
  }
 -{ called by the options code to remove COM entries, && before that, get permission, if required.
 +// helper functions
 +
 +HRESULT RemoveCOMRegistryEntries()
 +{
 +	HKEY hRootKey;
 +	if ( !RegOpenKeyExA(HKEY_CLASSES_ROOT, "miranda.shlext", 0, KEY_READ, &hRootKey)) {
 +		// need to delete the subkey before the parent key is deleted under NT/2000/XP
 +		RegDeleteKeyA(hRootKey, "CLSID");
 +		// close the key
 +		RegCloseKey(hRootKey);
 +		// delete it
 +		if ( RegDeleteKeyA(HKEY_CLASSES_ROOT, "miranda.shlext") != ERROR_SUCCESS)
 +			MessageBoxA(0,
 +				"Unable to delete registry key for 'shlext COM', this key may already be deleted or you may need admin rights.",
 +				"Problem", MB_ICONERROR);
 +	}
 +	if ( !RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\*\\shellex\\ContextMenuHandlers", 0, KEY_ALL_ACCESS, &hRootKey)) {
 +		if ( RegDeleteKeyA(hRootKey, "miranda.shlext") != ERROR_SUCCESS)
 +			MessageBoxA(0,
 +				"Unable to delete registry key for 'File context menu handlers', this key may already be deleted or you may need admin rights.",
 +				"Problem", MB_ICONERROR);
 +		RegCloseKey(hRootKey);
 +	}
 +	if ( !RegOpenKeyExA(HKEY_CLASSES_ROOT, "Directory\\shellex\\ContextMenuHandlers", 0, KEY_ALL_ACCESS, &hRootKey)) {
 +		if ( RegDeleteKeyA(hRootKey, "miranda.shlext") != ERROR_SUCCESS)
 +			MessageBoxA(0,
 +				"Unable to delete registry key for 'Directory context menu handlers', this key may already be deleted or you may need admin rights.",
 +				"Problem", MB_ICONERROR);
 +		RegCloseKey(hRootKey);
 +	}
 +	if ( !RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", 0, KEY_ALL_ACCESS, &hRootKey)) {
 +		if ( !RegDeleteValueA(hRootKey, "{72013A26-A94C-11d6-8540-A5E62932711D}") != ERROR_SUCCESS) {
 +			MessageBoxA(0,
 +				"Unable to delete registry entry for 'Approved context menu handlers', this key may already be deleted | you may need admin rights.",
 +				"Problem", MB_ICONERROR);
 +		}
 +		RegCloseKey(hRootKey);
 +	}
 +	return S_OK;
  }
 -procedure CheckUnregisterServer;
 +// called by the options code to remove COM entries, && before that, get permission, if required.
 -  sei: TSHELLEXECUTEINFO;
 -  szBuf: array [0 .. MAX_PATH * 2] of Char;
 -  szFileName: array [0 .. MAX_PATH] of Char;
 +void CheckUnregisterServer()
  {
 -  if not VistaOrLater 
 -  {
 -    RemoveCOMRegistryEntries();
 -    Exit;
 -  }
 -  // launches regsvr to remove the dll under admin.
 -  GetModuleFileName(System.hInstance, szFileName, sizeof(szFileName));
 -  wsprintfs(szBuf, '/s /u "%s"', szFileName);
 -  ZeroMemory(@sei, sizeof(sei));
 -  sei.cbSize = sizeof(sei);
 -  sei.lpVerb = 'runas';
 -  sei.lpFile = 'regsvr32';
 -  sei.lpParameters = szBuf;
 -  ShellExecuteEx(sei);
 -  Sleep(1000);
 -  RemoveCOMRegistryEntries();
 +	if (VistaOrLater) {
 +		// launches regsvr to remove the dll under admin.
 +		char szFileName[MAX_PATH], szBuf[MAX_PATH * 2];
 +		GetModuleFileNameA(hInst, szFileName, SIZEOF(szFileName));
 +		mir_snprintf(szBuf, sizeof(szBuf), "/s /u \"%s\"", szFileName);
 +
 +		SHELLEXECUTEINFOA sei = { 0 };
 +		sei.cbSize = sizeof(sei);
 +		sei.lpVerb = "runas";
 +		sei.lpFile = "regsvr32";
 +		sei.lpParameters = szBuf;
 +		ShellExecuteExA(&sei);
 +		Sleep(1000);
 +	}
 +	RemoveCOMRegistryEntries();
  }
 -{ Wow, I can't believe there isn't a direct API for this - 'runas' will invoke the UAC && ask
 -  for permission before installing the shell extension.  note the filepath arg has to be quoted }
 -procedure CheckRegisterServer;
 +// Wow, I can't believe there isn't a direct API for this - 'runas' will invoke the UAC && ask
 +// for permission before installing the shell extension.  note the filepath arg has to be quoted }
 -  hRegKey: HKEY;
 -  sei: TSHELLEXECUTEINFO;
 -  szBuf: array [0 .. MAX_PATH * 2] of Char;
 -  szFileName: array [0 .. MAX_PATH] of Char;
 +void CheckRegisterServer()
  {
 -  if ERROR_SUCCESS = RegOpenKeyEx(HKEY_CLASSES_ROOT, 'miranda.shlext', 0, KEY_READ, hRegKey)
 -  
 -  {
 -    RegCloseKey(hRegKey);
 -  }
 -  else
 -  {
 -    if VistaOrLater 
 -    {
 -      MessageBox(0,
 -        'Shell context menus requires your permission to register with Windows Explorer (one time only).',
 -        'Miranda IM - Shell context menus (shlext.dll)', MB_OK | MB_ICONINFORMATION);
 -      // /s = silent
 -      GetModuleFileName(System.hInstance, szFileName, sizeof(szFileName));
 -      wsprintfs(szBuf, '/s "%s"', szFileName);
 -      ZeroMemory(@sei, sizeof(sei));
 -      sei.cbSize = sizeof(sei);
 -      sei.lpVerb = 'runas';
 -      sei.lpFile = 'regsvr32';
 -      sei.lpParameters = szBuf;
 -      ShellExecuteEx(sei);
 -    }
 -  }
 +	char szFileName[MAX_PATH], szBuf[MAX_PATH * 2];
 +
 +	HKEY hRegKey;
 +	if ( !RegOpenKeyExA(HKEY_CLASSES_ROOT, "miranda.shlext", 0, KEY_READ, &hRegKey))
 +		RegCloseKey(hRegKey);
 +	else if (VistaOrLater) {
 +		MessageBoxA(0,
 +			"Shell context menus requires your permission to register with Windows Explorer (one time only).",
 +			"Miranda NG - Shell context menus (shellext.dll)", MB_OK | MB_ICONINFORMATION);
 +		// /s = silent
 +		GetModuleFileNameA(hInst, szFileName, sizeof(szFileName));
 +		mir_snprintf(szBuf, sizeof(szBuf), "/s \"%s\"", szFileName);
 +
 +		SHELLEXECUTEINFOA sei = { 0 };
 +		sei.cbSize = sizeof(sei);
 +		sei.lpVerb = "runas";
 +		sei.lpFile = "regsvr32";
 +		sei.lpParameters = szBuf;
 +		ShellExecuteExA(&sei);
 +	}
  }
 diff --git a/plugins/ShellExt/src/shlcom.h b/plugins/ShellExt/src/shlcom.h index 6aa7377e8c..01461acd8d 100644 --- a/plugins/ShellExt/src/shlcom.h +++ b/plugins/ShellExt/src/shlcom.h @@ -94,16 +94,17 @@ struct TSlotIPC  struct THeaderIPC
  {
 -	int cbSize;
 -	DWORD dwVersion;
 -	void *pServerBaseAddress, *pClientBaseAddress;
 -	int   fRequests;
 -	DWORD dwFlags;
 -	int   Slots, Cardinal;
 -	char  SignalEventName[64];
 -	char  MirandaName[64];
 -	char  MRUMenuName[64];
 -	char  ClearEntries[64];
 +	int    cbSize;
 +	DWORD  dwVersion;
 +	void  *pServerBaseAddress, *pClientBaseAddress;
 +	int    fRequests;
 +	DWORD  dwFlags;
 +	int    Slots;
 +	HANDLE Param;
 +	char   SignalEventName[64];
 +	char   MirandaName[64];
 +	char   MRUMenuName[64];
 +	char   ClearEntries[64];
  	TSlotIPC *IconsBegin, *ContactsBegin, *GroupsBegin, *NewIconsBegin;
  	// start of an flat memory stack, which is referenced as a linked list
  	int DataSize;
 diff --git a/plugins/ShellExt/src/stdafx.h b/plugins/ShellExt/src/stdafx.h index 3c231ae4b1..d84021d3e6 100644 --- a/plugins/ShellExt/src/stdafx.h +++ b/plugins/ShellExt/src/stdafx.h @@ -5,12 +5,18 @@  #include <ShlObj.h>
  #include <Wincodec.h>
 +#include <string.h>
  #include <string>
  #include <newpluginapi.h>
  #include <m_system_cpp.h>
  #include <m_protocols.h>
 +#include <m_protosvc.h>
 +#include <m_file.h>
 +#include <m_ignore.h>
 +#include <m_skin.h>
 +#include <m_clist.h>
  #include <m_langpack.h>
  #include <m_options.h>
  #include <m_database.h>
  | 
