|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// VPROJECT.CPP
//
//=====================================================================================//
#include "vproject.h"
#define MAX_PROJECTS 50
#define ID_PROJECTS_LISTVIEW 100
// column id
#define ID_PROJECT_NAME 0
#define ID_PROJECT_DIRECTORY 1
#define WM_TRAY (WM_APP + 1)
#define ID_TRAY 5000
#define ID_TRAY_ADDVPROJECT 6000
#define ID_TRAY_MODIFYVPROJECT 6001
#define ID_TRAY_MOVEUP 6002
#define ID_TRAY_MOVEDOWN 6003
#define ID_TRAY_EXIT 6004
typedef struct { char *pName; char *pGamedir; } project_t;
HWND g_hWnd; char g_project_name[256]; char g_project_gamedir[256]; HINSTANCE g_hInstance; project_t g_projects[MAX_PROJECTS]; int g_numProjects; NOTIFYICONDATA g_iconData; HMENU g_hMenu; int g_nActiveVProject; POINT g_cursorPoint;
void TrayMessageHandler( HWND hWnd, UINT uMessageID );
//-----------------------------------------------------------------------------
// SetVProject
//
//-----------------------------------------------------------------------------
void SetVProject( const char *pProjectName ) { char *pGamedir; char project[256]; int i;
if ( pProjectName ) { strcpy( project, pProjectName ); Sys_StripQuotesFromToken( project );
for ( i=0; i<g_numProjects; i++ ) { if ( !stricmp( g_projects[i].pName, project ) ) { // found
break; } }
if ( i >= g_numProjects ) { // not found
return; }
pGamedir = g_projects[i].pGamedir; } else { pGamedir = ""; }
// Changed to CURRENT_USER to solve security issues in vista!
Sys_SetRegistryString( //"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment\\VProject",
"HKEY_CURRENT_USER\\Environment\\VProject" pGamedir );
DWORD result; SendMessageTimeout( HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM)"Environment", SMTO_ABORTIFHUNG, 0, &result ); }
//-----------------------------------------------------------------------------
// ModifyVProject
//
//-----------------------------------------------------------------------------
void ModifyVProject( int index, const char *pName, const char *pGamedir ) { free( g_projects[index].pName ); free( g_projects[index].pGamedir );
if ( !pName || !pName[0] ) { // delete
if ( g_numProjects-index-1 > 0 ) { // shift remaining elements
memcpy( &g_projects[index], &g_projects[index+1], (g_numProjects-index-1)*sizeof( project_t ) ); }
g_projects[g_numProjects-1].pName = NULL; g_projects[g_numProjects-1].pGamedir = NULL;
g_numProjects--;
if ( g_nActiveVProject == index+1 ) { // deleted current vproject
if ( !g_numProjects ) { // no more projects
g_nActiveVProject = 0; SetVProject( NULL ); } else { // set to top
g_nActiveVProject = 1; SetVProject( g_projects[0].pName ); } } } else { g_projects[index].pName = strdup( pName ); g_projects[index].pGamedir = strdup( pGamedir ); } }
//-----------------------------------------------------------------------------
// AddVProject
//
//-----------------------------------------------------------------------------
void AddVProject( const char *pName, const char *pGamedir ) { if ( !pName || !pName[0] ) { // do not add empty projects
return; }
ModifyVProject( g_numProjects, pName, pGamedir ); g_numProjects++; }
//-----------------------------------------------------------------------------
// LoadRegistryValues
//
//-----------------------------------------------------------------------------
void LoadRegistryValues() { char keyBuff[32]; char valueBuff[256]; char projectName[256]; char gamedirString[256]; char *ptr; char *token; int i;
for ( i=0; i<MAX_PROJECTS; i++ ) { projectName[0] = '\0'; gamedirString[0] = '\0';
sprintf( keyBuff, "project%d", i ); Sys_GetRegistryString( keyBuff, valueBuff, "", sizeof( valueBuff ) );
// parse and populate valid values
ptr = valueBuff; token = Sys_GetToken( &ptr, false, NULL ); if ( token[0] ) { strcpy( projectName, token ); } else { continue; }
token = Sys_GetToken( &ptr, false, NULL ); if ( token[0] ) { strcpy( gamedirString, token ); }
AddVProject( projectName, gamedirString ); } }
//-----------------------------------------------------------------------------
// SaveRegistryValues
//
//-----------------------------------------------------------------------------
void SaveRegistryValues() { char valueBuff[256]; char keyBuff[32]; char *pProjectName; char *pGamedir; int len; int i;
for ( i=0; i<MAX_PROJECTS; i++ ) { sprintf( keyBuff, "project%d", i );
pProjectName = g_projects[i].pName; if ( !pProjectName ) { pProjectName = ""; }
pGamedir = g_projects[i].pGamedir; if ( !pGamedir ) { pGamedir = ""; }
len = _snprintf( valueBuff, sizeof( valueBuff ), "\"%s\" \"%s\"", pProjectName, pGamedir ); if ( len == -1 ) { // kill it
valueBuff[0] = '\0'; }
Sys_SetRegistryString( keyBuff, valueBuff ); } }
//-----------------------------------------------------------------------------
// ShiftActiveProjectUp
//
//-----------------------------------------------------------------------------
void ShiftActiveProjectUp() { if ( g_numProjects <= 1 || !g_nActiveVProject ) { // nothing to do
return; }
int active = g_nActiveVProject-1; int previous = (active + g_numProjects - 1) % g_numProjects;
project_t tempProject; tempProject = g_projects[previous]; g_projects[previous] = g_projects[active]; g_projects[active] = tempProject;
g_nActiveVProject = previous + 1; }
//-----------------------------------------------------------------------------
// ShiftActiveProjectDown
//
//-----------------------------------------------------------------------------
void ShiftActiveProjectDown() { if ( g_numProjects <= 1 || !g_nActiveVProject ) { // nothing to do
return; }
int active = g_nActiveVProject-1; int next = (active + g_numProjects + 1) % g_numProjects;
project_t tempProject; tempProject = g_projects[next]; g_projects[next] = g_projects[active]; g_projects[active] = tempProject;
g_nActiveVProject = next + 1; }
//-----------------------------------------------------------------------------
// ModifyDlg_Proc
//
//-----------------------------------------------------------------------------
BOOL CALLBACK ModifyDlg_Proc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { size_t len; int width; int height; RECT rect;
switch ( message ) { case WM_INITDIALOG: SetDlgItemText( hWnd, IDC_MODIFY_PROJECT, g_project_name ); SetDlgItemText( hWnd, IDC_MODIFY_GAMEDIR, g_project_gamedir );
// center dialog
GetWindowRect( hWnd, &rect ); width = GetSystemMetrics( SM_CXSCREEN ); height = GetSystemMetrics( SM_CYSCREEN ); SetWindowPos( hWnd, NULL, ( width - ( rect.right - rect.left ) )/2, ( height - ( rect.bottom - rect.top ) )/2, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); return ( TRUE );
case WM_COMMAND: switch ( LOWORD( wParam ) ) { case IDC_OK: GetDlgItemText( hWnd, IDC_MODIFY_PROJECT, g_project_name, sizeof( g_project_name ) ); GetDlgItemText( hWnd, IDC_MODIFY_GAMEDIR, g_project_gamedir, sizeof( g_project_gamedir ) );
// remove trailing seperator
Sys_NormalizePath( g_project_gamedir, false ); len = strlen( g_project_gamedir ); if ( len > 2 && g_project_gamedir[len-1] == '\\' ) { g_project_gamedir[len-1] = '\0'; } // fall through
case IDCANCEL: case IDC_CANCEL: EndDialog( hWnd, wParam ); return ( TRUE ); } break; } return ( FALSE ); }
//-----------------------------------------------------------------------------
// ModifyDlg_Open
//
//-----------------------------------------------------------------------------
BOOL ModifyDlg_Open() { int result; result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_VPROJECT ), g_hWnd, ( DLGPROC )ModifyDlg_Proc ); if ( LOWORD( result ) != IDC_OK ) { return FALSE; }
return TRUE; }
//-----------------------------------------------------------------------------
// ShowPopupMenu
//
//-----------------------------------------------------------------------------
void ShowPopupMenu( HWND hWnd, bool bUseCachedMenuPos ) { BOOL bDelete = true;
// delete existing entries
for ( int nIndex = 1; nIndex < ID_TRAY_ADDVPROJECT && bDelete; nIndex++ ) { bDelete = DeleteMenu( g_hMenu, nIndex, MF_BYCOMMAND ); }
// Insert projects
char szMenuItem[MAX_PATH]; for ( int nIndex = 0; nIndex < g_numProjects; nIndex++ ) { strcpy( szMenuItem, g_projects[nIndex].pName ); strcat( szMenuItem, "\t" ); strcat( szMenuItem, g_projects[nIndex].pGamedir ); strcat( szMenuItem, " " );
InsertMenu( g_hMenu, nIndex, MF_BYPOSITION | MF_STRING, nIndex + 1, szMenuItem ); }
if ( g_nActiveVProject ) { CheckMenuItem( g_hMenu, g_nActiveVProject, MF_BYCOMMAND|MF_CHECKED ); SetMenuDefaultItem( g_hMenu, g_nActiveVProject, FALSE ); }
// Display the popup menu at the current cursor location
// Use the cached cursor position if set
if ( !bUseCachedMenuPos || ( !g_cursorPoint.x && !g_cursorPoint.y ) ) { GetCursorPos( &g_cursorPoint ); } SetForegroundWindow( hWnd ); TrackPopupMenu( g_hMenu, 0, g_cursorPoint.x, g_cursorPoint.y, 0, hWnd, 0 ); PostMessage( hWnd, WM_NULL, 0, 0 ); }
//-----------------------------------------------------------------------------
// TrayMessageHandler
//
//-----------------------------------------------------------------------------
void TrayMessageHandler( HWND hWnd, UINT uMessageID ) { switch ( uMessageID ) { case 0: break;
case ID_TRAY_EXIT: DestroyWindow( hWnd ); break;
case ID_TRAY_ADDVPROJECT: SetForegroundWindow( hWnd ); g_project_name[0] = '\0'; g_project_gamedir[0] = '\0'; if ( ModifyDlg_Open() ) { AddVProject( g_project_name, g_project_gamedir ); SaveRegistryValues(); } ShowPopupMenu( hWnd, true ); break;
case ID_TRAY_MODIFYVPROJECT: SetForegroundWindow( hWnd ); if ( g_nActiveVProject ) { strcpy( g_project_name, g_projects[g_nActiveVProject-1].pName ); strcpy( g_project_gamedir, g_projects[g_nActiveVProject-1].pGamedir ); if ( ModifyDlg_Open() ) { ModifyVProject( g_nActiveVProject-1, g_project_name, g_project_gamedir ); SaveRegistryValues(); } ShowPopupMenu( hWnd, true ); } break;
case ID_TRAY_MOVEUP: SetForegroundWindow( hWnd ); if ( g_nActiveVProject ) { ShiftActiveProjectUp(); SaveRegistryValues(); ShowPopupMenu( hWnd, true ); } break;
case ID_TRAY_MOVEDOWN: SetForegroundWindow( hWnd ); if ( g_nActiveVProject ) { ShiftActiveProjectDown(); SaveRegistryValues(); ShowPopupMenu( hWnd, true ); } break;
default: if ( uMessageID >= 1 && uMessageID <= MAX_PROJECTS ) { // set current vproject
g_nActiveVProject = uMessageID; SetVProject( g_projects[uMessageID-1].pName ); } break; } }
//-----------------------------------------------------------------------------
// Main_WndProc
//
//-----------------------------------------------------------------------------
LRESULT CALLBACK Main_WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) { switch ( message ) { case WM_DESTROY: PostQuitMessage( 0 ); return 0L; case WM_TRAY: if ( lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN ) { ShowPopupMenu( hWnd, false ); return 0L; } break;
case WM_COMMAND: TrayMessageHandler( hWnd, LOWORD( wParam ) ); break; }
return ( DefWindowProc( hWnd, message, wParam, lParam ) ); }
//-----------------------------------------------------------------------------
// Startup
//
//-----------------------------------------------------------------------------
bool Startup() { int i;
// set up our window class
WNDCLASS wndclass; memset( &wndclass, 0, sizeof( wndclass ) ); wndclass.style = 0; wndclass.lpfnWndProc = Main_WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_hInstance; wndclass.hIcon = LoadIcon( g_hInstance, (LPCTSTR)IDI_VPROJECT ); wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = VPROJECT_CLASSNAME; if ( !RegisterClass( &wndclass ) ) { return false; }
// create the hidden window
g_hWnd = CreateWindow( VPROJECT_CLASSNAME, 0, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, g_hInstance, NULL ); // Create tray icon
g_iconData.cbSize = sizeof( NOTIFYICONDATA ); g_iconData.hIcon = LoadIcon( g_hInstance, (LPCTSTR)IDI_VPROJECT ); g_iconData.hWnd = g_hWnd; g_iconData.uCallbackMessage = WM_TRAY; g_iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; g_iconData.uID = ID_TRAY; strcpy(g_iconData.szTip, "VPROJECT"); Shell_NotifyIcon( NIM_ADD, &g_iconData );
// Create popup menu and add initial items
g_hMenu = CreatePopupMenu(); AppendMenu( g_hMenu, MF_SEPARATOR, 0, 0); AppendMenu( g_hMenu, MF_STRING, ID_TRAY_ADDVPROJECT, "Add VProject" ); AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MODIFYVPROJECT, "Modify VProject" ); AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MOVEUP, "Move Up" ); AppendMenu( g_hMenu, MF_STRING, ID_TRAY_MOVEDOWN, "Move Down" ); AppendMenu( g_hMenu, MF_SEPARATOR, 0, 0); AppendMenu( g_hMenu, MF_STRING, ID_TRAY_EXIT, "Remove From Tray" );
// find the current vproject
char* vproject = getenv( "vproject" ); if ( vproject && vproject[0] ) { char temp[MAX_PATH]; strcpy( temp, vproject ); Sys_NormalizePath( temp, false ); for ( i=0; i<g_numProjects; i++ ) { if ( !stricmp( g_projects[i].pGamedir, temp ) ) { // found
g_nActiveVProject = i+1; break; } } }
return true; }
//-----------------------------------------------------------------------------
// Shutdown
//
// Free all resources
//-----------------------------------------------------------------------------
void Shutdown() { }
//-----------------------------------------------------------------------------
// WinMain
//
// Entry point for program
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow ) { bool error = true; MSG msg = {0};
g_hInstance = hInstance;
// get the project list
LoadRegistryValues();
if ( pCmdLine && pCmdLine[0] ) { // set directly
SetVProject( pCmdLine ); return 0; }
HWND hwnd = FindWindow( VPROJECT_CLASSNAME, NULL ); if ( hwnd ) { // single instance only
return ( FALSE ); }
if ( !Startup() ) { goto cleanUp; }
// message pump
while ( GetMessage( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); }
// no-error, end of app
error = false;
cleanUp: if ( error ) { char str[255]; FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), 0, str, 255, NULL ); MessageBox( NULL, str, NULL, MB_OK ); }
Shutdown();
return ( (int)msg.wParam ); }
|