// TrayWnd.cpp : implementation file // #include "stdafx.h" #include "DenAgent.h" #include "TrayWnd.h" #include "..\Inject\InjectApi.h" #include "forcelib.h" #include "DenAgentDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define ID_SYSTRAY 1 #define NM_SYSTRAY ( WM_USER + 1000 ) const UINT s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); bool g_bOldInject; // Inject Enable/Inject Disable function pointers typedef void (*VoidNoParams)(); VoidNoParams InjEnable = NULL; VoidNoParams InjDisable = NULL; // HMODULE for Inject dll HMODULE g_hInj = NULL; // This is for our windows enumeration process BOOL CALLBACK EnumerationCallbackProc( HWND, LPARAM ); CTrayWnd* CTrayWnd::s_pWnd = NULL; ///////////////////////////////////////////////////////////////////////////// // CTrayWnd CTrayWnd::CTrayWnd() : m_pDialog( NULL ), m_uiTimer( NULL ) { s_pWnd = this; } CTrayWnd::~CTrayWnd() { s_pWnd = NULL; } BEGIN_MESSAGE_MAP(CTrayWnd, CWnd) //{{AFX_MSG_MAP(CTrayWnd) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_TIMER() ON_COMMAND(ID_SYSTRAY_CONFIGURE, OnSystrayConfigure) ON_COMMAND(ID_SYSTRAY_EXIT, OnSystrayExit) ON_REGISTERED_MESSAGE(s_uTaskbarRestart, OnTaskbarRestart) //}}AFX_MSG_MAP ON_MESSAGE(NM_SYSTRAY, OnSysTray) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTrayWnd message handlers LRESULT CTrayWnd::OnTaskbarRestart(WPARAM, LPARAM) { NOTIFYICONDATA nid; ::memset( &nid, 0, sizeof( NOTIFYICONDATA ) ); nid.cbSize = sizeof( NOTIFYICONDATA ); nid.hWnd = m_hWnd; nid.uID = ID_SYSTRAY; nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; nid.uCallbackMessage = NM_SYSTRAY; nid.hIcon = AfxGetApp()->LoadIcon( IDR_TRAYICON ); ::_tcscpy( nid.szTip, _T( "Decal Agent" ) ); ::Shell_NotifyIcon( NIM_DELETE, &nid ); ::Shell_NotifyIcon( NIM_ADD, &nid ); DestroyIcon(nid.hIcon); return TRUE; } void CTrayWnd::showDialog() { if( m_pDialog == NULL ) { CDenAgentDlg dlg; m_pDialog = &dlg; dlg.DoModal(); m_pDialog = NULL; } else { m_pDialog->SetForegroundWindow(); m_pDialog->BringWindowToTop(); } } int CTrayWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; ::CoInitialize( NULL ); // Check if asheron's call is already running HWND wndAC = ::FindWindowEx( NULL, NULL, _T( "Asheron's Call" ), _T( "Asheron's Call" ) ); bEnabled = ( wndAC == NULL ); if( wndAC != NULL ) { ::AfxMessageBox( _T( "Asheron's Call was started before the Agent.\r\nNo plugins will be installed until Asheron's Call and the agent are exited and restarted.\r\n\r\nThe Agent must be run before Asheron's Call to properly install plugins." ), MB_ICONERROR | MB_OK ); ::PostQuitMessage( 0 ); } else { RegKey key; DWORD dwOldInj; if( key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal" )) != ERROR_SUCCESS ) { g_bOldInject = false; m_uiTimer = SetTimer (1, 1000, NULL); } else { if( key.QueryDWORDValue( "OldInjection", dwOldInj ) == ERROR_SUCCESS ) { if( dwOldInj == 1 ) { g_bOldInject = true; TCHAR szInjectDll[ MAX_PATH ]; memset( szInjectDll, 0, sizeof( szInjectDll ) / sizeof( szInjectDll[0] ) ); // Open the COM CoClass for IPager to get Inject.dll path if( key.Open( HKEY_CLASSES_ROOT, _T( "CLSID\\{C79E2F76-06F8-4CD0-A613-4829237D297D}\\InprocServer32" ), KEY_READ ) == ERROR_SUCCESS ) { DWORD dwChars = MAX_PATH - 1; if( key.QueryStringValue( NULL, szInjectDll, &dwChars ) != ERROR_SUCCESS ) { ::AfxMessageBox( _T( "There is a serious problem with the Decal Agent registry settings!!\n\nExiting." ), MB_ICONERROR | MB_OK ); ::PostQuitMessage( 0 ); } } g_hInj = LoadLibrary( szInjectDll ); InjEnable = (VoidNoParams) GetProcAddress( g_hInj, (LPCSTR) 0x00000012 ); InjDisable = (VoidNoParams) GetProcAddress( g_hInj, (LPCSTR) 0x00000011 ); if( !InjEnable || !InjDisable ) { ::AfxMessageBox( _T( "Can't load Inject.dll. Please turn off old style injection." ), MB_ICONERROR | MB_OK ); g_bOldInject = false; } else ::InjEnable(); } else { g_bOldInject = false; m_uiTimer = SetTimer( 1, 1000, NULL ); } } else { g_bOldInject = false; m_uiTimer = SetTimer( 1, 1000, NULL ); } } } // Create the system tray icon NOTIFYICONDATA nid; ::memset( &nid, 0, sizeof( NOTIFYICONDATA ) ); nid.cbSize = sizeof( NOTIFYICONDATA ); nid.hWnd = m_hWnd; nid.uID = ID_SYSTRAY; nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; nid.uCallbackMessage = NM_SYSTRAY; nid.hIcon = AfxGetApp()->LoadIcon( IDR_TRAYICON ); ::_tcscpy( nid.szTip, _T( "Decal Agent" ) ); ::Shell_NotifyIcon( NIM_ADD, &nid ); DestroyIcon(nid.hIcon); // Get the image path (path of parent executable) TCHAR szImagePath[ MAX_PATH ]; ::GetModuleFileName( NULL, szImagePath, MAX_PATH ); LPTSTR strProcessName = ::_tcsrchr( szImagePath, _T( '\\' ) ); *( strProcessName + 1 ) = _T( '\0' ); RegKey key; key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal\\Agent" ) ); key.SetStringValue( _T( "AgentPath" ), szImagePath ); return 0; } void CTrayWnd::OnDestroy() { CWnd::OnDestroy(); NOTIFYICONDATA nid; ::memset( &nid, 0, sizeof( NOTIFYICONDATA ) ); nid.cbSize = sizeof( NOTIFYICONDATA ); nid.hWnd = m_hWnd; nid.uID = ID_SYSTRAY; ::Shell_NotifyIcon( NIM_DELETE, &nid ); if( g_bOldInject ) { if( bEnabled ) ::InjDisable(); InjEnable = NULL; InjDisable = NULL; FreeLibrary( g_hInj ); } else if( m_uiTimer ) { KillTimer (m_uiTimer); m_uiTimer = 0; } ::CoUninitialize(); } void CTrayWnd::OnTimer (UINT_PTR nIDEvent) { ::EnumWindows( EnumerationCallbackProc, (LPARAM) NULL ); } BOOL CALLBACK EnumerationCallbackProc( HWND hwnd, LPARAM lParam ) { TCHAR szClassName[64]; memset( szClassName, 0, sizeof( szClassName ) / sizeof( szClassName[0] ) ); GetClassName( hwnd, szClassName, 64 ); if( _tcsicmp( _T( "ZoneLobbyWindow" ), szClassName ) != 0 ) { return TRUE; } if( CTrayWnd::s_pWnd != NULL ) return CTrayWnd::s_pWnd->OnEnum( hwnd ); else return FALSE; } BOOL CTrayWnd::OnEnum( HWND hWndLobby ) { if( hWndLobby != NULL ) { DWORD dwProcessId = 0; GetWindowThreadProcessId( hWndLobby, &dwProcessId ); if( dwProcessId != 0 ) { TCHAR tszBuffer [256]; ::_stprintf (tszBuffer, _T("__LOBBYHOOK_%d"), dwProcessId); HANDLE hLobbySemaphore = ::CreateSemaphore (NULL, 0, 1, tszBuffer); DWORD dwLastError = ::GetLastError (); if (hLobbySemaphore) { ::CloseHandle (hLobbySemaphore); if (dwLastError == ERROR_ALREADY_EXISTS) { // The lobbyhook has already been injected, we know because it created the semaphore. return TRUE; } } RegKey key; TCHAR szDll[ MAX_PATH ]; TCHAR szDllPath[ MAX_PATH ]; memset( szDllPath, 0, sizeof( szDllPath ) / sizeof( szDllPath[0] ) ); if( key.Open( HKEY_LOCAL_MACHINE, _T( "Software\\Decal\\Agent" ), KEY_READ ) == ERROR_SUCCESS ) { DWORD dwChars = MAX_PATH - 1; if( key.QueryStringValue( _T( "AgentPath" ), szDllPath, &dwChars ) == ERROR_SUCCESS ) { lstrcpy( szDll, szDllPath ); lstrcat( szDll, _T( "\\ForceLibrary.dll" ) ); } else { DWORD dwError = GetLastError(); char szBuffer[256]; _snprintf( szBuffer, sizeof( szBuffer ), "Couldn't query AgentPath value: 0x%08lx", dwError ); ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_OK ); } } else { DWORD dwError = GetLastError(); char szBuffer[256]; _snprintf( szBuffer, sizeof( szBuffer ), "Couldn't open HKLM\\Software\\Decal\\Agent key: 0x%08lx", dwError ); ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_OK ); } if( szDllPath[0] ) { HMODULE hLib = (HMODULE) ForceLibraryNow( dwProcessId, szDll ); if( hLib == NULL ) { DWORD dwError = GetLastError(); char szBuffer[256]; _snprintf( szBuffer, sizeof( szBuffer ), "ForceLibraryNow (LobbyHook.dll) has failed( 0x%08lx )\nDo you want to switch to old style injection?\nIf Decal is loading in AC properly answer no.", dwError ); // Kill timer to avoid 1000 popups KillTimer( m_uiTimer ); m_uiTimer = 0; int iRet = ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_YESNO ); if( iRet == IDYES ) { RegKey key; key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal" ) ); key.SetDWORDValue("OldInjection", 0x1L); g_bOldInject = true; TCHAR szInjectDll[ MAX_PATH ]; memset( szInjectDll, 0, sizeof( szInjectDll ) / sizeof( szInjectDll[0] ) ); // Open the COM CoClass for IPager to get Inject.dll path if( key.Open( HKEY_CLASSES_ROOT, _T( "CLSID\\{C79E2F76-06F8-4CD0-A613-4829237D297D}\\InprocServer32" ), KEY_READ ) == ERROR_SUCCESS ) { DWORD dwChars = MAX_PATH - 1; if( key.QueryStringValue( NULL, szInjectDll, &dwChars ) != ERROR_SUCCESS ) { ::AfxMessageBox( _T( "There is a serious problem with the Decal Agent registry settings!!\n\nExiting." ), MB_ICONERROR | MB_OK ); ::PostQuitMessage( 0 ); } } g_hInj = LoadLibrary( szInjectDll ); InjEnable = (VoidNoParams) GetProcAddress( g_hInj, (LPCSTR) 0x00000012 ); InjDisable = (VoidNoParams) GetProcAddress( g_hInj, (LPCSTR) 0x00000011 ); ::InjEnable(); } else // no { _snprintf( szBuffer, sizeof( szBuffer ), "Lobby Injection halted... restart DenAgent to try again." ); ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_OK ); } } lstrcpy( szDll, szDllPath ); lstrcat( szDll, _T( "\\LobbyHook.dll" ) ); hLib = (HMODULE) ForceLibraryNow( dwProcessId, szDll ); if( hLib == NULL ) { DWORD dwError = GetLastError(); char szBuffer[256]; _snprintf( szBuffer, sizeof( szBuffer ), "ForceLibraryNow (LobbyHook.dll) has failed( 0x%08lx )\nDo you want to switch to old style injection?\nIf Decal is loading in AC properly answer no.", dwError ); // Kill timer KillTimer( m_uiTimer ); m_uiTimer = 0; int iRet = ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_YESNO ); if( iRet == IDYES ) { RegKey key; key.Create( HKEY_LOCAL_MACHINE, _T( "SOFTWARE\\Decal" ) ); key.SetDWORDValue("OldInjection", 0x1L); g_bOldInject = true; TCHAR szInjectDll[ MAX_PATH ]; memset( szInjectDll, 0, sizeof( szInjectDll ) / sizeof( szInjectDll[0] ) ); // Open the COM CoClass for IPager to get Inject.dll path if( key.Open( HKEY_CLASSES_ROOT, _T( "CLSID\\{C79E2F76-06F8-4CD0-A613-4829237D297D}\\InprocServer32" ), KEY_READ ) == ERROR_SUCCESS ) { DWORD dwChars = MAX_PATH - 1; if( key.QueryStringValue( NULL, szInjectDll, &dwChars ) != ERROR_SUCCESS ) { ::AfxMessageBox( _T( "There is a serious problem with the Decal Agent registry settings!!\n\nExiting." ), MB_ICONERROR | MB_OK ); ::PostQuitMessage( 0 ); } } g_hInj = LoadLibrary( szInjectDll ); InjEnable = (VoidNoParams) GetProcAddress( g_hInj, (LPCSTR) 0x00000012 ); InjDisable = (VoidNoParams) GetProcAddress( g_hInj, (LPCSTR) 0x00000011 ); ::InjEnable(); } else // no { _snprintf( szBuffer, sizeof( szBuffer ), "Lobby Injection halted... restart DenAgent to try again." ); ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_OK ); } } } else { DWORD dwError = GetLastError(); char szBuffer[256]; _snprintf( szBuffer, sizeof( szBuffer ), "DLL path was blank: 0x%08lx", dwError ); ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_OK ); } } else { DWORD dwError = GetLastError(); char szBuffer[256]; _snprintf( szBuffer, sizeof( szBuffer ), "Couldn't get process id: 0x%08lx", dwError ); ::MessageBox( NULL, szBuffer, _T( "DenAgent" ), MB_OK ); } } return TRUE; } LRESULT CTrayWnd::OnSysTray(WPARAM nID, LPARAM uMsg) { // We should only receive message for the one systray we register ASSERT( nID == ID_SYSTRAY ); switch( uMsg ) { case WM_RBUTTONUP: { POINT pt; ::GetCursorPos( &pt ); CMenu menu; menu.LoadMenu( IDR_POPUPS ); CMenu *pSystray = menu.GetSubMenu( 0 ); pSystray->SetDefaultItem( 0, TRUE ); SetForegroundWindow(); pSystray->TrackPopupMenu( TPM_RIGHTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this ); } break; case WM_LBUTTONUP: showDialog(); break; } return 0; } void CTrayWnd::OnSystrayConfigure() { showDialog(); } void CTrayWnd::OnSystrayExit() { DestroyWindow(); ::PostQuitMessage( 0 ); } void CTrayWnd::UpdateXMLFiles() { CDenAgentDlg dlg; m_pDialog = &dlg; dlg.m_bDoUpdate = true; dlg.DoModal( ); m_pDialog = NULL; }