diff src/win32/ramwatch.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/win32/ramwatch.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,1249 @@
     1.4 +#include "stdafx.h"
     1.5 +#include "VBA.h"
     1.6 +#include "resource.h"
     1.7 +#include "WinMiscUtil.h"
     1.8 +#include "GBACheatsDlg.h"
     1.9 +#include "GBCheatsDlg.h"
    1.10 +#include "ram_search.h"
    1.11 +#include "ramwatch.h"
    1.12 +#include "reg.h"
    1.13 +#include "Sound.h"
    1.14 +#include <cassert>
    1.15 +#include <windows.h>
    1.16 +#include <string>
    1.17 +
    1.18 +/*
    1.19 +#include <commctrl.h>
    1.20 +#pragma comment(lib, "comctl32.lib")
    1.21 +#include <shellapi.h>
    1.22 +#pragma comment(lib, "shell32.lib")
    1.23 +#include <commdlg.h>
    1.24 +#pragma comment(lib, "comdlg32.lib")
    1.25 +*/
    1.26 +
    1.27 +static HMENU ramwatchmenu;
    1.28 +static HMENU rwrecentmenu;
    1.29 +/*static*/ HACCEL RamWatchAccels = NULL;
    1.30 +char rw_recent_files[MAX_RECENT_WATCHES][1024];
    1.31 +//char Watch_Dir[1024]="";
    1.32 +bool RWfileChanged = false; //Keeps track of whether the current watch file has been changed, if so, ramwatch will prompt to save changes
    1.33 +bool AutoRWLoad = false;    //Keeps track of whether Auto-load is checked
    1.34 +bool RWSaveWindowPos = false; //Keeps track of whether Save Window position is checked
    1.35 +char currentWatch[1024];
    1.36 +int ramw_x, ramw_y;			//Used to store ramwatch dialog window positions
    1.37 +AddressWatcher rswatches[MAX_WATCH_COUNT];
    1.38 +int WatchCount=0;
    1.39 +static int s_prevSelCount=-1;
    1.40 +
    1.41 +HWND RamWatchHWnd;
    1.42 +#define gamefilename theApp.gameFilename
    1.43 +#define hWnd AfxGetMainWnd()->GetSafeHwnd()
    1.44 +#define hInst AfxGetInstanceHandle()
    1.45 +static char Str_Tmp [1024];
    1.46 +
    1.47 +void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths); //initializes the ram search and/or ram watch listbox
    1.48 +
    1.49 +#define MESSAGEBOXPARENT (RamWatchHWnd ? RamWatchHWnd : hWnd)
    1.50 +
    1.51 +bool QuickSaveWatches();
    1.52 +bool ResetWatches();
    1.53 +
    1.54 +void RefreshWatchListSelectedCountControlStatus(HWND hDlg);
    1.55 +
    1.56 +unsigned int GetCurrentValue(AddressWatcher& watch)
    1.57 +{
    1.58 +	return ReadValueAtHardwareAddress(watch.Address, watch.Size == 'd' ? 4 : watch.Size == 'w' ? 2 : 1);
    1.59 +}
    1.60 +
    1.61 +bool IsSameWatch(const AddressWatcher& l, const AddressWatcher& r)
    1.62 +{
    1.63 +	if (r.Size == 'S') return false;
    1.64 +	return ((l.Address == r.Address) && (l.Size == r.Size) && (l.Type == r.Type)/* && (l.WrongEndian == r.WrongEndian)*/);
    1.65 +}
    1.66 +
    1.67 +bool VerifyWatchNotAlreadyAdded(const AddressWatcher& watch)
    1.68 +{
    1.69 +	for (int j = 0; j < WatchCount; j++)
    1.70 +	{
    1.71 +		if (IsSameWatch(rswatches[j], watch))
    1.72 +		{
    1.73 +			if(RamWatchHWnd)
    1.74 +				SetForegroundWindow(RamWatchHWnd);
    1.75 +			return false;
    1.76 +		}
    1.77 +	}
    1.78 +	return true;
    1.79 +}
    1.80 +
    1.81 +
    1.82 +bool InsertWatch(const AddressWatcher& Watch, char *Comment)
    1.83 +{
    1.84 +	if(WatchCount >= MAX_WATCH_COUNT)
    1.85 +		return false;
    1.86 +
    1.87 +	int i = WatchCount++;
    1.88 +	AddressWatcher& NewWatch = rswatches[i];
    1.89 +	NewWatch = Watch;
    1.90 +	//if (NewWatch.comment) free(NewWatch.comment);
    1.91 +	NewWatch.comment = (char *) malloc(strlen(Comment)+2);
    1.92 +	NewWatch.CurValue = GetCurrentValue(NewWatch);
    1.93 +	strcpy(NewWatch.comment, Comment);
    1.94 +	ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount);
    1.95 +	RWfileChanged=true;
    1.96 +
    1.97 +	return true;
    1.98 +}
    1.99 +
   1.100 +LRESULT CALLBACK PromptWatchNameProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //Gets the description of a watched address
   1.101 +{
   1.102 +	RECT r;
   1.103 +	RECT r2;
   1.104 +	int dx1, dy1, dx2, dy2;
   1.105 +
   1.106 +	switch(uMsg)
   1.107 +	{
   1.108 +		case WM_INITDIALOG:
   1.109 +			//Clear_Sound_Buffer();
   1.110 +
   1.111 +			GetWindowRect(hWnd, &r);
   1.112 +			dx1 = (r.right - r.left) / 2;
   1.113 +			dy1 = (r.bottom - r.top) / 2;
   1.114 +
   1.115 +			GetWindowRect(hDlg, &r2);
   1.116 +			dx2 = (r2.right - r2.left) / 2;
   1.117 +			dy2 = (r2.bottom - r2.top) / 2;
   1.118 +
   1.119 +			//SetWindowPos(hDlg, NULL, max(0, r.left + (dx1 - dx2)), max(0, r.top + (dy1 - dy2)), NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
   1.120 +			SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
   1.121 +			strcpy(Str_Tmp,"Enter a name for this RAM address.");
   1.122 +			SendDlgItemMessage(hDlg,IDC_PROMPT_TEXT,WM_SETTEXT,0,(LPARAM)Str_Tmp);
   1.123 +			strcpy(Str_Tmp,"");
   1.124 +			SendDlgItemMessage(hDlg,IDC_PROMPT_TEXT2,WM_SETTEXT,0,(LPARAM)Str_Tmp);
   1.125 +			return true;
   1.126 +			break;
   1.127 +
   1.128 +		case WM_COMMAND:
   1.129 +			switch(LOWORD(wParam))
   1.130 +			{
   1.131 +				case IDOK:
   1.132 +				{
   1.133 +					GetDlgItemText(hDlg,IDC_PROMPT_EDIT,Str_Tmp,80);
   1.134 +					InsertWatch(rswatches[WatchCount],Str_Tmp);
   1.135 +					EndDialog(hDlg, true);
   1.136 +					return true;
   1.137 +					break;
   1.138 +				}
   1.139 +				case ID_CANCEL:
   1.140 +				case IDCANCEL:
   1.141 +					EndDialog(hDlg, false);
   1.142 +					return false;
   1.143 +					break;
   1.144 +			}
   1.145 +			break;
   1.146 +
   1.147 +		case WM_CLOSE:
   1.148 +			EndDialog(hDlg, false);
   1.149 +			return false;
   1.150 +			break;
   1.151 +	}
   1.152 +
   1.153 +	return false;
   1.154 +}
   1.155 +
   1.156 +bool InsertWatch(const AddressWatcher& Watch, HWND parent)
   1.157 +{
   1.158 +	if(!VerifyWatchNotAlreadyAdded(Watch))
   1.159 +		return false;
   1.160 +
   1.161 +	if(!parent)
   1.162 +		parent = RamWatchHWnd;
   1.163 +	if(!parent)
   1.164 +		parent = hWnd;
   1.165 +
   1.166 +	int prevWatchCount = WatchCount;
   1.167 +
   1.168 +	rswatches[WatchCount] = Watch;
   1.169 +	rswatches[WatchCount].CurValue = GetCurrentValue(rswatches[WatchCount]);
   1.170 +	systemSoundClearBuffer();
   1.171 +	DialogBox(hInst, MAKEINTRESOURCE(IDD_PROMPT), parent, (DLGPROC) PromptWatchNameProc);
   1.172 +
   1.173 +	return WatchCount > prevWatchCount;
   1.174 +}
   1.175 +
   1.176 +void Update_RAM_Watch()
   1.177 +{
   1.178 +	BOOL watchChanged[MAX_WATCH_COUNT] = {0};
   1.179 +
   1.180 +	if(WatchCount)
   1.181 +	{
   1.182 +		// update cached values and detect changes to displayed listview items
   1.183 +
   1.184 +		for(int i = 0; i < WatchCount; i++)
   1.185 +		{
   1.186 +			unsigned int prevCurValue = rswatches[i].CurValue;
   1.187 +			unsigned int newCurValue = GetCurrentValue(rswatches[i]);
   1.188 +			if(prevCurValue != newCurValue)
   1.189 +			{
   1.190 +				rswatches[i].CurValue = newCurValue;
   1.191 +				watchChanged[i] = TRUE;
   1.192 +			}
   1.193 +		}
   1.194 +	}
   1.195 +
   1.196 +	// refresh any visible parts of the listview box that changed
   1.197 +	HWND lv = GetDlgItem(RamWatchHWnd,IDC_WATCHLIST);
   1.198 +	int top = ListView_GetTopIndex(lv);
   1.199 +	int bottom = top + ListView_GetCountPerPage(lv) + 1; // +1 is so we will update a partially-displayed last item
   1.200 +	if(top < 0) top = 0;
   1.201 +	if(bottom > WatchCount) bottom = WatchCount;
   1.202 +	int start = -1;
   1.203 +	for(int i = top; i <= bottom; i++)
   1.204 +	{
   1.205 +		if(start == -1)
   1.206 +		{
   1.207 +			if(i != bottom && watchChanged[i])
   1.208 +			{
   1.209 +				start = i;
   1.210 +				//somethingChanged = true;
   1.211 +			}
   1.212 +		}
   1.213 +		else
   1.214 +		{
   1.215 +			if(i == bottom || !watchChanged[i])
   1.216 +			{
   1.217 +				ListView_RedrawItems(lv, start, i-1);
   1.218 +				start = -1;
   1.219 +			}
   1.220 +		}
   1.221 +	}
   1.222 +}
   1.223 +
   1.224 +bool AskSave()
   1.225 +{
   1.226 +	//This function asks to save changes if the watch file contents have changed
   1.227 +	//returns false only if a save was attempted but failed or was cancelled
   1.228 +	if (RWfileChanged)
   1.229 +	{
   1.230 +		systemSoundClearBuffer();
   1.231 +		int answer = MessageBox(MESSAGEBOXPARENT, "Save Changes?", "Ram Watch", MB_YESNOCANCEL);
   1.232 +		if(answer == IDYES)
   1.233 +			if(!QuickSaveWatches())
   1.234 +				return false;
   1.235 +		return (answer != IDCANCEL);
   1.236 +	}
   1.237 +	return true;
   1.238 +}
   1.239 +
   1.240 +void WriteRecentRWFiles()
   1.241 +{
   1.242 +	char str[2048];
   1.243 +	for (int i = 0; i < MAX_RECENT_WATCHES; i++)
   1.244 +	{
   1.245 +		sprintf(str, "recentWatch%d", i+1);
   1.246 +		regSetStringValue(str, &rw_recent_files[i][0]);
   1.247 +	}
   1.248 +}
   1.249 +
   1.250 +void UpdateRW_RMenu(HMENU menu, unsigned int mitem, unsigned int baseid)
   1.251 +{
   1.252 +	MENUITEMINFO moo;
   1.253 +	int x;
   1.254 +
   1.255 +	moo.cbSize = sizeof(moo);
   1.256 +	moo.fMask = MIIM_SUBMENU | MIIM_STATE;
   1.257 +
   1.258 +	GetMenuItemInfo(GetSubMenu(ramwatchmenu, 0), mitem, FALSE, &moo);
   1.259 +	moo.hSubMenu = menu;
   1.260 +	moo.fState = strlen(rw_recent_files[0]) ? MFS_ENABLED : MFS_GRAYED;
   1.261 +
   1.262 +	SetMenuItemInfo(GetSubMenu(ramwatchmenu, 0), mitem, FALSE, &moo);
   1.263 +
   1.264 +	// Remove all recent files submenus
   1.265 +	for(x = 0; x < MAX_RECENT_WATCHES; x++)
   1.266 +	{
   1.267 +		RemoveMenu(menu, baseid + x, MF_BYCOMMAND);
   1.268 +	}
   1.269 +
   1.270 +	// Recreate the menus
   1.271 +	for(x = MAX_RECENT_WATCHES - 1; x >= 0; x--)
   1.272 +	{  
   1.273 +		// Skip empty strings
   1.274 +		if(!strlen(rw_recent_files[x]))
   1.275 +		{
   1.276 +			continue;
   1.277 +		}
   1.278 +
   1.279 +		moo.cbSize = sizeof(moo);
   1.280 +		moo.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE;
   1.281 +
   1.282 +#if 0
   1.283 +		const int TEMP_STRING_LENGTH = 128 + 5;
   1.284 +		char tmp[TEMP_STRING_LENGTH];	// FIXME?
   1.285 +
   1.286 +		// Fill in the menu text.
   1.287 +		if(strlen(rw_recent_files[x]) < 128)
   1.288 +		{
   1.289 +			sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, rw_recent_files[x]);
   1.290 +		}
   1.291 +		else
   1.292 +		{
   1.293 +			sprintf(tmp, "&%d. %s", ( x + 1 ) % 10, rw_recent_files[x] + strlen( rw_recent_files[x] ) - 127);
   1.294 +		}
   1.295 +#endif
   1.296 +		// the ATL way; it is really pain to work out a MBCS-compatible string replace function in the pure c way
   1.297 +		CString atltmp(rw_recent_files[x]);
   1.298 +		atltmp.Replace("&", "&&");
   1.299 +		char *tmp = atltmp.GetBuffer(0);
   1.300 +
   1.301 +		// Insert the menu item
   1.302 +		moo.cch = strlen(tmp);
   1.303 +		moo.fType = 0;
   1.304 +		moo.wID = baseid + x;
   1.305 +		moo.dwTypeData = tmp;
   1.306 +		InsertMenuItem(menu, 0, 1, &moo);
   1.307 +
   1.308 +		// atltmp.ReleaseBuffer();
   1.309 +	}
   1.310 +
   1.311 +	// I don't think one function shall do so many things in a row
   1.312 +//	WriteRecentRWFiles();	// write recent menu to ini
   1.313 +}
   1.314 +
   1.315 +void UpdateRWRecentArray(const char* addString, unsigned int arrayLen, HMENU menu, unsigned int menuItem, unsigned int baseId)
   1.316 +{
   1.317 +	const size_t len = 1024; // Avoid magic numbers
   1.318 +
   1.319 +	// Try to find out if the filename is already in the recent files list.
   1.320 +	for(unsigned int x = 0; x < arrayLen; x++)
   1.321 +	{
   1.322 +		if(strlen(rw_recent_files[x]))
   1.323 +		{
   1.324 +			if(!strncmp(rw_recent_files[x], addString, 1024))    // Item is already in list.
   1.325 +			{
   1.326 +				// If the filename is in the file list don't add it again.
   1.327 +				// Move it up in the list instead.
   1.328 +
   1.329 +				int y;
   1.330 +				char tmp[len];
   1.331 +
   1.332 +				// Save pointer.
   1.333 +				strncpy(tmp, rw_recent_files[x], len - 1);	// assuming rw_recent_files[n] is 0-terminated
   1.334 +				
   1.335 +				for(y = x; y; y--)
   1.336 +				{
   1.337 +					// Move items down.
   1.338 +					strncpy(rw_recent_files[y], rw_recent_files[y - 1], len);
   1.339 +				}
   1.340 +
   1.341 +				// Put item on top.
   1.342 +				strncpy(rw_recent_files[0],tmp, len);
   1.343 +
   1.344 +				// Update the recent files menu
   1.345 +				UpdateRW_RMenu(menu, menuItem, baseId);
   1.346 +
   1.347 +				return;
   1.348 +			}
   1.349 +		}
   1.350 +	}
   1.351 +
   1.352 +	// The filename wasn't found in the list. That means we need to add it.
   1.353 +
   1.354 +	// Move the other items down.
   1.355 +	for(unsigned int x = arrayLen - 1; x; x--)
   1.356 +	{
   1.357 +		strncpy(rw_recent_files[x],rw_recent_files[x - 1], len);
   1.358 +	}
   1.359 +
   1.360 +	// Add the new item.
   1.361 +	strncpy(rw_recent_files[0], addString, len);
   1.362 +	rw_recent_files[0][len - 1] = '\0';	// better not assume that
   1.363 +
   1.364 +	// Update the recent files menu
   1.365 +	UpdateRW_RMenu(menu, menuItem, baseId);
   1.366 +}
   1.367 +
   1.368 +void RWAddRecentFile(const char *filename)
   1.369 +{
   1.370 +	UpdateRWRecentArray(filename, MAX_RECENT_WATCHES, rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE);
   1.371 +}
   1.372 +
   1.373 +void OpenRWRecentFile(int memwRFileNumber)
   1.374 +{
   1.375 +	if(!ResetWatches())
   1.376 +		return;
   1.377 +
   1.378 +	int rnum = memwRFileNumber;
   1.379 +	if ((unsigned int)rnum >= MAX_RECENT_WATCHES)
   1.380 +		return; //just in case
   1.381 +
   1.382 +	char* x;
   1.383 +
   1.384 +	while(true)
   1.385 +	{
   1.386 +		x = rw_recent_files[rnum];
   1.387 +		if (!*x) 
   1.388 +			return;		//If no recent files exist just return.  Useful for Load last file on startup (or if something goes screwy)
   1.389 +
   1.390 +		if (rnum) //Change order of recent files if not most recent
   1.391 +		{
   1.392 +			RWAddRecentFile(x);
   1.393 +			rnum = 0;
   1.394 +		}
   1.395 +		else
   1.396 +		{
   1.397 +			break;
   1.398 +		}
   1.399 +	}
   1.400 +
   1.401 +	strcpy(currentWatch,x);
   1.402 +	strcpy(Str_Tmp,currentWatch);
   1.403 +
   1.404 +	//loadwatches here
   1.405 +	FILE *WatchFile = fopen(Str_Tmp,"rb");
   1.406 +	if (!WatchFile)
   1.407 +	{
   1.408 +		systemSoundClearBuffer();
   1.409 +		int answer = MessageBox(MESSAGEBOXPARENT,"Error opening file.","ERROR",MB_OKCANCEL);
   1.410 +		if (answer == IDOK)
   1.411 +		{
   1.412 +			rw_recent_files[rnum][0] = '\0';	//Clear file from list 
   1.413 +			if (rnum)							//Update the ramwatch list
   1.414 +				RWAddRecentFile(rw_recent_files[0]); 
   1.415 +			else
   1.416 +				RWAddRecentFile(rw_recent_files[1]);
   1.417 +		}
   1.418 +		return;
   1.419 +	}
   1.420 +	const char DELIM = '\t';
   1.421 +	AddressWatcher Temp;
   1.422 +	char mode;
   1.423 +	fgets(Str_Tmp,1024,WatchFile);
   1.424 +	sscanf(Str_Tmp,"%c%*s",&mode);
   1.425 +	//if ((mode == '1' && !(SegaCD_Started)) || (mode == '2' && !(_32X_Started)))
   1.426 +	//{
   1.427 +	//	char Device[8];
   1.428 +	//	strcpy(Device,(mode > '1')?"32X":"SegaCD");
   1.429 +	//	sprintf(Str_Tmp,"Warning: %s not started. \nWatches for %s addresses will be ignored.",Device,Device);
   1.430 +	//	MessageBox(MESSAGEBOXPARENT,Str_Tmp,"Possible Device Mismatch",MB_OK);
   1.431 +	//}
   1.432 +	int WatchAdd;
   1.433 +	fgets(Str_Tmp,1024,WatchFile);
   1.434 +	sscanf(Str_Tmp,"%d%*s",&WatchAdd);
   1.435 +	WatchAdd+=WatchCount;
   1.436 +	for (int i = WatchCount; i < WatchAdd; i++)
   1.437 +	{
   1.438 +		while (i < 0)
   1.439 +			i++;
   1.440 +		do {
   1.441 +			fgets(Str_Tmp,1024,WatchFile);
   1.442 +		} while (Str_Tmp[0] == '\n');
   1.443 +		sscanf(Str_Tmp,"%*05X%*c%08X%*c%c%*c%c%*c%d",&(Temp.Address),&(Temp.Size),&(Temp.Type),&(Temp.WrongEndian));
   1.444 +		Temp.WrongEndian = 0;
   1.445 +		char *Comment = strrchr(Str_Tmp,DELIM) + 1;
   1.446 +		*strrchr(Comment,'\n') = '\0';
   1.447 +		InsertWatch(Temp,Comment);
   1.448 +	}
   1.449 +
   1.450 +	fclose(WatchFile);
   1.451 +	if (RamWatchHWnd) {
   1.452 +		ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount);
   1.453 +		RefreshWatchListSelectedCountControlStatus(RamWatchHWnd);
   1.454 +	}
   1.455 +	RWfileChanged=false;
   1.456 +	return;
   1.457 +}
   1.458 +
   1.459 +int Change_File_L(char *Dest, const char *Dir, const char *Titre, const char *Filter, const char *Ext, HWND hwnd)
   1.460 +{
   1.461 +	if (!strcmp(Dest, ""))
   1.462 +	{
   1.463 +		strcpy(Dest, "default.");
   1.464 +		strcat(Dest, Ext);
   1.465 +	}
   1.466 +
   1.467 +	SetCurrentDirectory(winGetDestDir(IDS_WATCH_DIR));
   1.468 +
   1.469 +	OPENFILENAME ofn;
   1.470 +
   1.471 +	memset(&ofn, 0, sizeof(OPENFILENAME));
   1.472 +
   1.473 +	ofn.lStructSize = sizeof(OPENFILENAME);
   1.474 +	ofn.hwndOwner = hwnd;
   1.475 +	ofn.hInstance = hInst;
   1.476 +	ofn.lpstrFile = Dest;
   1.477 +	ofn.nMaxFile = 2047;
   1.478 +	ofn.lpstrFilter = Filter;
   1.479 +	ofn.nFilterIndex = 1;
   1.480 +	ofn.lpstrInitialDir = Dir;
   1.481 +	ofn.lpstrTitle = Titre;
   1.482 +	ofn.lpstrDefExt = Ext;
   1.483 +	ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
   1.484 +
   1.485 +	systemSoundClearBuffer();
   1.486 +
   1.487 +	if (GetOpenFileName(&ofn)) return 1;
   1.488 +
   1.489 +	return 0;
   1.490 +}
   1.491 +
   1.492 +int Change_File_S(char *Dest, const char *Dir, const char *Titre, const char *Filter, const char *Ext, HWND hwnd)
   1.493 +{
   1.494 +	if (!strcmp(Dest, ""))
   1.495 +	{
   1.496 +		strcpy(Dest, "default.");
   1.497 +		strcat(Dest, Ext);
   1.498 +	}
   1.499 +
   1.500 +	SetCurrentDirectory(winGetDestDir(IDS_WATCH_DIR));
   1.501 +
   1.502 +	OPENFILENAME ofn;
   1.503 +
   1.504 +	memset(&ofn, 0, sizeof(OPENFILENAME));
   1.505 +
   1.506 +	ofn.lStructSize = sizeof(OPENFILENAME);
   1.507 +	ofn.hwndOwner = hwnd;
   1.508 +	ofn.hInstance = hInst;
   1.509 +	ofn.lpstrFile = Dest;
   1.510 +	ofn.nMaxFile = 2047;
   1.511 +	ofn.lpstrFilter = Filter;
   1.512 +	ofn.nFilterIndex = 1;
   1.513 +	ofn.lpstrInitialDir = Dir;
   1.514 +	ofn.lpstrTitle = Titre;
   1.515 +	ofn.lpstrDefExt = Ext;
   1.516 +	ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
   1.517 +
   1.518 +	if (GetSaveFileName(&ofn)) return 1;
   1.519 +
   1.520 +	return 0;
   1.521 +}
   1.522 +
   1.523 +bool Save_Watches()
   1.524 +{
   1.525 +	const char* slash = max(strrchr(gamefilename, '|'), max(strrchr(gamefilename, '\\'), strrchr(gamefilename, '/')));
   1.526 +	strcpy(Str_Tmp,slash ? slash+1 : gamefilename);
   1.527 +	char* dot = strrchr(Str_Tmp, '.');
   1.528 +	if(dot) *dot = 0;
   1.529 +	strcat(Str_Tmp,".wch");
   1.530 +	if(Change_File_S(Str_Tmp, winGetDestDir(IDS_WATCH_DIR), "Save Watches", "Watchlist\0*.wch\0All Files\0*.*\0\0", "wch", RamWatchHWnd))
   1.531 +	{
   1.532 +		FILE *WatchFile = fopen(Str_Tmp,"r+b");
   1.533 +		if (!WatchFile) WatchFile = fopen(Str_Tmp,"w+b");
   1.534 +		fputc('\n',WatchFile);
   1.535 +		strcpy(currentWatch,Str_Tmp);
   1.536 +		RWAddRecentFile(currentWatch);
   1.537 +		sprintf(Str_Tmp,"%d\n",WatchCount);
   1.538 +		fputs(Str_Tmp,WatchFile);
   1.539 +		const char DELIM = '\t';
   1.540 +		for (int i = 0; i < WatchCount; i++)
   1.541 +		{
   1.542 +			sprintf(Str_Tmp,"%05X%c%08X%c%c%c%c%c%d%c%s\n",i,DELIM,rswatches[i].Address,DELIM,rswatches[i].Size,DELIM,rswatches[i].Type,DELIM,rswatches[i].WrongEndian,DELIM,rswatches[i].comment);
   1.543 +			fputs(Str_Tmp,WatchFile);
   1.544 +		}
   1.545 +		
   1.546 +		fclose(WatchFile);
   1.547 +		RWfileChanged=false;
   1.548 +		//TODO: Add to recent list function call here
   1.549 +		return true;
   1.550 +	}
   1.551 +	return false;
   1.552 +}
   1.553 +
   1.554 +bool QuickSaveWatches()
   1.555 +{
   1.556 +if (RWfileChanged==false) return true; //If file has not changed, no need to save changes
   1.557 +if (currentWatch[0] == NULL) //If there is no currently loaded file, run to Save as and then return
   1.558 +	{
   1.559 +		return Save_Watches();
   1.560 +	}
   1.561 +		
   1.562 +		strcpy(Str_Tmp,currentWatch);
   1.563 +		FILE *WatchFile = fopen(Str_Tmp,"r+b");
   1.564 +		if (!WatchFile) WatchFile = fopen(Str_Tmp,"w+b");
   1.565 +		fputc('\n',WatchFile);
   1.566 +		sprintf(Str_Tmp,"%d\n",WatchCount);
   1.567 +		fputs(Str_Tmp,WatchFile);
   1.568 +		const char DELIM = '\t';
   1.569 +		for (int i = 0; i < WatchCount; i++)
   1.570 +		{
   1.571 +			sprintf(Str_Tmp,"%05X%c%08X%c%c%c%c%c%d%c%s\n",i,DELIM,rswatches[i].Address,DELIM,rswatches[i].Size,DELIM,rswatches[i].Type,DELIM,rswatches[i].WrongEndian,DELIM,rswatches[i].comment);
   1.572 +			fputs(Str_Tmp,WatchFile);
   1.573 +		}
   1.574 +		fclose(WatchFile);
   1.575 +		RWfileChanged=false;
   1.576 +		return true;
   1.577 +}
   1.578 +
   1.579 +bool Load_Watches(bool clear, const char* filename)
   1.580 +{
   1.581 +	const char DELIM = '\t';
   1.582 +	FILE* WatchFile = fopen(filename,"rb");
   1.583 +	if (!WatchFile)
   1.584 +	{
   1.585 +		systemSoundClearBuffer();
   1.586 +		MessageBox(MESSAGEBOXPARENT,"Error opening file.","ERROR",MB_OK);
   1.587 +		return false;
   1.588 +	}
   1.589 +	if(clear)
   1.590 +	{
   1.591 +		if(!ResetWatches())
   1.592 +		{
   1.593 +			fclose(WatchFile);
   1.594 +			return false;
   1.595 +		}
   1.596 +	}
   1.597 +	strcpy(currentWatch,filename);
   1.598 +	RWAddRecentFile(currentWatch);
   1.599 +	AddressWatcher Temp;
   1.600 +	char mode;
   1.601 +	fgets(Str_Tmp,1024,WatchFile);
   1.602 +	sscanf(Str_Tmp,"%c%*s",&mode);
   1.603 +	int WatchAdd;
   1.604 +	fgets(Str_Tmp,1024,WatchFile);
   1.605 +	sscanf(Str_Tmp,"%d%*s",&WatchAdd);
   1.606 +	WatchAdd+=WatchCount;
   1.607 +	for (int i = WatchCount; i < WatchAdd; i++)
   1.608 +	{
   1.609 +		while (i < 0)
   1.610 +			i++;
   1.611 +		do {
   1.612 +			fgets(Str_Tmp,1024,WatchFile);
   1.613 +		} while (Str_Tmp[0] == '\n');
   1.614 +		sscanf(Str_Tmp,"%*05X%*c%08X%*c%c%*c%c%*c%d",&(Temp.Address),&(Temp.Size),&(Temp.Type),&(Temp.WrongEndian));
   1.615 +		Temp.WrongEndian = 0;
   1.616 +		char *Comment = strrchr(Str_Tmp,DELIM) + 1;
   1.617 +		*strrchr(Comment,'\n') = '\0';
   1.618 +		InsertWatch(Temp,Comment);
   1.619 +	}
   1.620 +	
   1.621 +	fclose(WatchFile);
   1.622 +	if (RamWatchHWnd)
   1.623 +		ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount);
   1.624 +	RWfileChanged=false;
   1.625 +	return true;
   1.626 +}
   1.627 +
   1.628 +bool Load_Watches(bool clear)
   1.629 +{
   1.630 +	const char* slash = max(strrchr(gamefilename, '|'), max(strrchr(gamefilename, '\\'), strrchr(gamefilename, '/')));
   1.631 +	strcpy(Str_Tmp,slash ? slash+1 : gamefilename);
   1.632 +	char* dot = strrchr(Str_Tmp, '.');
   1.633 +	if(dot) *dot = 0;
   1.634 +	strcat(Str_Tmp,".wch");
   1.635 +	if(Change_File_L(Str_Tmp, winGetDestDir(IDS_WATCH_DIR), "Load Watches", "Watchlist\0*.wch\0All Files\0*.*\0\0", "wch", RamWatchHWnd))
   1.636 +	{
   1.637 +		return Load_Watches(clear, Str_Tmp);
   1.638 +	}
   1.639 +	return false;
   1.640 +}
   1.641 +
   1.642 +bool ResetWatches()
   1.643 +{
   1.644 +	if(!AskSave())
   1.645 +		return false;
   1.646 +	for (;WatchCount>=0;WatchCount--)
   1.647 +	{
   1.648 +		free(rswatches[WatchCount].comment);
   1.649 +		rswatches[WatchCount].comment = NULL;
   1.650 +	}
   1.651 +	WatchCount++;
   1.652 +	if (RamWatchHWnd) {
   1.653 +		ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount);
   1.654 +		RefreshWatchListSelectedCountControlStatus(RamWatchHWnd);
   1.655 +	}
   1.656 +	RWfileChanged = false;
   1.657 +	currentWatch[0] = NULL;
   1.658 +	return true;
   1.659 +}
   1.660 +
   1.661 +void RemoveWatch(int watchIndex)
   1.662 +{
   1.663 +	free(rswatches[watchIndex].comment);
   1.664 +	rswatches[watchIndex].comment = NULL;
   1.665 +	for (int i = watchIndex; i <= WatchCount; i++)
   1.666 +		rswatches[i] = rswatches[i+1];
   1.667 +	WatchCount--;
   1.668 +}
   1.669 +
   1.670 +LRESULT CALLBACK EditWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) //Gets info for a RAM Watch, and then inserts it into the Watch List
   1.671 +{
   1.672 +	RECT r;
   1.673 +	RECT r2;
   1.674 +	int dx1, dy1, dx2, dy2;
   1.675 +	static int index;
   1.676 +	static char s,t = s = 0;
   1.677 +
   1.678 +	switch(uMsg)
   1.679 +	{
   1.680 +		case WM_INITDIALOG:
   1.681 +			//Clear_Sound_Buffer();
   1.682 +			
   1.683 +
   1.684 +			GetWindowRect(hWnd, &r);
   1.685 +			dx1 = (r.right - r.left) / 2;
   1.686 +			dy1 = (r.bottom - r.top) / 2;
   1.687 +
   1.688 +			GetWindowRect(hDlg, &r2);
   1.689 +			dx2 = (r2.right - r2.left) / 2;
   1.690 +			dy2 = (r2.bottom - r2.top) / 2;
   1.691 +
   1.692 +			//SetWindowPos(hDlg, NULL, max(0, r.left + (dx1 - dx2)), max(0, r.top + (dy1 - dy2)), NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
   1.693 +			SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
   1.694 +			index = (int)lParam;
   1.695 +			sprintf(Str_Tmp,"%08X",rswatches[index].Address);
   1.696 +			SetDlgItemText(hDlg,IDC_EDIT_COMPAREADDRESS,Str_Tmp);
   1.697 +			if (rswatches[index].comment != NULL)
   1.698 +				SetDlgItemText(hDlg,IDC_PROMPT_EDIT,rswatches[index].comment);
   1.699 +			s = rswatches[index].Size;
   1.700 +			t = rswatches[index].Type;
   1.701 +			switch (s)
   1.702 +			{
   1.703 +				case 'b':
   1.704 +					SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0);
   1.705 +					break;
   1.706 +				case 'w':
   1.707 +					SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0);
   1.708 +					break;
   1.709 +				case 'd':
   1.710 +					SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0);
   1.711 +					break;
   1.712 +				default:
   1.713 +					s = 0;
   1.714 +					break;
   1.715 +			}
   1.716 +			switch (t)
   1.717 +			{
   1.718 +				case 's':
   1.719 +					SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0);
   1.720 +					break;
   1.721 +				case 'u':
   1.722 +					SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0);
   1.723 +					break;
   1.724 +				case 'h':
   1.725 +					SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0);
   1.726 +					break;
   1.727 +				default:
   1.728 +					t = 0;
   1.729 +					break;
   1.730 +			}
   1.731 +
   1.732 +			return true;
   1.733 +			break;
   1.734 +		
   1.735 +		case WM_COMMAND:
   1.736 +			switch(LOWORD(wParam))
   1.737 +			{
   1.738 +				case IDC_SIGNED:
   1.739 +					t='s';
   1.740 +					return true;
   1.741 +				case IDC_UNSIGNED:
   1.742 +					t='u';
   1.743 +					return true;
   1.744 +				case IDC_HEX:
   1.745 +					t='h';
   1.746 +					return true;
   1.747 +				case IDC_1_BYTE:
   1.748 +					s = 'b';
   1.749 +					return true;
   1.750 +				case IDC_2_BYTES:
   1.751 +					s = 'w';
   1.752 +					return true;
   1.753 +				case IDC_4_BYTES:
   1.754 +					s = 'd';
   1.755 +					return true;
   1.756 +				case IDOK:
   1.757 +				{
   1.758 +					if (s && t)
   1.759 +					{
   1.760 +						AddressWatcher Temp;
   1.761 +						Temp.Size = s;
   1.762 +						Temp.Type = t;
   1.763 +						Temp.WrongEndian = false; //replace this when I get little endian working properly
   1.764 +						GetDlgItemText(hDlg,IDC_EDIT_COMPAREADDRESS,Str_Tmp,1024);
   1.765 +						char *addrstr = Str_Tmp;
   1.766 +						if (strlen(Str_Tmp) > 8) addrstr = &(Str_Tmp[strlen(Str_Tmp) - 9]);
   1.767 +						for(int i = 0; addrstr[i]; i++) {if(toupper(addrstr[i]) == 'O') addrstr[i] = '0';}
   1.768 +						sscanf(addrstr,"%08X",&(Temp.Address));
   1.769 +
   1.770 +						if((Temp.Address & ~0xFFFFFF) == ~0xFFFFFF)
   1.771 +							Temp.Address &= 0xFFFFFF;
   1.772 +
   1.773 +						if(IsHardwareAddressValid(Temp.Address))
   1.774 +						{
   1.775 +							GetDlgItemText(hDlg,IDC_PROMPT_EDIT,Str_Tmp,80);
   1.776 +							if (index < WatchCount) RemoveWatch(index);
   1.777 +							InsertWatch(Temp,Str_Tmp);
   1.778 +							if(RamWatchHWnd)
   1.779 +							{
   1.780 +								ListView_SetItemCount(GetDlgItem(RamWatchHWnd,IDC_WATCHLIST),WatchCount);
   1.781 +							}
   1.782 +							EndDialog(hDlg, true);
   1.783 +						}
   1.784 +						else
   1.785 +						{
   1.786 +							MessageBox(hDlg,"Invalid Address","ERROR",MB_OK);
   1.787 +						}
   1.788 +					}
   1.789 +					else
   1.790 +					{
   1.791 +						strcpy(Str_Tmp,"Error:");
   1.792 +						if (!s)
   1.793 +							strcat(Str_Tmp," Size must be specified.");
   1.794 +						if (!t)
   1.795 +							strcat(Str_Tmp," Type must be specified.");
   1.796 +						MessageBox(hDlg,Str_Tmp,"ERROR",MB_OK);
   1.797 +					}
   1.798 +					RWfileChanged=true;
   1.799 +					return true;
   1.800 +					break;
   1.801 +				}
   1.802 +				case ID_CANCEL:
   1.803 +				case IDCANCEL:
   1.804 +					EndDialog(hDlg, false);
   1.805 +					return false;
   1.806 +					break;
   1.807 +			}
   1.808 +			break;
   1.809 +
   1.810 +		case WM_CLOSE:
   1.811 +			EndDialog(hDlg, false);
   1.812 +			return false;
   1.813 +			break;
   1.814 +	}
   1.815 +
   1.816 +	return false;
   1.817 +}
   1.818 +
   1.819 +
   1.820 +
   1.821 +
   1.822 +void RamWatchEnableCommand(HWND hDlg, HMENU hMenu, UINT uIDEnableItem, bool enable)
   1.823 +{
   1.824 +	EnableWindow(GetDlgItem(hDlg, uIDEnableItem), (enable?TRUE:FALSE));
   1.825 +	if (hMenu != NULL) {
   1.826 +		if (uIDEnableItem == ID_WATCHES_UPDOWN) {
   1.827 +			EnableMenuItem(hMenu, IDC_C_WATCH_UP, MF_BYCOMMAND | (enable?MF_ENABLED:MF_GRAYED));
   1.828 +			EnableMenuItem(hMenu, IDC_C_WATCH_DOWN, MF_BYCOMMAND | (enable?MF_ENABLED:MF_GRAYED));
   1.829 +		}
   1.830 +		else
   1.831 +			EnableMenuItem(hMenu, uIDEnableItem, MF_BYCOMMAND | (enable?MF_ENABLED:MF_GRAYED));
   1.832 +	}
   1.833 +}
   1.834 +
   1.835 +void RefreshWatchListSelectedCountControlStatus(HWND hDlg)
   1.836 +{
   1.837 +	int selCount = ListView_GetSelectedCount(GetDlgItem(hDlg,IDC_WATCHLIST));
   1.838 +	if(selCount != s_prevSelCount)
   1.839 +	{
   1.840 +		if(selCount < 2 || s_prevSelCount < 2)
   1.841 +		{
   1.842 +			RamWatchEnableCommand(hDlg, ramwatchmenu, IDC_C_WATCH_EDIT, selCount == 1);
   1.843 +			RamWatchEnableCommand(hDlg, ramwatchmenu, IDC_C_WATCH_REMOVE, selCount >= 1);
   1.844 +			RamWatchEnableCommand(hDlg, ramwatchmenu, IDC_C_WATCH, WatchCount < MAX_WATCH_COUNT);
   1.845 +			RamWatchEnableCommand(hDlg, ramwatchmenu, IDC_C_WATCH_DUPLICATE, selCount == 1 && WatchCount < MAX_WATCH_COUNT);
   1.846 +			RamWatchEnableCommand(hDlg, ramwatchmenu, IDC_C_ADDCHEAT, selCount == 1);
   1.847 +			RamWatchEnableCommand(hDlg, ramwatchmenu, ID_WATCHES_UPDOWN, selCount == 1);
   1.848 +		}
   1.849 +		s_prevSelCount = selCount;
   1.850 +	}
   1.851 +}
   1.852 +
   1.853 +LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
   1.854 +{
   1.855 +	RECT r;
   1.856 +	RECT r2;
   1.857 +	int dx1, dy1, dx2, dy2;
   1.858 +	static int watchIndex=0;
   1.859 +
   1.860 +	switch(uMsg)
   1.861 +	{
   1.862 +		case WM_MOVE: {
   1.863 +			RECT wrect;
   1.864 +			GetWindowRect(hDlg,&wrect);
   1.865 +			ramw_x = wrect.left;
   1.866 +			ramw_y = wrect.top;
   1.867 +			regSetDwordValue(RAMWX, ramw_x);
   1.868 +			regSetDwordValue(RAMWY, ramw_y);
   1.869 +		}	break;
   1.870 +
   1.871 +		case WM_INITDIALOG: {
   1.872 +			GetWindowRect(hWnd, &r);  //Ramwatch window
   1.873 +			dx1 = (r.right - r.left) / 2;
   1.874 +			dy1 = (r.bottom - r.top) / 2;
   1.875 +
   1.876 +			GetWindowRect(hDlg, &r2); // TASer window
   1.877 +			dx2 = (r2.right - r2.left) / 2;
   1.878 +			dy2 = (r2.bottom - r2.top) / 2;
   1.879 +
   1.880 +			
   1.881 +			// push it away from the main window if we can
   1.882 +			const int width = (r.right-r.left);
   1.883 +			const int height = (r.bottom - r.top);
   1.884 +			const int width2 = (r2.right-r2.left); 
   1.885 +			if(r.left+width2 + width < GetSystemMetrics(SM_CXSCREEN))
   1.886 +			{
   1.887 +				r.right += width;
   1.888 +				r.left += width;
   1.889 +			}
   1.890 +			else if((int)r.left - (int)width2 > 0)
   1.891 +			{
   1.892 +				r.right -= width2;
   1.893 +				r.left -= width2;
   1.894 +			}
   1.895 +			
   1.896 +			//-----------------------------------------------------------------------------------
   1.897 +			//If user has Save Window Pos selected, override default positioning
   1.898 +			if (RWSaveWindowPos)	
   1.899 +			{
   1.900 +				//If ramwindow is for some reason completely off screen, use default instead 
   1.901 +				if (ramw_x > (-width*2) || ramw_x < (width*2 + GetSystemMetrics(SM_CYSCREEN))   ) 
   1.902 +					r.left = ramw_x;	  //This also ignores cases of windows -32000 error codes
   1.903 +				//If ramwindow is for some reason completely off screen, use default instead 
   1.904 +				if (ramw_y > (0-height*2) ||ramw_y < (height*2 + GetSystemMetrics(SM_CYSCREEN))	)
   1.905 +					r.top = ramw_y;		  //This also ignores cases of windows -32000 error codes
   1.906 +			}
   1.907 +			//-------------------------------------------------------------------------------------
   1.908 +			SetWindowPos(hDlg, NULL, r.left, r.top, NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
   1.909 +			
   1.910 +			ramwatchmenu=GetMenu(hDlg);
   1.911 +			rwrecentmenu=CreateMenu();
   1.912 +			UpdateRW_RMenu(rwrecentmenu, RAMMENU_FILE_RECENT, RW_MENU_FIRST_RECENT_FILE);
   1.913 +			
   1.914 +			const char* names[3] = {"Address","Value","Notes"};
   1.915 +			int widths[3] = {62,64,64+51+53};
   1.916 +			init_list_box(GetDlgItem(hDlg,IDC_WATCHLIST),names,3,widths);
   1.917 +			if (!ResultCount)
   1.918 +				reset_address_info();
   1.919 +			else
   1.920 +				signal_new_frame();
   1.921 +			ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount);
   1.922 +			if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0);
   1.923 +			//if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0);
   1.924 +
   1.925 +			RamWatchAccels = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1));
   1.926 +
   1.927 +			// due to some bug in windows, the arrow button width from the resource gets ignored, so we have to set it here
   1.928 +			SetWindowPos(GetDlgItem(hDlg,ID_WATCHES_UPDOWN), 0,0,0, 30,60, SWP_NOMOVE);
   1.929 +
   1.930 +			Update_RAM_Watch();
   1.931 +
   1.932 +			DragAcceptFiles(hDlg, TRUE);
   1.933 +
   1.934 +			s_prevSelCount = -1;
   1.935 +			RefreshWatchListSelectedCountControlStatus(hDlg);
   1.936 +			return false;
   1.937 +		}	break;
   1.938 +		
   1.939 +		case WM_INITMENU:
   1.940 +			CheckMenuItem(ramwatchmenu, RAMMENU_FILE_AUTOLOAD, AutoRWLoad ? MF_CHECKED : MF_UNCHECKED);
   1.941 +			CheckMenuItem(ramwatchmenu, RAMMENU_FILE_SAVEWINDOW, RWSaveWindowPos ? MF_CHECKED : MF_UNCHECKED);
   1.942 +			break;
   1.943 +
   1.944 +		case WM_ENTERMENULOOP:
   1.945 +			systemSoundClearBuffer();
   1.946 +			break;
   1.947 +
   1.948 +		case WM_MENUSELECT:
   1.949 + 		case WM_ENTERSIZEMOVE:
   1.950 +			//Clear_Sound_Buffer();
   1.951 +			break;
   1.952 +
   1.953 +		case WM_NOTIFY:
   1.954 +		{
   1.955 +			switch(wParam)
   1.956 +			{
   1.957 +				case ID_WATCHES_UPDOWN:
   1.958 +				{
   1.959 +					switch(((LPNMUPDOWN)lParam)->hdr.code)
   1.960 +					{
   1.961 +						case UDN_DELTAPOS: {
   1.962 +							int delta = ((LPNMUPDOWN)lParam)->iDelta;
   1.963 +							SendMessage(hDlg, WM_COMMAND, delta<0 ? IDC_C_WATCH_UP : IDC_C_WATCH_DOWN,0);
   1.964 +						} break;
   1.965 +					}
   1.966 +				} break;
   1.967 +
   1.968 +				default:
   1.969 +				{
   1.970 +					LPNMHDR lP = (LPNMHDR) lParam;
   1.971 +					switch (lP->code)
   1.972 +					{
   1.973 +						case LVN_ITEMCHANGED: // selection changed event
   1.974 +						{
   1.975 +							NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lP;
   1.976 +							if(pNMListView->uNewState & LVIS_FOCUSED ||
   1.977 +								(pNMListView->uNewState ^ pNMListView->uOldState) & LVIS_SELECTED)
   1.978 +							{
   1.979 +								// disable buttons that we don't have the right number of selected items for
   1.980 +								RefreshWatchListSelectedCountControlStatus(hDlg);
   1.981 +							}
   1.982 +						}	break;
   1.983 +
   1.984 +						case LVN_GETDISPINFO:
   1.985 +						{
   1.986 +							LV_DISPINFO *Item = (LV_DISPINFO *)lParam;
   1.987 +							Item->item.mask = LVIF_TEXT;
   1.988 +							Item->item.state = 0;
   1.989 +							Item->item.iImage = 0;
   1.990 +							const unsigned int iNum = Item->item.iItem;
   1.991 +							static char num[11];
   1.992 +							switch (Item->item.iSubItem)
   1.993 +							{
   1.994 +								case 0:
   1.995 +									sprintf(num,"%08X",rswatches[iNum].Address);
   1.996 +									Item->item.pszText = num;
   1.997 +									return true;
   1.998 +								case 1: {
   1.999 +									int i = rswatches[iNum].CurValue;
  1.1000 +									int t = rswatches[iNum].Type;
  1.1001 +									int size = rswatches[iNum].Size;
  1.1002 +									const char* formatString = ((t=='s') ? "%d" : (t=='u') ? "%u" : (size=='d' ? "%08X" : size=='w' ? "%04X" : "%02X"));
  1.1003 +									switch (size)
  1.1004 +									{
  1.1005 +										case 'b':
  1.1006 +										default: sprintf(num, formatString, t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break;
  1.1007 +										case 'w': sprintf(num, formatString, t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break;
  1.1008 +										case 'd': sprintf(num, formatString, t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break;
  1.1009 +									}
  1.1010 +
  1.1011 +									Item->item.pszText = num;
  1.1012 +								}	return true;
  1.1013 +								case 2:
  1.1014 +									Item->item.pszText = rswatches[iNum].comment ? rswatches[iNum].comment : "";
  1.1015 +									return true;
  1.1016 +
  1.1017 +								default:
  1.1018 +									return false;
  1.1019 +							}
  1.1020 +						}
  1.1021 +						case LVN_ODFINDITEM:
  1.1022 +						{	
  1.1023 +							// disable search by keyboard typing,
  1.1024 +							// because it interferes with some of the accelerators
  1.1025 +							// and it isn't very useful here anyway
  1.1026 +							SetWindowLong(hDlg, DWL_MSGRESULT, ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST)));
  1.1027 +							return 1;
  1.1028 +						}
  1.1029 +					}
  1.1030 +				}
  1.1031 +			}
  1.1032 +		}	break;
  1.1033 +
  1.1034 +		case WM_COMMAND:
  1.1035 +			switch(LOWORD(wParam))
  1.1036 +			{
  1.1037 +				case RAMMENU_FILE_SAVE:
  1.1038 +					QuickSaveWatches();
  1.1039 +					break;
  1.1040 +
  1.1041 +				case RAMMENU_FILE_SAVEAS:	
  1.1042 +				//case IDC_C_SAVE:
  1.1043 +					return Save_Watches();
  1.1044 +				case RAMMENU_FILE_OPEN:
  1.1045 +					return Load_Watches(true);
  1.1046 +				case RAMMENU_FILE_APPEND:
  1.1047 +				//case IDC_C_LOAD:
  1.1048 +					return Load_Watches(false);
  1.1049 +				case RAMMENU_FILE_NEW:
  1.1050 +				//case IDC_C_RESET:
  1.1051 +					ResetWatches();
  1.1052 +					return true;
  1.1053 +				case IDC_C_WATCH_REMOVE:
  1.1054 +				{
  1.1055 +					HWND watchListControl = GetDlgItem(hDlg, IDC_WATCHLIST);
  1.1056 +					watchIndex = ListView_GetNextItem(watchListControl, -1, LVNI_ALL | LVNI_SELECTED);
  1.1057 +					while (watchIndex >= 0)
  1.1058 +					{
  1.1059 +						RemoveWatch(watchIndex);
  1.1060 +						ListView_DeleteItem(watchListControl, watchIndex);
  1.1061 +						watchIndex = ListView_GetNextItem(watchListControl, -1, LVNI_ALL | LVNI_SELECTED);
  1.1062 +					}
  1.1063 +					RWfileChanged=true;
  1.1064 +					SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1065 +					return true;
  1.1066 +				}
  1.1067 +				case IDC_C_WATCH_EDIT:
  1.1068 +					watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1069 +					if(watchIndex != -1)
  1.1070 +					{
  1.1071 +						systemSoundClearBuffer();
  1.1072 +						DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) watchIndex);
  1.1073 +						SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1074 +					}
  1.1075 +					return true;
  1.1076 +				case IDC_C_WATCH:
  1.1077 +					rswatches[WatchCount].Address = rswatches[WatchCount].WrongEndian = 0;
  1.1078 +					rswatches[WatchCount].Size = 'b';
  1.1079 +					rswatches[WatchCount].Type = 's';
  1.1080 +					systemSoundClearBuffer();
  1.1081 +					DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) WatchCount);
  1.1082 +					SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1083 +					return true;
  1.1084 +				case IDC_C_WATCH_DUPLICATE:
  1.1085 +					watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1086 +					if(watchIndex != -1)
  1.1087 +					{
  1.1088 +						rswatches[WatchCount].Address = rswatches[watchIndex].Address;
  1.1089 +						rswatches[WatchCount].WrongEndian = rswatches[watchIndex].WrongEndian;
  1.1090 +						rswatches[WatchCount].Size = rswatches[watchIndex].Size;
  1.1091 +						rswatches[WatchCount].Type = rswatches[watchIndex].Type;
  1.1092 +						systemSoundClearBuffer();
  1.1093 +						DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_EDITWATCH), hDlg, (DLGPROC) EditWatchProc,(LPARAM) WatchCount);
  1.1094 +						SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1095 +					}
  1.1096 +					return true;
  1.1097 +
  1.1098 +				case IDC_C_WATCH_SEPARATE:
  1.1099 +					AddressWatcher separator;
  1.1100 +					separator.Address = 0;
  1.1101 +					separator.WrongEndian = false;
  1.1102 +					separator.Size = 'S';
  1.1103 +					separator.Type = 'S';
  1.1104 +					InsertWatch(separator, "----------------------------");
  1.1105 +					SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1106 +					return true;
  1.1107 +
  1.1108 +				case IDC_C_WATCH_UP:
  1.1109 +				{
  1.1110 +					watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1111 +					if (watchIndex == 0 || watchIndex == -1)
  1.1112 +						return true;
  1.1113 +					void *tmp = malloc(sizeof(AddressWatcher));
  1.1114 +					memcpy(tmp,&(rswatches[watchIndex]),sizeof(AddressWatcher));
  1.1115 +					memcpy(&(rswatches[watchIndex]),&(rswatches[watchIndex - 1]),sizeof(AddressWatcher));
  1.1116 +					memcpy(&(rswatches[watchIndex - 1]),tmp,sizeof(AddressWatcher));
  1.1117 +					free(tmp);
  1.1118 +					ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex,0,LVIS_FOCUSED|LVIS_SELECTED);
  1.1119 +					ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex-1);
  1.1120 +					ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex-1,LVIS_FOCUSED|LVIS_SELECTED,LVIS_FOCUSED|LVIS_SELECTED);
  1.1121 +					ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount);
  1.1122 +					RWfileChanged=true;
  1.1123 +					return true;
  1.1124 +				}
  1.1125 +				case IDC_C_WATCH_DOWN:
  1.1126 +				{
  1.1127 +					watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1128 +					if (watchIndex >= WatchCount - 1 || watchIndex == -1)
  1.1129 +						return true;
  1.1130 +					void *tmp = malloc(sizeof(AddressWatcher));
  1.1131 +					memcpy(tmp,&(rswatches[watchIndex]),sizeof(AddressWatcher));
  1.1132 +					memcpy(&(rswatches[watchIndex]),&(rswatches[watchIndex + 1]),sizeof(AddressWatcher));
  1.1133 +					memcpy(&(rswatches[watchIndex + 1]),tmp,sizeof(AddressWatcher));
  1.1134 +					free(tmp);
  1.1135 +					ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex,0,LVIS_FOCUSED|LVIS_SELECTED);
  1.1136 +					ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex+1);
  1.1137 +					ListView_SetItemState(GetDlgItem(hDlg,IDC_WATCHLIST),watchIndex+1,LVIS_FOCUSED|LVIS_SELECTED,LVIS_FOCUSED|LVIS_SELECTED);
  1.1138 +					ListView_SetItemCount(GetDlgItem(hDlg,IDC_WATCHLIST),WatchCount);
  1.1139 +					RWfileChanged=true;
  1.1140 +					return true;
  1.1141 +				}
  1.1142 +				case ID_WATCHES_UPDOWN:
  1.1143 +				{
  1.1144 +					int delta = ((LPNMUPDOWN)lParam)->iDelta;
  1.1145 +					SendMessage(hDlg, WM_COMMAND, delta<0 ? IDC_C_WATCH_UP : IDC_C_WATCH_DOWN,0);
  1.1146 +					break;
  1.1147 +				}
  1.1148 +				case RAMMENU_FILE_AUTOLOAD:
  1.1149 +				{
  1.1150 +					AutoRWLoad ^= 1;
  1.1151 +					CheckMenuItem(ramwatchmenu, RAMMENU_FILE_AUTOLOAD, AutoRWLoad ? MF_CHECKED : MF_UNCHECKED);
  1.1152 +					regSetDwordValue(AUTORWLOAD, AutoRWLoad);
  1.1153 +					break;
  1.1154 +				}
  1.1155 +				case RAMMENU_FILE_SAVEWINDOW:
  1.1156 +				{
  1.1157 +					RWSaveWindowPos ^=1;
  1.1158 +					CheckMenuItem(ramwatchmenu, RAMMENU_FILE_SAVEWINDOW, RWSaveWindowPos ? MF_CHECKED : MF_UNCHECKED);
  1.1159 +					regSetDwordValue(RWSAVEPOS, RWSaveWindowPos);
  1.1160 +					break;
  1.1161 +				}
  1.1162 +				case IDC_C_ADDCHEAT:
  1.1163 +				{
  1.1164 +					watchIndex = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1165 +					if(watchIndex >= 0)
  1.1166 +					{
  1.1167 +						unsigned int address = rswatches[watchIndex].Address;
  1.1168 +
  1.1169 +						int sizeType = -1;
  1.1170 +						if(rswatches[watchIndex].Size == 'b')
  1.1171 +							sizeType = 0;
  1.1172 +						else if(rswatches[watchIndex].Size == 'w')
  1.1173 +							sizeType = 1;
  1.1174 +						else if(rswatches[watchIndex].Size == 'd')
  1.1175 +							sizeType = 2;
  1.1176 +
  1.1177 +						int numberType = -1;
  1.1178 +						if(rswatches[watchIndex].Type == 's')
  1.1179 +							numberType = 0;
  1.1180 +						else if(rswatches[watchIndex].Type == 'u')
  1.1181 +							numberType = 1;
  1.1182 +						else if(rswatches[watchIndex].Type == 'h')
  1.1183 +							numberType = 2;
  1.1184 +
  1.1185 +						if(systemCartridgeType == 0)
  1.1186 +						{
  1.1187 +							AddCheat dlg (address/*, hDlg*/);
  1.1188 +							if(sizeType != -1) dlg.sizeType = sizeType;
  1.1189 +							if(numberType != -1) dlg.numberType = numberType;
  1.1190 +							systemSoundClearBuffer();
  1.1191 +							dlg.DoModal();
  1.1192 +						}
  1.1193 +						else
  1.1194 +						{
  1.1195 +							AddGBCheat dlg (address/*, hDlg*/);
  1.1196 +							if(sizeType != -1) dlg.sizeType = sizeType;
  1.1197 +							if(numberType != -1) dlg.numberType = numberType;
  1.1198 +							systemSoundClearBuffer();
  1.1199 +							dlg.DoModal();
  1.1200 +						}
  1.1201 +					}
  1.1202 +				}
  1.1203 +				break;
  1.1204 +				case IDOK:
  1.1205 +				case IDCANCEL:
  1.1206 +					RamWatchHWnd = NULL;
  1.1207 +					DragAcceptFiles(hDlg, FALSE);
  1.1208 +					EndDialog(hDlg, true);
  1.1209 +					return true;
  1.1210 +				default:
  1.1211 +					if (LOWORD(wParam) >= RW_MENU_FIRST_RECENT_FILE && LOWORD(wParam) < RW_MENU_FIRST_RECENT_FILE+MAX_RECENT_WATCHES && LOWORD(wParam) <= RW_MENU_LAST_RECENT_FILE)
  1.1212 +					OpenRWRecentFile(LOWORD(wParam) - RW_MENU_FIRST_RECENT_FILE);
  1.1213 +			}
  1.1214 +			break;
  1.1215 +
  1.1216 +#if 0
  1.1217 +		// this message is never received
  1.1218 +		case WM_KEYDOWN: // handle accelerator keys
  1.1219 +		{
  1.1220 +			SetFocus(GetDlgItem(hDlg,IDC_WATCHLIST));
  1.1221 +			MSG msg;
  1.1222 +			msg.hwnd = hDlg;
  1.1223 +			msg.message = uMsg;
  1.1224 +			msg.wParam = wParam;
  1.1225 +			msg.lParam = lParam;
  1.1226 +			if(RamWatchAccels && TranslateAccelerator(hDlg, RamWatchAccels, &msg))
  1.1227 +				return true;
  1.1228 +		}	break;
  1.1229 +#endif
  1.1230 +
  1.1231 +		case WM_CLOSE:
  1.1232 +			SendMessage(RamWatchHWnd, WM_DESTROY, 0, 0);
  1.1233 +			break;
  1.1234 +
  1.1235 +		case WM_DESTROY:
  1.1236 +			// this is the correct place
  1.1237 +			RamWatchHWnd = NULL;
  1.1238 +			DragAcceptFiles(hDlg, FALSE);
  1.1239 +			WriteRecentRWFiles();	// write recent menu to ini
  1.1240 +			break;
  1.1241 +
  1.1242 +		case WM_DROPFILES:
  1.1243 +		{
  1.1244 +			HDROP hDrop = (HDROP)wParam;
  1.1245 +			DragQueryFile(hDrop, 0, Str_Tmp, 1024);
  1.1246 +			DragFinish(hDrop);
  1.1247 +			return Load_Watches(true, Str_Tmp);
  1.1248 +		}	break;
  1.1249 +	}
  1.1250 +
  1.1251 +	return false;
  1.1252 +}