You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
648 lines
15 KiB
648 lines
15 KiB
//========= 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 ); |
|
} |
|
|
|
|
|
|