diff src/win32/ram_search.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/ram_search.cpp	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,2127 @@
     1.4 +// A few notes about this implementation of a RAM search window:
     1.5 +//
     1.6 +// Speed of update was one of the highest priories.
     1.7 +// This is because I wanted the RAM search window to be able to
     1.8 +// update every single value in RAM every single frame, and
     1.9 +// keep track of the exact number of frames across which each value has changed,
    1.10 +// without causing the emulation to run noticeably slower than normal.
    1.11 +//
    1.12 +// The data representation was changed from one entry per valid address
    1.13 +// to one entry per contiguous range of uneliminated addresses
    1.14 +// which references uniform pools of per-address properties.
    1.15 +// - This saves time when there are many items because
    1.16 +//   it minimizes the amount of data that needs to be stored and processed per address.
    1.17 +// - It also saves time when there are few items because
    1.18 +//   it ensures that no time is wasted in iterating through
    1.19 +//   addresses that have already been eliminated from the search.
    1.20 +//
    1.21 +// The worst-case scenario is when every other item has been
    1.22 +// eliminated from the search, maximizing the number of regions.
    1.23 +// This implementation manages to handle even that pathological case
    1.24 +// acceptably well. In fact, it still updates faster than the previous implementation.
    1.25 +// The time spent setting up or clearing such a large number of regions
    1.26 +// is somewhat horrendous, but it seems reasonable to have poor worst-case speed
    1.27 +// during these sporadic "setup" steps to achieve an all-around faster per-update speed.
    1.28 +// (You can test this case by performing the search: Modulo 2 Is Specific Address 0)
    1.29 +
    1.30 +
    1.31 +#ifdef _WIN32
    1.32 +	#include "stdafx.h"
    1.33 +	#include "resource.h"
    1.34 +	#include "VBA.h"
    1.35 +	//#include <windows.h>
    1.36 +	#include <commctrl.h>
    1.37 +	#include "BaseTsd.h"
    1.38 +	#include "GBACheatsDlg.h"
    1.39 +	#include "GBCheatsDlg.h"
    1.40 +	typedef INT_PTR intptr_t;
    1.41 +#else
    1.42 +	#include "stdint.h"
    1.43 +#endif
    1.44 +#include <cassert>
    1.45 +#include <list>
    1.46 +#include <vector>
    1.47 +
    1.48 +#include "ram_search.h"
    1.49 +#include "ramwatch.h"
    1.50 +#include "../gba/GBAGlobals.h"
    1.51 +#include "../gb/gbGlobals.h"
    1.52 +#include "../common/vbalua.h"
    1.53 +#include "Reg.h"
    1.54 +
    1.55 +static inline u8* HardwareToSoftwareAddress(HWAddressType address)
    1.56 +{
    1.57 +	if(!emulating)
    1.58 +		return NULL;
    1.59 +
    1.60 +	// note: this currently follows the "quick" memory rules,
    1.61 +	// meaning it will miss whatever special cases aren't handled by read/writeMemoryQuick.
    1.62 +	// if this is made more accurate, it may be necessary to reduce regionSearchGranularity.
    1.63 +	if(systemCartridgeType == 0)
    1.64 +	{
    1.65 +		// GBA
    1.66 +		HWAddressType mask = ::map[address >> 24].mask;
    1.67 +		if(!mask || (address & 0xFFFFFF) > mask)
    1.68 +			return NULL;
    1.69 +		return &::map[address >> 24].address[address & mask];
    1.70 +	}
    1.71 +	else
    1.72 +	{
    1.73 +		// GB
    1.74 +		extern int32 gbEchoRAMFixOn;
    1.75 +		if (gbEchoRAMFixOn)
    1.76 +			if (address >= 0xe000 && address < 0xfe00)
    1.77 +				address -= 0x2000;
    1.78 +		if((address>>12) >= sizeof(gbMemoryMap)/sizeof(*gbMemoryMap))
    1.79 +			return NULL;
    1.80 +		return &gbMemoryMap[address>>12][address&0xfff];
    1.81 +	}
    1.82 +}
    1.83 +
    1.84 +
    1.85 +struct MemoryRegion
    1.86 +{
    1.87 +	HWAddressType hardwareAddress; // hardware address of the start of this region
    1.88 +	unsigned int size; // number of bytes to the end of this region
    1.89 +	unsigned char* softwareAddress; // pointer to the start of the live emulator source values for this region
    1.90 +
    1.91 +	unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions()
    1.92 +	unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false
    1.93 +};
    1.94 +
    1.95 +int MAX_RAM_SIZE = 0;
    1.96 +static unsigned char* s_prevValues = 0; // values at last search or reset
    1.97 +static unsigned char* s_curValues = 0; // values at last frame update
    1.98 +static unsigned short* s_numChanges = 0; // number of changes of the item starting at this virtual index address
    1.99 +static MemoryRegion** s_itemIndexToRegionPointer = 0; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false
   1.100 +static BOOL s_itemIndicesInvalid = true; // if true, the link from listbox items to memory regions (s_itemIndexToRegionPointer) and the link from memory regions to list box items (MemoryRegion::itemIndex) both need to be recalculated
   1.101 +static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled
   1.102 +static unsigned int s_maxItemIndex = 0; // max currently valid item index, the listbox sometimes tries to update things past the end of the list so we need to know this to ignore those attempts
   1.103 +static int s_prevSelCount = -1;
   1.104 +
   1.105 +HWND RamSearchHWnd;
   1.106 +#define hWnd AfxGetMainWnd()->GetSafeHwnd()
   1.107 +#define hInst AfxGetInstanceHandle()
   1.108 +static char Str_Tmp [1024];
   1.109 +
   1.110 +int disableRamSearchUpdate = false;
   1.111 +
   1.112 +
   1.113 +
   1.114 +//static const MemoryRegion s_prgRegion    = {  0x020000, SEGACD_RAM_PRG_SIZE, (unsigned char*)Ram_Prg,     true};
   1.115 +//static const MemoryRegion s_word1MRegion = {  0x200000, SEGACD_1M_RAM_SIZE,  (unsigned char*)Ram_Word_1M, true};
   1.116 +//static const MemoryRegion s_word2MRegion = {  0x200000, SEGACD_2M_RAM_SIZE,  (unsigned char*)Ram_Word_2M, true};
   1.117 +//static const MemoryRegion s_z80Region    = {  0xA00000, Z80_RAM_SIZE,        (unsigned char*)Ram_Z80,     true};
   1.118 +//static const MemoryRegion s_68kRegion    = {  0xFF0000, _68K_RAM_SIZE,       (unsigned char*)Ram_68k,     true};
   1.119 +//static const MemoryRegion s_32xRegion    = {0x06000000, _32X_RAM_SIZE,       (unsigned char*)_32X_Ram,    false};
   1.120 +
   1.121 +// list of contiguous uneliminated memory regions
   1.122 +typedef std::list<MemoryRegion> MemoryList;
   1.123 +static MemoryList s_activeMemoryRegions;
   1.124 +static CRITICAL_SECTION s_activeMemoryRegionsCS;
   1.125 +
   1.126 +// for undo support (could be better, but this way was really easy)
   1.127 +static MemoryList s_activeMemoryRegionsBackup;
   1.128 +static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo
   1.129 +
   1.130 +void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg);
   1.131 +static const int tooManyRegionsForUndo = 10000;
   1.132 +
   1.133 +void ResetMemoryRegions()
   1.134 +{
   1.135 +	systemSoundClearBuffer();
   1.136 +	EnterCriticalSection(&s_activeMemoryRegionsCS);
   1.137 +
   1.138 +	s_activeMemoryRegions.clear();
   1.139 +
   1.140 +	// use HardwareToSoftwareAddress to figure out what all the possible memory regions are,
   1.141 +	// split up wherever there's a discontinuity in the address in our software RAM.
   1.142 +	static const int regionSearchGranularity = 0x100; // if this is too small, we'll waste time (in this function only), but if any region in RAM isn't evenly divisible by this, we might crash.
   1.143 +	HWAddressType hwRegionStart = 0;
   1.144 +	u8* regionStart = NULL;
   1.145 +	u8* regionEnd = NULL;
   1.146 +	for(HWAddressType addr = 0; addr != 0x10000000+regionSearchGranularity; addr += regionSearchGranularity)
   1.147 +	{
   1.148 +		u8* swAddr = HardwareToSoftwareAddress(addr);
   1.149 +		if(regionEnd && swAddr != regionEnd+regionSearchGranularity)
   1.150 +		{
   1.151 +			// hit end of region
   1.152 +			// check to see if it mirrors an existing one (in which case we discard it)
   1.153 +			bool discard = false;
   1.154 +			for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
   1.155 +			{
   1.156 +				MemoryRegion& region = *iter;
   1.157 +				if(region.softwareAddress == regionStart)
   1.158 +				{
   1.159 +					unsigned int size = regionSearchGranularity + (regionEnd - regionStart);
   1.160 +					if(size <= region.size)
   1.161 +					{
   1.162 +						discard = true;
   1.163 +					}
   1.164 +					else
   1.165 +					{
   1.166 +						hwRegionStart += region.size;
   1.167 +						regionStart += region.size;
   1.168 +					}
   1.169 +					break;
   1.170 +				}
   1.171 +			}
   1.172 +			
   1.173 +			// don't include ROM in our RAM search (it's too huge)
   1.174 +			if(regionStart == rom || regionStart == gbRom)
   1.175 +				discard = true;
   1.176 +
   1.177 +			// create the region
   1.178 +			if(!discard)
   1.179 +			{
   1.180 +				MemoryRegion region = { hwRegionStart, regionSearchGranularity + (regionEnd - regionStart), regionStart };
   1.181 +				s_activeMemoryRegions.push_back(region);
   1.182 +			}
   1.183 +
   1.184 +			hwRegionStart = 0;
   1.185 +			regionStart = NULL;
   1.186 +			regionEnd = NULL;
   1.187 +		}
   1.188 +		if(swAddr)
   1.189 +		{
   1.190 +			if(regionStart)
   1.191 +			{
   1.192 +				// continue region
   1.193 +				regionEnd = swAddr;
   1.194 +			}
   1.195 +			else
   1.196 +			{
   1.197 +				// start new region
   1.198 +				hwRegionStart = addr;
   1.199 +				regionStart = swAddr;
   1.200 +				regionEnd = swAddr;
   1.201 +			}
   1.202 +		}
   1.203 +	}
   1.204 +
   1.205 +
   1.206 +	int nextVirtualIndex = 0;
   1.207 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
   1.208 +	{
   1.209 +		MemoryRegion& region = *iter;
   1.210 +		region.virtualIndex = nextVirtualIndex;
   1.211 +		assert(((intptr_t)region.softwareAddress & 1) == 0 && "somebody needs to reimplement ReadValueAtSoftwareAddress()");
   1.212 +		nextVirtualIndex = region.virtualIndex + region.size;
   1.213 +	}
   1.214 +	//assert(nextVirtualIndex <= MAX_RAM_SIZE);
   1.215 +
   1.216 +	if(nextVirtualIndex > MAX_RAM_SIZE)
   1.217 +	{
   1.218 +		s_prevValues = (unsigned char*)realloc(s_prevValues, sizeof(char)*(nextVirtualIndex+4));
   1.219 +		memset(s_prevValues, 0, sizeof(char)*(nextVirtualIndex+4));
   1.220 +
   1.221 +		s_curValues = (unsigned char*)realloc(s_curValues, sizeof(char)*(nextVirtualIndex+4));
   1.222 +		memset(s_curValues, 0, sizeof(char)*(nextVirtualIndex+4));
   1.223 +
   1.224 +		s_numChanges = (unsigned short*)realloc(s_numChanges, sizeof(short)*(nextVirtualIndex+4));
   1.225 +		memset(s_numChanges, 0, sizeof(short)*(nextVirtualIndex+4));
   1.226 +
   1.227 +		s_itemIndexToRegionPointer = (MemoryRegion**)realloc(s_itemIndexToRegionPointer, sizeof(MemoryRegion*)*(nextVirtualIndex+4));
   1.228 +		memset(s_itemIndexToRegionPointer, 0, sizeof(MemoryRegion*)*(nextVirtualIndex+4));
   1.229 +
   1.230 +		MAX_RAM_SIZE = nextVirtualIndex;
   1.231 +	}
   1.232 +	LeaveCriticalSection(&s_activeMemoryRegionsCS);
   1.233 +}
   1.234 +
   1.235 +// eliminates a range of hardware addresses from the search results
   1.236 +// returns 2 if it changed the region and moved the iterator to another region
   1.237 +// returns 1 if it changed the region but didn't move the iterator
   1.238 +// returns 0 if it had no effect
   1.239 +// warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion...
   1.240 +//   doing so would be tremendously slow because DeactivateRegion invalidates the index cache
   1.241 +int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, HWAddressType hardwareAddress, unsigned int size)
   1.242 +{
   1.243 +	if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size)
   1.244 +	{
   1.245 +		// region is unaffected
   1.246 +		return 0;
   1.247 +	}
   1.248 +	else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size)
   1.249 +	{
   1.250 +		// erase end of region
   1.251 +		region.size = hardwareAddress - region.hardwareAddress;
   1.252 +		return 1;
   1.253 +	}
   1.254 +	else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size)
   1.255 +	{
   1.256 +		// erase start of region
   1.257 +		int eraseSize = (hardwareAddress + size) - region.hardwareAddress;
   1.258 +		region.hardwareAddress += eraseSize;
   1.259 +		region.size -= eraseSize;
   1.260 +		region.softwareAddress += eraseSize;
   1.261 +		region.virtualIndex += eraseSize;
   1.262 +		return 1;
   1.263 +	}
   1.264 +	else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size)
   1.265 +	{
   1.266 +		// erase entire region
   1.267 +		iter = s_activeMemoryRegions.erase(iter);
   1.268 +		s_itemIndicesInvalid = TRUE;
   1.269 +		return 2;
   1.270 +	}
   1.271 +	else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size)
   1.272 +	{
   1.273 +		// split region
   1.274 +		int eraseSize = (hardwareAddress + size) - region.hardwareAddress;
   1.275 +		MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.softwareAddress + eraseSize, region.virtualIndex + eraseSize};
   1.276 +		region.size = hardwareAddress - region.hardwareAddress;
   1.277 +		iter = s_activeMemoryRegions.insert(++iter, region2);
   1.278 +		s_itemIndicesInvalid = TRUE;
   1.279 +		return 2;
   1.280 +	}
   1.281 +}
   1.282 +
   1.283 +/*
   1.284 +// eliminates a range of hardware addresses from the search results
   1.285 +// this is a simpler but usually slower interface for the above function
   1.286 +void DeactivateRegion(HWAddressType hardwareAddress, unsigned int size)
   1.287 +{
   1.288 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
   1.289 +	{
   1.290 +		MemoryRegion& region = *iter;
   1.291 +		if(2 != DeactivateRegion(region, iter, hardwareAddress, size))
   1.292 +			++iter;
   1.293 +	}
   1.294 +}
   1.295 +*/
   1.296 +
   1.297 +struct AutoCritSect
   1.298 +{
   1.299 +	AutoCritSect(CRITICAL_SECTION* cs) : m_cs(cs) { EnterCriticalSection(m_cs); }
   1.300 +	~AutoCritSect() { LeaveCriticalSection(m_cs); }
   1.301 +	CRITICAL_SECTION* m_cs;
   1.302 +};
   1.303 +
   1.304 +// warning: can be slow
   1.305 +void CalculateItemIndices(int itemSize)
   1.306 +{
   1.307 +	AutoCritSect cs(&s_activeMemoryRegionsCS);
   1.308 +	unsigned int itemIndex = 0;
   1.309 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
   1.310 +	{
   1.311 +		MemoryRegion& region = *iter;
   1.312 +		region.itemIndex = itemIndex;
   1.313 +		int startSkipSize = ((unsigned int)(itemSize - (unsigned int)region.hardwareAddress)) % itemSize; // FIXME: is this still ok?
   1.314 +		unsigned int start = startSkipSize;
   1.315 +		unsigned int end = region.size;
   1.316 +		for(unsigned int i = start; i < end; i += itemSize)
   1.317 +			s_itemIndexToRegionPointer[itemIndex++] = &region;
   1.318 +	}
   1.319 +	s_maxItemIndex = itemIndex;
   1.320 +	s_itemIndicesInvalid = FALSE;
   1.321 +}
   1.322 +
   1.323 +template<typename stepType, typename compareType>
   1.324 +void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr)
   1.325 +{
   1.326 +	//if(GetAsyncKeyState(VK_SHIFT) & 0x8000) // speed hack
   1.327 +	//	return;
   1.328 +
   1.329 +	if(s_prevValuesNeedUpdate)
   1.330 +		memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType));
   1.331 +
   1.332 +	unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
   1.333 +
   1.334 +
   1.335 +	unsigned char* sourceAddr = region.softwareAddress - region.virtualIndex;
   1.336 +
   1.337 +	unsigned int indexStart = region.virtualIndex + startSkipSize;
   1.338 +	unsigned int indexEnd = region.virtualIndex + region.size;
   1.339 +
   1.340 +	if(sizeof(compareType) == 1)
   1.341 +	{
   1.342 +		for(unsigned int i = indexStart; i < indexEnd; i++)
   1.343 +		{
   1.344 +			if(s_curValues[i] != sourceAddr[i]) // if value changed
   1.345 +			{
   1.346 +				s_curValues[i] = sourceAddr[i]; // update value
   1.347 +				//if(s_numChanges[i] != 0xFFFF)
   1.348 +					s_numChanges[i]++; // increase change count
   1.349 +			}
   1.350 +		}
   1.351 +	}
   1.352 +	else // it's more complicated for non-byte sizes because:
   1.353 +	{    // - more than one byte can affect a given change count entry
   1.354 +	     // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1
   1.355 +	     // - a few of those bytes can be outside the region
   1.356 +
   1.357 +		unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType);
   1.358 +		unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType);
   1.359 +		unsigned int lastIndexToCopy = lastIndexToRead;
   1.360 +		if(nextRegionPtr)
   1.361 +		{
   1.362 +			const MemoryRegion& nextRegion = *nextRegionPtr;
   1.363 +			int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType);
   1.364 +			unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize;
   1.365 +			if(lastIndexToCopy > nextIndexStart)
   1.366 +				lastIndexToCopy = nextIndexStart;
   1.367 +		}
   1.368 +
   1.369 +		unsigned int nextValidChange [sizeof(compareType)];
   1.370 +		for(unsigned int i = 0; i < sizeof(compareType); i++)
   1.371 +			nextValidChange[i] = indexStart + i;
   1.372 +
   1.373 +		for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++)
   1.374 +		{
   1.375 +			if(s_curValues[i] != sourceAddr[i]) // if value of this byte changed
   1.376 +			{
   1.377 +				if(i < lastIndexToCopy)
   1.378 +					s_curValues[i] = sourceAddr[i]; // update value
   1.379 +				for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte
   1.380 +				{
   1.381 +					if(i >= indexEnd+k)
   1.382 +						continue;
   1.383 +					int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1);
   1.384 +					if(nextValidChange[m] <= i) // if we didn't already increase the change count for this entry
   1.385 +					{
   1.386 +						//if(s_numChanges[i-k] != 0xFFFF)
   1.387 +							s_numChanges[i-k]++; // increase the change count for this entry
   1.388 +						nextValidChange[m] = i-k+sizeof(compareType); // and remember not to increase it again
   1.389 +					}
   1.390 +				}
   1.391 +			}
   1.392 +		}
   1.393 +	}
   1.394 +}
   1.395 +
   1.396 +template<typename stepType, typename compareType>
   1.397 +void UpdateRegionsT()
   1.398 +{
   1.399 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();)
   1.400 +	{
   1.401 +		const MemoryRegion& region = *iter;
   1.402 +		++iter;
   1.403 +		const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter;
   1.404 +
   1.405 +		UpdateRegionT<stepType, compareType>(region, nextRegion);
   1.406 +	}
   1.407 +
   1.408 +	s_prevValuesNeedUpdate = false;
   1.409 +}
   1.410 +
   1.411 +template<typename stepType, typename compareType>
   1.412 +int CountRegionItemsT()
   1.413 +{
   1.414 +	AutoCritSect cs(&s_activeMemoryRegionsCS);
   1.415 +	if(sizeof(stepType) == 1)
   1.416 +	{
   1.417 +		if(s_activeMemoryRegions.empty())
   1.418 +			return 0;
   1.419 +
   1.420 +		if(s_itemIndicesInvalid)
   1.421 +			CalculateItemIndices(sizeof(stepType));
   1.422 +
   1.423 +		MemoryRegion& lastRegion = s_activeMemoryRegions.back();
   1.424 +		return lastRegion.itemIndex + lastRegion.size;
   1.425 +	}
   1.426 +	else // the branch above is faster but won't work if the step size isn't 1
   1.427 +	{
   1.428 +		int total = 0;
   1.429 +		for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
   1.430 +		{
   1.431 +			MemoryRegion& region = *iter;
   1.432 +			int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
   1.433 +			total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType);
   1.434 +		}
   1.435 +		return total;
   1.436 +	}
   1.437 +}
   1.438 +
   1.439 +// returns information about the item in the form of a "fake" region
   1.440 +// that has the item in it and nothing else
   1.441 +template<typename stepType, typename compareType>
   1.442 +void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion)
   1.443 +{
   1.444 +	if(s_itemIndicesInvalid)
   1.445 +		CalculateItemIndices(sizeof(stepType));
   1.446 +
   1.447 +	if(itemIndex >= s_maxItemIndex)
   1.448 +	{
   1.449 +		memset(&virtualRegion, 0, sizeof(MemoryRegion));
   1.450 +		return;
   1.451 +	}
   1.452 +
   1.453 +	const MemoryRegion* regionPtr = s_itemIndexToRegionPointer[itemIndex];
   1.454 +	const MemoryRegion& region = *regionPtr;
   1.455 +
   1.456 +	int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType);
   1.457 +	int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
   1.458 +	bytesWithinRegion += startSkipSize;
   1.459 +	
   1.460 +	virtualRegion.size = sizeof(compareType);
   1.461 +	virtualRegion.hardwareAddress = region.hardwareAddress + bytesWithinRegion;
   1.462 +	virtualRegion.softwareAddress = region.softwareAddress + bytesWithinRegion;
   1.463 +	virtualRegion.virtualIndex = region.virtualIndex + bytesWithinRegion;
   1.464 +	virtualRegion.itemIndex = itemIndex;
   1.465 +	return;
   1.466 +}
   1.467 +
   1.468 +template<typename stepType, typename compareType>
   1.469 +unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex)
   1.470 +{
   1.471 +	MemoryRegion virtualRegion;
   1.472 +	ItemIndexToVirtualRegion<stepType,compareType>(itemIndex, virtualRegion);
   1.473 +	return virtualRegion.virtualIndex;
   1.474 +}
   1.475 +
   1.476 +template<typename T>
   1.477 +T ReadLocalValue(const unsigned char* data)
   1.478 +{
   1.479 +	return *(const T*)data;
   1.480 +}
   1.481 +//template<> signed char ReadLocalValue(const unsigned char* data) { return *data; }
   1.482 +//template<> unsigned char ReadLocalValue(const unsigned char* data) { return *data; }
   1.483 +
   1.484 +
   1.485 +template<typename stepType, typename compareType>
   1.486 +compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex)
   1.487 +{
   1.488 +	return ReadLocalValue<compareType>(s_prevValues + virtualIndex);
   1.489 +	//return *(compareType*)(s_prevValues+virtualIndex);
   1.490 +}
   1.491 +template<typename stepType, typename compareType>
   1.492 +compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex)
   1.493 +{
   1.494 +	return ReadLocalValue<compareType>(s_curValues + virtualIndex);
   1.495 +//	return *(compareType*)(s_curValues+virtualIndex);
   1.496 +}
   1.497 +template<typename stepType, typename compareType>
   1.498 +unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex)
   1.499 +{
   1.500 +	unsigned short num = s_numChanges[virtualIndex];
   1.501 +	//for(unsigned int i = 1; i < sizeof(stepType); i++)
   1.502 +	//	if(num < s_numChanges[virtualIndex+i])
   1.503 +	//		num = s_numChanges[virtualIndex+i];
   1.504 +	return num;
   1.505 +}
   1.506 +
   1.507 +template<typename stepType, typename compareType>
   1.508 +compareType GetPrevValueFromItemIndex(unsigned int itemIndex)
   1.509 +{
   1.510 +	int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);
   1.511 +	return GetPrevValueFromVirtualIndex<stepType,compareType>(virtualIndex);
   1.512 +}
   1.513 +template<typename stepType, typename compareType>
   1.514 +compareType GetCurValueFromItemIndex(unsigned int itemIndex)
   1.515 +{
   1.516 +	int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);
   1.517 +	return GetCurValueFromVirtualIndex<stepType,compareType>(virtualIndex);
   1.518 +}
   1.519 +template<typename stepType, typename compareType>
   1.520 +unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex)
   1.521 +{
   1.522 +	int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);
   1.523 +	return GetNumChangesFromVirtualIndex<stepType,compareType>(virtualIndex);
   1.524 +}
   1.525 +template<typename stepType, typename compareType>
   1.526 +unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex)
   1.527 +{
   1.528 +	MemoryRegion virtualRegion;
   1.529 +	ItemIndexToVirtualRegion<stepType,compareType>(itemIndex, virtualRegion);
   1.530 +	return virtualRegion.hardwareAddress;
   1.531 +}
   1.532 +
   1.533 +// this one might be unreliable, haven't used it much
   1.534 +template<typename stepType, typename compareType>
   1.535 +unsigned int HardwareAddressToItemIndex(HWAddressType hardwareAddress)
   1.536 +{
   1.537 +	if(s_itemIndicesInvalid)
   1.538 +		CalculateItemIndices(sizeof(stepType));
   1.539 +
   1.540 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)
   1.541 +	{
   1.542 +		MemoryRegion& region = *iter;
   1.543 +		if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size)
   1.544 +		{
   1.545 +			int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType);
   1.546 +			return region.itemIndex + indexWithinRegion;
   1.547 +		}
   1.548 +	}
   1.549 +
   1.550 +	return -1;
   1.551 +}
   1.552 +
   1.553 +
   1.554 +
   1.555 +// workaround for MSVC 7 that doesn't support varadic C99 macros
   1.556 +#define CALL_WITH_T_SIZE_TYPES_0(functionName, sizeTypeID, isSigned, requiresAligned) \
   1.557 +	(sizeTypeID == 'b' \
   1.558 +		? (isSigned \
   1.559 +			? functionName<char, signed char>() \
   1.560 +			: functionName<char, unsigned char>()) \
   1.561 +	: sizeTypeID == 'w' \
   1.562 +		? (isSigned \
   1.563 +			? (requiresAligned \
   1.564 +				? functionName<short, signed short>() \
   1.565 +				: functionName<char, signed short>()) \
   1.566 +			: (requiresAligned \
   1.567 +				? functionName<short, unsigned short>() \
   1.568 +				: functionName<char, unsigned short>())) \
   1.569 +	: sizeTypeID == 'd' \
   1.570 +		? (isSigned \
   1.571 +			? (requiresAligned \
   1.572 +				? functionName<short, signed long>() \
   1.573 +				: functionName<char, signed long>()) \
   1.574 +			: (requiresAligned \
   1.575 +				? functionName<short, unsigned long>() \
   1.576 +				: functionName<char, unsigned long>())) \
   1.577 +	: functionName<char, signed char>())
   1.578 +
   1.579 +#define CALL_WITH_T_SIZE_TYPES_1(functionName, sizeTypeID, isSigned, requiresAligned, p0) \
   1.580 +	(sizeTypeID == 'b' \
   1.581 +		? (isSigned \
   1.582 +			? functionName<char, signed char>(p0) \
   1.583 +			: functionName<char, unsigned char>(p0)) \
   1.584 +	: sizeTypeID == 'w' \
   1.585 +		? (isSigned \
   1.586 +			? (requiresAligned \
   1.587 +				? functionName<short, signed short>(p0) \
   1.588 +				: functionName<char, signed short>(p0)) \
   1.589 +			: (requiresAligned \
   1.590 +				? functionName<short, unsigned short>(p0) \
   1.591 +				: functionName<char, unsigned short>(p0))) \
   1.592 +	: sizeTypeID == 'd' \
   1.593 +		? (isSigned \
   1.594 +			? (requiresAligned \
   1.595 +				? functionName<short, signed long>(p0) \
   1.596 +				: functionName<char, signed long>(p0)) \
   1.597 +			: (requiresAligned \
   1.598 +				? functionName<short, unsigned long>(p0) \
   1.599 +				: functionName<char, unsigned long>(p0))) \
   1.600 +	: functionName<char, signed char>(p0))
   1.601 +
   1.602 +#define CALL_WITH_T_SIZE_TYPES_3(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2) \
   1.603 +	(sizeTypeID == 'b' \
   1.604 +		? (isSigned \
   1.605 +			? functionName<char, signed char>(p0, p1, p2) \
   1.606 +			: functionName<char, unsigned char>(p0, p1, p2)) \
   1.607 +	: sizeTypeID == 'w' \
   1.608 +		? (isSigned \
   1.609 +			? (requiresAligned \
   1.610 +				? functionName<short, signed short>(p0, p1, p2) \
   1.611 +				: functionName<char, signed short>(p0, p1, p2)) \
   1.612 +			: (requiresAligned \
   1.613 +				? functionName<short, unsigned short>(p0, p1, p2) \
   1.614 +				: functionName<char, unsigned short>(p0, p1, p2))) \
   1.615 +	: sizeTypeID == 'd' \
   1.616 +		? (isSigned \
   1.617 +			? (requiresAligned \
   1.618 +				? functionName<short, signed long>(p0, p1, p2) \
   1.619 +				: functionName<char, signed long>(p0, p1, p2)) \
   1.620 +			: (requiresAligned \
   1.621 +				? functionName<short, unsigned long>(p0, p1, p2) \
   1.622 +				: functionName<char, unsigned long>(p0, p1, p2))) \
   1.623 +	: functionName<char, signed char>(p0, p1, p2))
   1.624 +
   1.625 +#define CALL_WITH_T_SIZE_TYPES_4(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2, p3) \
   1.626 +	(sizeTypeID == 'b' \
   1.627 +		? (isSigned \
   1.628 +			? functionName<char, signed char>(p0, p1, p2, p3) \
   1.629 +			: functionName<char, unsigned char>(p0, p1, p2, p3)) \
   1.630 +	: sizeTypeID == 'w' \
   1.631 +		? (isSigned \
   1.632 +			? (requiresAligned \
   1.633 +				? functionName<short, signed short>(p0, p1, p2, p3) \
   1.634 +				: functionName<char, signed short>(p0, p1, p2, p3)) \
   1.635 +			: (requiresAligned \
   1.636 +				? functionName<short, unsigned short>(p0, p1, p2, p3) \
   1.637 +				: functionName<char, unsigned short>(p0, p1, p2, p3))) \
   1.638 +	: sizeTypeID == 'd' \
   1.639 +		? (isSigned \
   1.640 +			? (requiresAligned \
   1.641 +				? functionName<short, signed long>(p0, p1, p2, p3) \
   1.642 +				: functionName<char, signed long>(p0, p1, p2, p3)) \
   1.643 +			: (requiresAligned \
   1.644 +				? functionName<short, unsigned long>(p0, p1, p2, p3) \
   1.645 +				: functionName<char, unsigned long>(p0, p1, p2, p3))) \
   1.646 +	: functionName<char, signed char>(p0, p1, p2, p3))
   1.647 +
   1.648 +// version that takes a forced comparison type
   1.649 +#define CALL_WITH_T_STEP_3(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2) \
   1.650 +	(sizeTypeID == 'b' \
   1.651 +		? functionName<char, type>(p0, p1, p2) \
   1.652 +	: sizeTypeID == 'w' \
   1.653 +		? (requiresAligned \
   1.654 +			? functionName<short, type>(p0, p1, p2) \
   1.655 +			: functionName<char, type>(p0, p1, p2)) \
   1.656 +	: sizeTypeID == 'd' \
   1.657 +		? (requiresAligned \
   1.658 +			? functionName<short, type>(p0, p1, p2) \
   1.659 +			: functionName<char, type>(p0, p1, p2)) \
   1.660 +	: functionName<char, type>(p0, p1, p2))
   1.661 +
   1.662 +// version that takes a forced comparison type
   1.663 +#define CALL_WITH_T_STEP_4(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2, p3) \
   1.664 +	(sizeTypeID == 'b' \
   1.665 +		? functionName<char, type>(p0, p1, p2, p3) \
   1.666 +	: sizeTypeID == 'w' \
   1.667 +		? (requiresAligned \
   1.668 +			? functionName<short, type>(p0, p1, p2, p3) \
   1.669 +			: functionName<char, type>(p0, p1, p2, p3)) \
   1.670 +	: sizeTypeID == 'd' \
   1.671 +		? (requiresAligned \
   1.672 +			? functionName<short, type>(p0, p1, p2, p3) \
   1.673 +			: functionName<char, type>(p0, p1, p2, p3)) \
   1.674 +	: functionName<char, type>(p0, p1, p2, p3))
   1.675 +
   1.676 +// basic comparison functions:
   1.677 +template <typename T> inline bool LessCmp (T x, T y, T i)        { return x < y; }
   1.678 +template <typename T> inline bool MoreCmp (T x, T y, T i)        { return x > y; }
   1.679 +template <typename T> inline bool LessEqualCmp (T x, T y, T i)   { return x <= y; }
   1.680 +template <typename T> inline bool MoreEqualCmp (T x, T y, T i)   { return x >= y; }
   1.681 +template <typename T> inline bool EqualCmp (T x, T y, T i)       { return x == y; }
   1.682 +template <typename T> inline bool UnequalCmp (T x, T y, T i)     { return x != y; }
   1.683 +template <typename T> inline bool DiffByCmp (T x, T y, T p)      { return x - y == p || y - x == p; }
   1.684 +template <typename T> inline bool ModIsCmp (T x, T y, T p)       { return p && x % p == y; }
   1.685 +
   1.686 +// compare-to type functions:
   1.687 +template<typename stepType, typename T>
   1.688 +void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param)
   1.689 +{
   1.690 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
   1.691 +	{
   1.692 +		MemoryRegion& region = *iter;
   1.693 +		int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
   1.694 +		unsigned int start = region.virtualIndex + startSkipSize;
   1.695 +		unsigned int end = region.virtualIndex + region.size;
   1.696 +		for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
   1.697 +			if(!cmpFun(GetCurValueFromVirtualIndex<stepType,T>(i), GetPrevValueFromVirtualIndex<stepType,T>(i), param))
   1.698 +				if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
   1.699 +					goto outerContinue;
   1.700 +		++iter;
   1.701 +outerContinue:
   1.702 +		continue;
   1.703 +	}
   1.704 +}
   1.705 +template<typename stepType, typename T>
   1.706 +void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param)
   1.707 +{
   1.708 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
   1.709 +	{
   1.710 +		MemoryRegion& region = *iter;
   1.711 +		int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
   1.712 +		unsigned int start = region.virtualIndex + startSkipSize;
   1.713 +		unsigned int end = region.virtualIndex + region.size;
   1.714 +		for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
   1.715 +			if(!cmpFun(GetCurValueFromVirtualIndex<stepType,T>(i), value, param))
   1.716 +				if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
   1.717 +					goto outerContinue;
   1.718 +		++iter;
   1.719 +outerContinue:
   1.720 +		continue;
   1.721 +	}
   1.722 +}
   1.723 +template<typename stepType, typename T>
   1.724 +void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param)
   1.725 +{
   1.726 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
   1.727 +	{
   1.728 +		MemoryRegion& region = *iter;
   1.729 +		int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
   1.730 +		unsigned int start = region.virtualIndex + startSkipSize;
   1.731 +		unsigned int end = region.virtualIndex + region.size;
   1.732 +		for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
   1.733 +			if(!cmpFun(hwaddr, address, param))
   1.734 +				if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
   1.735 +					goto outerContinue;
   1.736 +		++iter;
   1.737 +outerContinue:
   1.738 +		continue;
   1.739 +	}
   1.740 +}
   1.741 +template<typename stepType, typename T>
   1.742 +void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param)
   1.743 +{
   1.744 +	for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )
   1.745 +	{
   1.746 +		MemoryRegion& region = *iter;
   1.747 +		int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);
   1.748 +		unsigned int start = region.virtualIndex + startSkipSize;
   1.749 +		unsigned int end = region.virtualIndex + region.size;
   1.750 +		for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))
   1.751 +			if(!cmpFun(GetNumChangesFromVirtualIndex<stepType,T>(i), changes, param))
   1.752 +				if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))
   1.753 +					goto outerContinue;
   1.754 +		++iter;
   1.755 +outerContinue:
   1.756 +		continue;
   1.757 +	}
   1.758 +}
   1.759 +
   1.760 +char rs_c='s';
   1.761 +char rs_o='=';
   1.762 +char rs_t='s';
   1.763 +int rs_param=0, rs_val=0, rs_val_valid=0;
   1.764 +char rs_type_size = 'b', rs_last_type_size = rs_type_size;
   1.765 +bool noMisalign = true, rs_last_no_misalign = noMisalign;
   1.766 +//bool littleEndian = false;
   1.767 +int last_rs_possible = -1;
   1.768 +int last_rs_regions = -1;
   1.769 +
   1.770 +void prune(char c,char o,char t,int v,int p)
   1.771 +{
   1.772 +	// repetition-reducing macros
   1.773 +	#define DO_SEARCH(sf) \
   1.774 +	switch (o) \
   1.775 +	{ \
   1.776 +		case '<': DO_SEARCH_2(LessCmp,sf); break; \
   1.777 +		case '>': DO_SEARCH_2(MoreCmp,sf); break; \
   1.778 +		case '=': DO_SEARCH_2(EqualCmp,sf); break; \
   1.779 +		case '!': DO_SEARCH_2(UnequalCmp,sf); break; \
   1.780 +		case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \
   1.781 +		case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \
   1.782 +		case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \
   1.783 +		case '%': DO_SEARCH_2(ModIsCmp,sf); break; \
   1.784 +		default: assert(!"Invalid operator for this search type."); break; \
   1.785 +	}
   1.786 +
   1.787 +	// perform the search, eliminating nonmatching values
   1.788 +	switch (c)
   1.789 +	{
   1.790 +		#define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES_3(sf, rs_type_size, t, noMisalign, CmpFun,v,p)
   1.791 +		case 'r': DO_SEARCH(SearchRelative); break;
   1.792 +		case 's': DO_SEARCH(SearchSpecific); break;
   1.793 +
   1.794 +		#undef DO_SEARCH_2
   1.795 +		#define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned int, noMisalign, CmpFun,v,p)
   1.796 +		case 'a': DO_SEARCH(SearchAddress); break;
   1.797 +
   1.798 +		#undef DO_SEARCH_2
   1.799 +		#define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned short, noMisalign, CmpFun,v,p)
   1.800 +		case 'n': DO_SEARCH(SearchChanges); break;
   1.801 +
   1.802 +		default: assert(!"Invalid search comparison type."); break;
   1.803 +	}
   1.804 +
   1.805 +	s_prevValuesNeedUpdate = true;
   1.806 +
   1.807 +	int prevNumItems = last_rs_possible;
   1.808 +
   1.809 +	CompactAddrs();
   1.810 +
   1.811 +	if(prevNumItems == last_rs_possible)
   1.812 +	{
   1.813 +		SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo
   1.814 +	}
   1.815 +}
   1.816 +
   1.817 +
   1.818 +
   1.819 +
   1.820 +template<typename stepType, typename T>
   1.821 +bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param)
   1.822 +{
   1.823 +	return cmpFun(GetCurValueFromItemIndex<stepType,T>(itemIndex), GetPrevValueFromItemIndex<stepType,T>(itemIndex), param);
   1.824 +}
   1.825 +template<typename stepType, typename T>
   1.826 +bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param)
   1.827 +{
   1.828 +	return cmpFun(GetCurValueFromItemIndex<stepType,T>(itemIndex), value, param);
   1.829 +}
   1.830 +template<typename stepType, typename T>
   1.831 +bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param)
   1.832 +{
   1.833 +	return cmpFun(GetHardwareAddressFromItemIndex<stepType,T>(itemIndex), address, param);
   1.834 +}
   1.835 +template<typename stepType, typename T>
   1.836 +bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param)
   1.837 +{
   1.838 +	return cmpFun(GetNumChangesFromItemIndex<stepType,T>(itemIndex), changes, param);
   1.839 +}
   1.840 +
   1.841 +int ReadControlInt(int controlID, bool forceHex, BOOL& success)
   1.842 +{
   1.843 +	int rv = 0;
   1.844 +	BOOL ok = false;
   1.845 +
   1.846 +	if(!forceHex)
   1.847 +	{
   1.848 +		rv = GetDlgItemInt(RamSearchHWnd,controlID,&ok,(rs_t == 's'));
   1.849 +	}
   1.850 +
   1.851 +	if(!ok)
   1.852 +	{
   1.853 +		if(GetDlgItemText(RamSearchHWnd,controlID,Str_Tmp,16))
   1.854 +		{
   1.855 +			for(int i = 0; Str_Tmp[i]; i++) {if(toupper(Str_Tmp[i]) == 'O') Str_Tmp[i] = '0';}
   1.856 +			const char* strPtr = Str_Tmp;
   1.857 +			bool negate = false;
   1.858 +			while(strPtr[0] == '-')
   1.859 +				strPtr++, negate = !negate;
   1.860 +			if(strPtr[0] == '+')
   1.861 +				strPtr++;
   1.862 +			if(strPtr[0] == '0' && tolower(strPtr[1]) == 'x')
   1.863 +				strPtr += 2, forceHex = true;
   1.864 +			if(strPtr[0] == '$')
   1.865 +				strPtr++, forceHex = true;
   1.866 +			if(!forceHex)
   1.867 +			{
   1.868 +				const char* strSearchPtr = strPtr;
   1.869 +				while(*strSearchPtr)
   1.870 +				{
   1.871 +					int c = tolower(*strSearchPtr++);
   1.872 +					if(c >= 'a' && c <= 'f')
   1.873 +						forceHex = true;
   1.874 +				}
   1.875 +			}
   1.876 +			const char* formatString = forceHex ? "%X" : ((rs_t=='s') ? "%d" : "%u");
   1.877 +			if(sscanf(strPtr, formatString, &rv) > 0)
   1.878 +				ok = true;
   1.879 +			if(negate)
   1.880 +				rv = -rv;
   1.881 +		}
   1.882 +	}
   1.883 +
   1.884 +	success = ok;
   1.885 +	return rv;
   1.886 +}
   1.887 +
   1.888 +
   1.889 +bool Set_RS_Val()
   1.890 +{
   1.891 +	BOOL success;
   1.892 +
   1.893 +	// update rs_val
   1.894 +	switch(rs_c)
   1.895 +	{
   1.896 +		case 'r':
   1.897 +		default:
   1.898 +			rs_val = 0;
   1.899 +			break;
   1.900 +		case 's':
   1.901 +			rs_val = ReadControlInt(IDC_EDIT_COMPAREVALUE, rs_t == 'h', success);
   1.902 +			if(!success)
   1.903 +				return false;
   1.904 +			if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) ||
   1.905 +			   (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) ||
   1.906 +			   (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) ||
   1.907 +			   (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535)))
   1.908 +			   return false;
   1.909 +			break;
   1.910 +		case 'a':
   1.911 +			rs_val = ReadControlInt(IDC_EDIT_COMPAREADDRESS, true, success);
   1.912 +			if(!success || rs_val < 0 || rs_val > 0x06040000)
   1.913 +				return false;
   1.914 +			break;
   1.915 +		case 'n': {
   1.916 +			rs_val = ReadControlInt(IDC_EDIT_COMPARECHANGES, false, success);
   1.917 +			if(!success || rs_val < 0 || rs_val > 0xFFFF)
   1.918 +				return false;
   1.919 +		}	break;
   1.920 +	}
   1.921 +
   1.922 +	// also update rs_param
   1.923 +	switch(rs_o)
   1.924 +	{
   1.925 +		default:
   1.926 +			rs_param = 0;
   1.927 +			break;
   1.928 +		case 'd':
   1.929 +			rs_param = ReadControlInt(IDC_EDIT_DIFFBY, false, success);
   1.930 +			if(!success)
   1.931 +				return false;
   1.932 +			if(rs_param < 0)
   1.933 +				rs_param = -rs_param;
   1.934 +			break;
   1.935 +		case '%':
   1.936 +			rs_param = ReadControlInt(IDC_EDIT_MODBY, false, success);
   1.937 +			if(!success || rs_param == 0)
   1.938 +				return false;
   1.939 +			break;
   1.940 +	}
   1.941 +
   1.942 +	// validate that rs_param fits in the comparison data type
   1.943 +	{
   1.944 +		int appliedSize = rs_type_size;
   1.945 +		int appliedSign = rs_t;
   1.946 +		if(rs_c == 'n')
   1.947 +			appliedSize = 'w', appliedSign = 'u';
   1.948 +		if(rs_c == 'a')
   1.949 +			appliedSize = 'd', appliedSign = 'u';
   1.950 +		if((appliedSize == 'b' && appliedSize == 's' && (rs_param < -128 || rs_param > 127)) ||
   1.951 +		   (appliedSize == 'b' && appliedSize != 's' && (rs_param < 0 || rs_param > 255)) ||
   1.952 +		   (appliedSize == 'w' && appliedSize == 's' && (rs_param < -32768 || rs_param > 32767)) ||
   1.953 +		   (appliedSize == 'w' && appliedSize != 's' && (rs_param < 0 || rs_param > 65535)))
   1.954 +		   return false;
   1.955 +	}
   1.956 +
   1.957 +	return true;
   1.958 +}
   1.959 +
   1.960 +bool IsSatisfied(int itemIndex)
   1.961 +{
   1.962 +	if(!rs_val_valid)
   1.963 +		return true;
   1.964 +	int o = rs_o;
   1.965 +	switch (rs_c)
   1.966 +	{
   1.967 +		#undef DO_SEARCH_2
   1.968 +		#define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_SIZE_TYPES_4(sf, rs_type_size,(rs_t=='s'),noMisalign, CmpFun,itemIndex,rs_val,rs_param);
   1.969 +		case 'r': DO_SEARCH(CompareRelativeAtItem); break;
   1.970 +		case 's': DO_SEARCH(CompareSpecificAtItem); break;
   1.971 +
   1.972 +		#undef DO_SEARCH_2
   1.973 +		#define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned int, noMisalign, CmpFun,itemIndex,rs_val,rs_param);
   1.974 +		case 'a': DO_SEARCH(CompareAddressAtItem); break;
   1.975 +
   1.976 +		#undef DO_SEARCH_2
   1.977 +		#define DO_SEARCH_2(CmpFun,sf) return CALL_WITH_T_STEP_4(sf, rs_type_size, unsigned short, noMisalign, CmpFun,itemIndex,rs_val,rs_param);
   1.978 +		case 'n': DO_SEARCH(CompareChangesAtItem); break;
   1.979 +	}
   1.980 +	return false;
   1.981 +}
   1.982 +
   1.983 +
   1.984 +
   1.985 +unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size)
   1.986 +{
   1.987 +	unsigned int value = 0;
   1.988 +	if(address)
   1.989 +	{
   1.990 +		// assumes we're little-endian
   1.991 +		memcpy(&value, address, size);
   1.992 +	}
   1.993 +	return value;
   1.994 +}
   1.995 +void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size)
   1.996 +{
   1.997 +	if(address)
   1.998 +	{
   1.999 +		// assumes we're little-endian
  1.1000 +		memcpy(address, &value, size);
  1.1001 +	}
  1.1002 +}
  1.1003 +unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size)
  1.1004 +{
  1.1005 +	return ReadValueAtSoftwareAddress(HardwareToSoftwareAddress(address), size);
  1.1006 +}
  1.1007 +bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsigned int size)
  1.1008 +{
  1.1009 +	WriteValueAtSoftwareAddress(HardwareToSoftwareAddress(address), value, size);
  1.1010 +	return true;
  1.1011 +}
  1.1012 +bool IsHardwareAddressValid(HWAddressType address)
  1.1013 +{
  1.1014 +	return HardwareToSoftwareAddress(address) != NULL;
  1.1015 +}
  1.1016 +
  1.1017 +
  1.1018 +
  1.1019 +int ResultCount=0;
  1.1020 +bool AutoSearch=false;
  1.1021 +bool AutoSearchAutoRetry=false;
  1.1022 +LRESULT CALLBACK PromptWatchNameProc(HWND, UINT, WPARAM, LPARAM);
  1.1023 +void UpdatePossibilities(int rs_possible, int regions);
  1.1024 +
  1.1025 +
  1.1026 +void CompactAddrs()
  1.1027 +{
  1.1028 +	int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2;
  1.1029 +	int prevResultCount = ResultCount;
  1.1030 +
  1.1031 +	CalculateItemIndices(size);
  1.1032 +	ResultCount = CALL_WITH_T_SIZE_TYPES_0(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign);
  1.1033 +
  1.1034 +	UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size());
  1.1035 +
  1.1036 +	if(ResultCount != prevResultCount)
  1.1037 +		ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount);
  1.1038 +}
  1.1039 +
  1.1040 +void soft_reset_address_info ()
  1.1041 +{
  1.1042 +	s_prevValuesNeedUpdate = false;
  1.1043 +	ResetMemoryRegions();
  1.1044 +	if(!RamSearchHWnd)
  1.1045 +	{
  1.1046 +		EnterCriticalSection(&s_activeMemoryRegionsCS);
  1.1047 +		s_activeMemoryRegions.clear();
  1.1048 +		LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.1049 +		ResultCount = 0;
  1.1050 +	}
  1.1051 +	else
  1.1052 +	{
  1.1053 +		// force s_prevValues to be valid
  1.1054 +		signal_new_frame();
  1.1055 +		s_prevValuesNeedUpdate = true;
  1.1056 +		signal_new_frame();
  1.1057 +	}
  1.1058 +	if(s_numChanges)
  1.1059 +		memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));
  1.1060 +	CompactAddrs();
  1.1061 +}
  1.1062 +void reset_address_info ()
  1.1063 +{
  1.1064 +	SetRamSearchUndoType(RamSearchHWnd, 0);
  1.1065 +	EnterCriticalSection(&s_activeMemoryRegionsCS);
  1.1066 +	s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo
  1.1067 +	LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.1068 +	if(s_prevValues)
  1.1069 +		memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE)));
  1.1070 +	s_prevValuesNeedUpdate = false;
  1.1071 +	ResetMemoryRegions();
  1.1072 +	if(!RamSearchHWnd)
  1.1073 +	{
  1.1074 +		EnterCriticalSection(&s_activeMemoryRegionsCS);
  1.1075 +		s_activeMemoryRegions.clear();
  1.1076 +		LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.1077 +		ResultCount = 0;
  1.1078 +	}
  1.1079 +	else
  1.1080 +	{
  1.1081 +		// force s_prevValues to be valid
  1.1082 +		signal_new_frame();
  1.1083 +		s_prevValuesNeedUpdate = true;
  1.1084 +		signal_new_frame();
  1.1085 +	}
  1.1086 +	memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));
  1.1087 +	CompactAddrs();
  1.1088 +}
  1.1089 +
  1.1090 +void signal_new_frame ()
  1.1091 +{
  1.1092 +	EnterCriticalSection(&s_activeMemoryRegionsCS);
  1.1093 +	CALL_WITH_T_SIZE_TYPES_0(UpdateRegionsT, rs_type_size, rs_t=='s', noMisalign);
  1.1094 +	LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.1095 +}
  1.1096 +
  1.1097 +
  1.1098 +
  1.1099 +
  1.1100 +
  1.1101 +bool RamSearchClosed = false;
  1.1102 +bool RamWatchClosed = false;
  1.1103 +
  1.1104 +void ResetResults()
  1.1105 +{
  1.1106 +	reset_address_info();
  1.1107 +	ResultCount = 0;
  1.1108 +	if (RamSearchHWnd)
  1.1109 +		ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount);
  1.1110 +}
  1.1111 +void CloseRamWindows() //Close the Ram Search & Watch windows when rom closes
  1.1112 +{
  1.1113 +	ResetWatches();
  1.1114 +	ResetResults();
  1.1115 +	if (RamSearchHWnd)
  1.1116 +	{
  1.1117 +		SendMessage(RamSearchHWnd,WM_CLOSE,NULL,NULL);
  1.1118 +		RamSearchClosed = true;
  1.1119 +	}
  1.1120 +	if (RamWatchHWnd)
  1.1121 +	{
  1.1122 +		SendMessage(RamWatchHWnd,WM_CLOSE,NULL,NULL);
  1.1123 +		RamWatchClosed = true;
  1.1124 +	}
  1.1125 +}
  1.1126 +void ReopenRamWindows() //Reopen them when a new Rom is loaded
  1.1127 +{
  1.1128 +	HWND hwnd = GetActiveWindow();
  1.1129 +
  1.1130 +	if (RamSearchClosed)
  1.1131 +	{
  1.1132 +		RamSearchClosed = false;
  1.1133 +		if(!RamSearchHWnd)
  1.1134 +		{
  1.1135 +			reset_address_info();
  1.1136 +			LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1.1137 +			RamSearchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMSEARCH), hWnd, (DLGPROC) RamSearchProc);
  1.1138 +		}
  1.1139 +		else
  1.1140 +			::SetForegroundWindow(RamSearchHWnd);
  1.1141 +	}
  1.1142 +	if (RamWatchClosed || AutoRWLoad)
  1.1143 +	{
  1.1144 +		RamWatchClosed = false;
  1.1145 +		if(!RamWatchHWnd)
  1.1146 +		{
  1.1147 +			if (AutoRWLoad) OpenRWRecentFile(0);
  1.1148 +			LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1.1149 +			RamWatchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMWATCH), hWnd, (DLGPROC) RamWatchProc);
  1.1150 +		}
  1.1151 +		else
  1.1152 +			::SetForegroundWindow(RamWatchHWnd);
  1.1153 +	}
  1.1154 +
  1.1155 +	if (hwnd == hWnd && hwnd != GetActiveWindow())
  1.1156 +		SetActiveWindow(hWnd); // restore focus to the main window if it had it before
  1.1157 +}
  1.1158 +
  1.1159 +
  1.1160 +
  1.1161 +
  1.1162 +
  1.1163 +void RefreshRamListSelectedCountControlStatus(HWND hDlg)
  1.1164 +{
  1.1165 +	int selCount = ListView_GetSelectedCount(GetDlgItem(hDlg,IDC_RAMLIST));
  1.1166 +	if(selCount != s_prevSelCount)
  1.1167 +	{
  1.1168 +		if(selCount < 2 || s_prevSelCount < 2)
  1.1169 +		{
  1.1170 +			EnableWindow(GetDlgItem(hDlg, IDC_C_WATCH), (WatchCount < MAX_WATCH_COUNT) ? TRUE : FALSE);
  1.1171 +			EnableWindow(GetDlgItem(hDlg, IDC_C_ADDCHEAT), (selCount >= 1) ? TRUE : FALSE);
  1.1172 +			EnableWindow(GetDlgItem(hDlg, IDC_C_ELIMINATE), (selCount >= 1) ? TRUE : FALSE);
  1.1173 +		}
  1.1174 +		s_prevSelCount = selCount;
  1.1175 +	}
  1.1176 +}
  1.1177 +
  1.1178 +
  1.1179 +
  1.1180 +
  1.1181 +struct AddrRange
  1.1182 +{
  1.1183 +	unsigned int addr;
  1.1184 +	unsigned int size;
  1.1185 +	unsigned int End() const { return addr + size; }
  1.1186 +	AddrRange(unsigned int a, unsigned int s) : addr(a),size(s){}
  1.1187 +};
  1.1188 +
  1.1189 +void signal_new_size ()
  1.1190 +{
  1.1191 +	HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST);
  1.1192 +
  1.1193 +	int oldSize = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2;
  1.1194 +	int newSize = (rs_type_size=='b' || !noMisalign) ? 1 : 2;
  1.1195 +	bool numberOfItemsChanged = (oldSize != newSize);
  1.1196 +
  1.1197 +	unsigned int itemsPerPage = ListView_GetCountPerPage(lv);
  1.1198 +	unsigned int oldTopIndex = ListView_GetTopIndex(lv);
  1.1199 +	unsigned int oldSelectionIndex = ListView_GetSelectionMark(lv);
  1.1200 +	unsigned int oldTopAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldTopIndex);
  1.1201 +	unsigned int oldSelectionAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldSelectionIndex);
  1.1202 +
  1.1203 +	std::vector<AddrRange> selHardwareAddrs;
  1.1204 +	if(numberOfItemsChanged)
  1.1205 +	{
  1.1206 +		// store selection ranges
  1.1207 +		// unfortunately this can take a while if the user has a huge range of items selected
  1.1208 +		systemSoundClearBuffer();
  1.1209 +		int selCount = ListView_GetSelectedCount(lv);
  1.1210 +		int size = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2;
  1.1211 +		int watchIndex = -1;
  1.1212 +		for(int i = 0; i < selCount; ++i)
  1.1213 +		{
  1.1214 +			watchIndex = ListView_GetNextItem(lv, watchIndex, LVNI_SELECTED);
  1.1215 +			int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, watchIndex);
  1.1216 +			if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End())
  1.1217 +				selHardwareAddrs.back().size += size;
  1.1218 +			else if (!(noMisalign && oldSize < newSize && addr % newSize != 0))
  1.1219 +				selHardwareAddrs.push_back(AddrRange(addr,size));
  1.1220 +		}
  1.1221 +	}
  1.1222 +
  1.1223 +	CompactAddrs();
  1.1224 +
  1.1225 +	rs_last_type_size = rs_type_size;
  1.1226 +	rs_last_no_misalign = noMisalign;
  1.1227 +
  1.1228 +	if(numberOfItemsChanged)
  1.1229 +	{
  1.1230 +		// restore selection ranges
  1.1231 +		unsigned int newTopIndex = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, oldTopAddr);
  1.1232 +		unsigned int newBottomIndex = newTopIndex + itemsPerPage - 1;
  1.1233 +		SendMessage(lv, WM_SETREDRAW, FALSE, 0);
  1.1234 +		ListView_SetItemState(lv, -1, 0, LVIS_SELECTED|LVIS_FOCUSED); // deselect all
  1.1235 +		for(unsigned int i = 0; i < selHardwareAddrs.size(); i++)
  1.1236 +		{
  1.1237 +			// calculate index ranges of this selection
  1.1238 +			const AddrRange& range = selHardwareAddrs[i];
  1.1239 +			int selRangeTop = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, range.addr);
  1.1240 +			int selRangeBottom = -1;
  1.1241 +			for(int endAddr = range.End()-1; endAddr >= selRangeTop && selRangeBottom == -1; endAddr--)
  1.1242 +				selRangeBottom = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, endAddr);
  1.1243 +			if(selRangeBottom == -1)
  1.1244 +				selRangeBottom = selRangeTop;
  1.1245 +			if(selRangeTop == -1)
  1.1246 +				continue;
  1.1247 +
  1.1248 +			// select the entire range
  1.1249 +			for (int j = selRangeTop; j <= selRangeBottom; j++)
  1.1250 +			{
  1.1251 +				ListView_SetItemState(lv, j, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);
  1.1252 +			}
  1.1253 +		}
  1.1254 +
  1.1255 +		// restore previous scroll position
  1.1256 +		if(newBottomIndex != -1)
  1.1257 +			ListView_EnsureVisible(lv, newBottomIndex, 0);
  1.1258 +		if(newTopIndex != -1)
  1.1259 +			ListView_EnsureVisible(lv, newTopIndex, 0);
  1.1260 +
  1.1261 +		SendMessage(lv, WM_SETREDRAW, TRUE, 0);
  1.1262 +
  1.1263 +		RefreshRamListSelectedCountControlStatus(RamSearchHWnd);
  1.1264 +
  1.1265 +		EnableWindow(GetDlgItem(RamSearchHWnd,IDC_MISALIGN), rs_type_size != 'b');
  1.1266 +	}
  1.1267 +	else
  1.1268 +	{
  1.1269 +		ListView_Update(lv, -1);
  1.1270 +	}
  1.1271 +	InvalidateRect(lv, NULL, TRUE);
  1.1272 +	//SetFocus(lv);
  1.1273 +}
  1.1274 +
  1.1275 +
  1.1276 +
  1.1277 +
  1.1278 +LRESULT CustomDraw (LPARAM lParam)
  1.1279 +{
  1.1280 +	LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
  1.1281 +
  1.1282 +	switch(lplvcd->nmcd.dwDrawStage) 
  1.1283 +	{
  1.1284 +		case CDDS_PREPAINT :
  1.1285 +			return CDRF_NOTIFYITEMDRAW;
  1.1286 +
  1.1287 +		case CDDS_ITEMPREPAINT:
  1.1288 +		{
  1.1289 +			int rv = CDRF_DODEFAULT;
  1.1290 +
  1.1291 +			if(lplvcd->nmcd.dwItemSpec % 2)
  1.1292 +			{
  1.1293 +				// alternate the background color slightly
  1.1294 +				lplvcd->clrTextBk = RGB(248,248,255);
  1.1295 +				rv = CDRF_NEWFONT;
  1.1296 +			}
  1.1297 +
  1.1298 +			if(!IsSatisfied(lplvcd->nmcd.dwItemSpec))
  1.1299 +			{
  1.1300 +				// tint red any items that would be eliminated if a search were to run now
  1.1301 +				lplvcd->clrText = RGB(192,64,64);
  1.1302 +				rv = CDRF_NEWFONT;
  1.1303 +			}
  1.1304 +
  1.1305 +			return rv;
  1.1306 +		}	break;
  1.1307 +	}
  1.1308 +	return CDRF_DODEFAULT;
  1.1309 +}
  1.1310 +
  1.1311 +void Update_RAM_Search() //keeps RAM values up to date in the search and watch windows
  1.1312 +{
  1.1313 +	if(disableRamSearchUpdate)
  1.1314 +		return;
  1.1315 +
  1.1316 +	int prevValuesNeededUpdate;
  1.1317 +	if (AutoSearch && !ResultCount)
  1.1318 +	{
  1.1319 +		if(!AutoSearchAutoRetry)
  1.1320 +		{
  1.1321 +			systemSoundClearBuffer();
  1.1322 +			int answer = MessageBox(RamSearchHWnd,"Choosing Retry will reset the search once and continue autosearching.\nChoose Ignore will reset the search whenever necessary and continue autosearching.\nChoosing Abort will reset the search once and stop autosearching.","Autosearch - out of results.",MB_ABORTRETRYIGNORE|MB_DEFBUTTON2|MB_ICONINFORMATION);
  1.1323 +			if(answer == IDABORT)
  1.1324 +			{
  1.1325 +				SendDlgItemMessage(RamSearchHWnd, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0);
  1.1326 +				SendMessage(RamSearchHWnd, WM_COMMAND, IDC_C_AUTOSEARCH, 0);
  1.1327 +			}
  1.1328 +			if(answer == IDIGNORE)
  1.1329 +				AutoSearchAutoRetry = true;
  1.1330 +		}
  1.1331 +		reset_address_info();
  1.1332 +		prevValuesNeededUpdate = s_prevValuesNeedUpdate;
  1.1333 +	}
  1.1334 +	else
  1.1335 +	{
  1.1336 +		prevValuesNeededUpdate = s_prevValuesNeedUpdate;
  1.1337 +		if (RamSearchHWnd)
  1.1338 +		{
  1.1339 +			// update active RAM values
  1.1340 +			signal_new_frame();
  1.1341 +		}
  1.1342 +
  1.1343 +		if (AutoSearch && ResultCount)
  1.1344 +		{
  1.1345 +			systemSoundClearBuffer();
  1.1346 +			if(!rs_val_valid)
  1.1347 +				rs_val_valid = Set_RS_Val();
  1.1348 +			if(rs_val_valid)
  1.1349 +				prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param);
  1.1350 +		}
  1.1351 +	}
  1.1352 +
  1.1353 +	if(RamSearchHWnd)
  1.1354 +	{
  1.1355 +		HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST);
  1.1356 +		if(prevValuesNeededUpdate != s_prevValuesNeedUpdate)
  1.1357 +		{
  1.1358 +			// previous values got updated, refresh everything visible
  1.1359 +			ListView_Update(lv, -1);
  1.1360 +		}
  1.1361 +		else
  1.1362 +		{
  1.1363 +			// refresh any visible parts of the listview box that changed
  1.1364 +			static int changes[128];
  1.1365 +			int top = ListView_GetTopIndex(lv);
  1.1366 +			int count = ListView_GetCountPerPage(lv);
  1.1367 +			int start = -1;
  1.1368 +			for(int i = top; i <= top+count; i++)
  1.1369 +			{
  1.1370 +				int changeNum = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, i); //s_numChanges[i];
  1.1371 +				int changed = changeNum != changes[i-top];
  1.1372 +				if(changed)
  1.1373 +					changes[i-top] = changeNum;
  1.1374 +
  1.1375 +				if(start == -1)
  1.1376 +				{
  1.1377 +					if(i != top+count && changed)
  1.1378 +					{
  1.1379 +						start = i;
  1.1380 +						//somethingChanged = true;
  1.1381 +					}
  1.1382 +				}
  1.1383 +				else
  1.1384 +				{
  1.1385 +					if(i == top+count || !changed)
  1.1386 +					{
  1.1387 +						ListView_RedrawItems(lv, start, i-1);
  1.1388 +						start = -1;
  1.1389 +					}
  1.1390 +				}
  1.1391 +			}
  1.1392 +		}
  1.1393 +	}
  1.1394 +
  1.1395 +	if(RamWatchHWnd)
  1.1396 +	{
  1.1397 +		Update_RAM_Watch();
  1.1398 +	}
  1.1399 +}
  1.1400 +
  1.1401 +static int rs_lastPercent = -1;
  1.1402 +inline void UpdateRamSearchProgressBar(int percent)
  1.1403 +{
  1.1404 +	if(rs_lastPercent != percent)
  1.1405 +	{
  1.1406 +		rs_lastPercent = percent;
  1.1407 +		UpdateRamSearchTitleBar(percent);
  1.1408 +	}
  1.1409 +}
  1.1410 +
  1.1411 +static void SelectEditControl(int controlID)
  1.1412 +{
  1.1413 +	HWND hEdit = GetDlgItem(RamSearchHWnd,controlID);
  1.1414 +	SetFocus(hEdit);
  1.1415 +	SendMessage(hEdit, EM_SETSEL, 0, -1);
  1.1416 +}
  1.1417 +
  1.1418 +static BOOL SelectingByKeyboard()
  1.1419 +{
  1.1420 +	int a = GetKeyState(VK_LEFT);
  1.1421 +	int b = GetKeyState(VK_RIGHT);
  1.1422 +	int c = GetKeyState(VK_UP);
  1.1423 +	int d = GetKeyState(VK_DOWN); // space and tab are intentionally omitted
  1.1424 +	return (a | b | c | d) & 0x80;
  1.1425 +}
  1.1426 +
  1.1427 +
  1.1428 +LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1.1429 +{
  1.1430 +	static int watchIndex=0;
  1.1431 +
  1.1432 +	switch(uMsg)
  1.1433 +	{
  1.1434 +		case WM_INITDIALOG: {
  1.1435 +			RamSearchHWnd = hDlg;
  1.1436 +			
  1.1437 +			SetWindowPos(hDlg, NULL, regQueryDwordValue("ramSearchX", 0), regQueryDwordValue("ramSearchY", 0), NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
  1.1438 +			switch(rs_o)
  1.1439 +			{
  1.1440 +				case '<':
  1.1441 +					SendDlgItemMessage(hDlg, IDC_LESSTHAN, BM_SETCHECK, BST_CHECKED, 0);
  1.1442 +					break;
  1.1443 +				case '>':
  1.1444 +					SendDlgItemMessage(hDlg, IDC_MORETHAN, BM_SETCHECK, BST_CHECKED, 0);
  1.1445 +					break;
  1.1446 +				case 'l':
  1.1447 +					SendDlgItemMessage(hDlg, IDC_NOMORETHAN, BM_SETCHECK, BST_CHECKED, 0);
  1.1448 +					break;
  1.1449 +				case 'm':
  1.1450 +					SendDlgItemMessage(hDlg, IDC_NOLESSTHAN, BM_SETCHECK, BST_CHECKED, 0);
  1.1451 +					break;
  1.1452 +				case '=': 
  1.1453 +					SendDlgItemMessage(hDlg, IDC_EQUALTO, BM_SETCHECK, BST_CHECKED, 0);
  1.1454 +					break;
  1.1455 +				case '!':
  1.1456 +					SendDlgItemMessage(hDlg, IDC_DIFFERENTFROM, BM_SETCHECK, BST_CHECKED, 0);
  1.1457 +					break;
  1.1458 +				case 'd':
  1.1459 +					SendDlgItemMessage(hDlg, IDC_DIFFERENTBY, BM_SETCHECK, BST_CHECKED, 0);
  1.1460 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true);
  1.1461 +					break;
  1.1462 +				case '%':
  1.1463 +					SendDlgItemMessage(hDlg, IDC_MODULO, BM_SETCHECK, BST_CHECKED, 0);
  1.1464 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true);
  1.1465 +					break;
  1.1466 +			}
  1.1467 +			switch (rs_c)
  1.1468 +			{
  1.1469 +				case 'r':
  1.1470 +					SendDlgItemMessage(hDlg, IDC_PREVIOUSVALUE, BM_SETCHECK, BST_CHECKED, 0);
  1.1471 +					break;
  1.1472 +				case 's':
  1.1473 +					SendDlgItemMessage(hDlg, IDC_SPECIFICVALUE, BM_SETCHECK, BST_CHECKED, 0);
  1.1474 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true);
  1.1475 +					break;
  1.1476 +				case 'a':
  1.1477 +					SendDlgItemMessage(hDlg, IDC_SPECIFICADDRESS, BM_SETCHECK, BST_CHECKED, 0);
  1.1478 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true);
  1.1479 +					break;
  1.1480 +				case 'n':
  1.1481 +					SendDlgItemMessage(hDlg, IDC_NUMBEROFCHANGES, BM_SETCHECK, BST_CHECKED, 0);
  1.1482 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true);
  1.1483 +					break;
  1.1484 +			}
  1.1485 +			switch (rs_t)
  1.1486 +			{
  1.1487 +				case 's':
  1.1488 +					SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0);
  1.1489 +					break;
  1.1490 +				case 'u':
  1.1491 +					SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0);
  1.1492 +					break;
  1.1493 +				case 'h':
  1.1494 +					SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0);
  1.1495 +					break;
  1.1496 +			}
  1.1497 +			switch (rs_type_size)
  1.1498 +			{
  1.1499 +				case 'b':
  1.1500 +					SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0);
  1.1501 +					break;
  1.1502 +				case 'w':
  1.1503 +					SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0);
  1.1504 +					break;
  1.1505 +				case 'd':
  1.1506 +					SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0);
  1.1507 +					break;
  1.1508 +			}
  1.1509 +
  1.1510 +			s_prevValuesNeedUpdate = true;
  1.1511 +
  1.1512 +			SendDlgItemMessage(hDlg,IDC_C_AUTOSEARCH,BM_SETCHECK,AutoSearch?BST_CHECKED:BST_UNCHECKED,0);
  1.1513 +			//const char* names[5] = {"Address","Value","Previous","Changes","Notes"};
  1.1514 +			//int widths[5] = {62,64,64,55,55};
  1.1515 +			const char* names[] = {"Address","Value","Previous","Changes"};
  1.1516 +			int widths[4] = {68,76,76,68};
  1.1517 +			if (!ResultCount)
  1.1518 +				reset_address_info();
  1.1519 +			else
  1.1520 +			{
  1.1521 +				signal_new_frame();
  1.1522 +				CompactAddrs();
  1.1523 +			}
  1.1524 +			void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths);
  1.1525 +			init_list_box(GetDlgItem(hDlg,IDC_RAMLIST),names,4,widths);
  1.1526 +			//ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount);
  1.1527 +			if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0);
  1.1528 +			//if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0);
  1.1529 +			last_rs_possible = -1;
  1.1530 +
  1.1531 +			s_prevSelCount = -1;
  1.1532 +			RefreshRamListSelectedCountControlStatus(hDlg);
  1.1533 +
  1.1534 +			// force misalign checkbox to refresh
  1.1535 +			signal_new_size();
  1.1536 +
  1.1537 +			// force undo button to refresh
  1.1538 +			int undoType = s_undoType;
  1.1539 +			SetRamSearchUndoType(hDlg, -2);
  1.1540 +			SetRamSearchUndoType(hDlg, undoType);
  1.1541 +
  1.1542 +			// force possibility count to refresh
  1.1543 +			last_rs_possible--;
  1.1544 +			UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size());
  1.1545 +			
  1.1546 +			rs_val_valid = Set_RS_Val();
  1.1547 +
  1.1548 +			ListView_SetCallbackMask(GetDlgItem(hDlg,IDC_RAMLIST), LVIS_FOCUSED|LVIS_SELECTED);
  1.1549 +
  1.1550 +			return true;
  1.1551 +		}	break;
  1.1552 +
  1.1553 +		case WM_NOTIFY:
  1.1554 +		{
  1.1555 +			LPNMHDR lP = (LPNMHDR) lParam;
  1.1556 +			switch (lP->code)
  1.1557 +			{
  1.1558 +				case LVN_ITEMCHANGED: // selection changed event
  1.1559 +				{
  1.1560 +					NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lP;
  1.1561 +					if(pNMListView->uNewState & LVIS_FOCUSED ||
  1.1562 +						(pNMListView->uNewState ^ pNMListView->uOldState) & LVIS_SELECTED)
  1.1563 +					{
  1.1564 +						// disable buttons that we don't have the right number of selected items for
  1.1565 +						RefreshRamListSelectedCountControlStatus(hDlg);
  1.1566 +					}
  1.1567 +				}	break;
  1.1568 +
  1.1569 +				case LVN_GETDISPINFO:
  1.1570 +				{
  1.1571 +					LV_DISPINFO *Item = (LV_DISPINFO *)lParam;
  1.1572 +					Item->item.mask = LVIF_TEXT;
  1.1573 +					Item->item.state = 0;
  1.1574 +					Item->item.iImage = 0;
  1.1575 +					const unsigned int iNum = Item->item.iItem;
  1.1576 +					static char num[11];
  1.1577 +					switch (Item->item.iSubItem)
  1.1578 +					{
  1.1579 +						case 0:
  1.1580 +						{
  1.1581 +							int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
  1.1582 +							sprintf(num,"%08X",addr);
  1.1583 +							Item->item.pszText = num;
  1.1584 +						}	return true;
  1.1585 +						case 1:
  1.1586 +						{
  1.1587 +							int i = CALL_WITH_T_SIZE_TYPES_1(GetCurValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
  1.1588 +							const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X"));
  1.1589 +							switch (rs_type_size)
  1.1590 +							{
  1.1591 +								case 'b':
  1.1592 +								default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break;
  1.1593 +								case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break;
  1.1594 +								case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break;
  1.1595 +							}
  1.1596 +							Item->item.pszText = num;
  1.1597 +						}	return true;
  1.1598 +						case 2:
  1.1599 +						{
  1.1600 +							int i = CALL_WITH_T_SIZE_TYPES_1(GetPrevValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
  1.1601 +							const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X"));
  1.1602 +							switch (rs_type_size)
  1.1603 +							{
  1.1604 +								case 'b':
  1.1605 +								default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break;
  1.1606 +								case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break;
  1.1607 +								case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break;
  1.1608 +							}
  1.1609 +							Item->item.pszText = num;
  1.1610 +						}	return true;
  1.1611 +						case 3:
  1.1612 +						{
  1.1613 +							int i = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);
  1.1614 +							sprintf(num,"%d",i);
  1.1615 +
  1.1616 +							Item->item.pszText = num;
  1.1617 +						}	return true;
  1.1618 +						//case 4:
  1.1619 +						//	Item->item.pszText = rsaddrs[rsresults[iNum].Index].comment ? rsaddrs[rsresults[iNum].Index].comment : "";
  1.1620 +						//	return true;
  1.1621 +						default:
  1.1622 +							return false;
  1.1623 +					}
  1.1624 +				}
  1.1625 +
  1.1626 +				case NM_CUSTOMDRAW:
  1.1627 +				{
  1.1628 +					SetWindowLong(hDlg, DWL_MSGRESULT, CustomDraw(lParam));
  1.1629 +					return TRUE;
  1.1630 +				}	break;
  1.1631 +
  1.1632 +				//case LVN_ODCACHEHINT: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something.
  1.1633 +				//{
  1.1634 +				//	LPNMLVCACHEHINT   lpCacheHint = (LPNMLVCACHEHINT)lParam;
  1.1635 +				//	return 0;
  1.1636 +				//}
  1.1637 +				//case LVN_ODFINDITEM: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something.
  1.1638 +				//{	
  1.1639 +				//	LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam;
  1.1640 +				//	return 0;
  1.1641 +				//}
  1.1642 +			}
  1.1643 +		}	break;
  1.1644 +
  1.1645 +		case WM_COMMAND:
  1.1646 +		{
  1.1647 +			int rv = false;
  1.1648 +			switch(LOWORD(wParam))
  1.1649 +			{
  1.1650 +				case IDC_SIGNED:
  1.1651 +					rs_t='s';
  1.1652 +					signal_new_size();
  1.1653 +					{rv = true; break;}
  1.1654 +				case IDC_UNSIGNED:
  1.1655 +					rs_t='u';
  1.1656 +					signal_new_size();
  1.1657 +					{rv = true; break;}
  1.1658 +				case IDC_HEX:
  1.1659 +					rs_t='h';
  1.1660 +					signal_new_size();
  1.1661 +					{rv = true; break;}
  1.1662 +				case IDC_1_BYTE:
  1.1663 +					rs_type_size = 'b';
  1.1664 +					signal_new_size();
  1.1665 +					{rv = true; break;}
  1.1666 +				case IDC_2_BYTES:
  1.1667 +					rs_type_size = 'w';
  1.1668 +					signal_new_size();
  1.1669 +					{rv = true; break;}
  1.1670 +				case IDC_4_BYTES:
  1.1671 +					rs_type_size = 'd';
  1.1672 +					signal_new_size();
  1.1673 +					{rv = true; break;}
  1.1674 +				case IDC_MISALIGN:
  1.1675 +					noMisalign = !noMisalign;
  1.1676 +					//CompactAddrs();
  1.1677 +					signal_new_size();
  1.1678 +					{rv = true; break;}
  1.1679 +//				case IDC_ENDIAN:
  1.1680 +////					littleEndian = !littleEndian;
  1.1681 +////					signal_new_size();
  1.1682 +//					{rv = true; break;}				
  1.1683 +				case IDC_LESSTHAN:
  1.1684 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
  1.1685 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
  1.1686 +					rs_o = '<';
  1.1687 +					{rv = true; break;}
  1.1688 +				case IDC_MORETHAN:
  1.1689 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
  1.1690 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
  1.1691 +					rs_o = '>';
  1.1692 +					{rv = true; break;}
  1.1693 +				case IDC_NOMORETHAN:
  1.1694 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
  1.1695 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
  1.1696 +					rs_o = 'l';
  1.1697 +					{rv = true; break;}
  1.1698 +				case IDC_NOLESSTHAN:
  1.1699 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
  1.1700 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
  1.1701 +					rs_o = 'm';
  1.1702 +					{rv = true; break;}
  1.1703 +				case IDC_EQUALTO:
  1.1704 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
  1.1705 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
  1.1706 +					rs_o = '=';
  1.1707 +					{rv = true; break;}
  1.1708 +				case IDC_DIFFERENTFROM:
  1.1709 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
  1.1710 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
  1.1711 +					rs_o = '!';
  1.1712 +					{rv = true; break;}
  1.1713 +				case IDC_DIFFERENTBY:
  1.1714 +				{
  1.1715 +					rs_o = 'd';
  1.1716 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true);
  1.1717 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);
  1.1718 +					if(!SelectingByKeyboard())
  1.1719 +						SelectEditControl(IDC_EDIT_DIFFBY);
  1.1720 +				}	{rv = true; break;}
  1.1721 +				case IDC_MODULO:
  1.1722 +				{
  1.1723 +					rs_o = '%';
  1.1724 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);
  1.1725 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true);
  1.1726 +					if(!SelectingByKeyboard())
  1.1727 +						SelectEditControl(IDC_EDIT_MODBY);
  1.1728 +				}	{rv = true; break;}
  1.1729 +				case IDC_PREVIOUSVALUE:
  1.1730 +					rs_c='r';
  1.1731 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);
  1.1732 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);
  1.1733 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);
  1.1734 +					{rv = true; break;}
  1.1735 +				case IDC_SPECIFICVALUE:
  1.1736 +				{
  1.1737 +					rs_c = 's';
  1.1738 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true);
  1.1739 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);
  1.1740 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);
  1.1741 +					if(!SelectingByKeyboard())
  1.1742 +						SelectEditControl(IDC_EDIT_COMPAREVALUE);
  1.1743 +					{rv = true; break;}
  1.1744 +				}
  1.1745 +				case IDC_SPECIFICADDRESS:
  1.1746 +				{
  1.1747 +					rs_c = 'a';
  1.1748 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true);
  1.1749 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);
  1.1750 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);
  1.1751 +					if(!SelectingByKeyboard())
  1.1752 +						SelectEditControl(IDC_EDIT_COMPAREADDRESS);
  1.1753 +				}	{rv = true; break;}
  1.1754 +				case IDC_NUMBEROFCHANGES:
  1.1755 +				{
  1.1756 +					rs_c = 'n';
  1.1757 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true);
  1.1758 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);
  1.1759 +					EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);
  1.1760 +					if(!SelectingByKeyboard())
  1.1761 +						SelectEditControl(IDC_EDIT_COMPARECHANGES);
  1.1762 +				}	{rv = true; break;}
  1.1763 +				case IDC_C_ADDCHEAT:
  1.1764 +				{
  1.1765 +					HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);
  1.1766 +					int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED);
  1.1767 +					while (watchItemIndex >= 0)
  1.1768 +					{
  1.1769 +						unsigned long address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex);
  1.1770 +
  1.1771 +						int sizeType = -1;
  1.1772 +						if(rs_type_size == 'b')
  1.1773 +							sizeType = 0;
  1.1774 +						else if(rs_type_size == 'w')
  1.1775 +							sizeType = 1;
  1.1776 +						else if(rs_type_size == 'd')
  1.1777 +							sizeType = 2;
  1.1778 +
  1.1779 +						int numberType = -1;
  1.1780 +						if(rs_t == 's')
  1.1781 +							numberType = 0;
  1.1782 +						else if(rs_t == 'u')
  1.1783 +							numberType = 1;
  1.1784 +						else if(rs_t == 'h')
  1.1785 +							numberType = 2;
  1.1786 +
  1.1787 +						if(systemCartridgeType == 0)
  1.1788 +						{
  1.1789 +							AddCheat dlg (address/*, hDlg*/);
  1.1790 +							if(sizeType != -1) dlg.sizeType = sizeType;
  1.1791 +							if(numberType != -1) dlg.numberType = numberType;
  1.1792 +							dlg.DoModal();
  1.1793 +						}
  1.1794 +						else
  1.1795 +						{
  1.1796 +							AddGBCheat dlg (address/*, hDlg*/);
  1.1797 +							if(sizeType != -1) dlg.sizeType = sizeType;
  1.1798 +							if(numberType != -1) dlg.numberType = numberType;
  1.1799 +							dlg.DoModal();
  1.1800 +						}
  1.1801 +						watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED);
  1.1802 +					}
  1.1803 +				}	{rv = true; break;}
  1.1804 +				case IDC_C_RESET:
  1.1805 +				{
  1.1806 +					RamSearchSaveUndoStateIfNotTooBig(RamSearchHWnd);
  1.1807 +					int prevNumItems = last_rs_possible;
  1.1808 +
  1.1809 +					soft_reset_address_info();
  1.1810 +
  1.1811 +					if(prevNumItems == last_rs_possible)
  1.1812 +						SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo
  1.1813 +
  1.1814 +					ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all
  1.1815 +					//ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount);
  1.1816 +					ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0);
  1.1817 +					RefreshRamListSelectedCountControlStatus(hDlg);
  1.1818 +					{rv = true; break;}
  1.1819 +				}
  1.1820 +				case IDC_C_RESET_CHANGES:
  1.1821 +					memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));
  1.1822 +					ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1);
  1.1823 +					//SetRamSearchUndoType(hDlg, 0);
  1.1824 +					{rv = true; break;}
  1.1825 +				case IDC_C_UNDO:
  1.1826 +					if(s_undoType>0)
  1.1827 +					{
  1.1828 +						systemSoundClearBuffer();
  1.1829 +						EnterCriticalSection(&s_activeMemoryRegionsCS);
  1.1830 +						if(s_activeMemoryRegions.size() < tooManyRegionsForUndo)
  1.1831 +						{
  1.1832 +							MemoryList tempMemoryList = s_activeMemoryRegions;
  1.1833 +							s_activeMemoryRegions = s_activeMemoryRegionsBackup;
  1.1834 +							s_activeMemoryRegionsBackup = tempMemoryList;
  1.1835 +							LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.1836 +							SetRamSearchUndoType(hDlg, 3 - s_undoType);
  1.1837 +						}
  1.1838 +						else
  1.1839 +						{
  1.1840 +							s_activeMemoryRegions = s_activeMemoryRegionsBackup;
  1.1841 +							LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.1842 +							SetRamSearchUndoType(hDlg, -1);
  1.1843 +						}
  1.1844 +						CompactAddrs();
  1.1845 +						ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all
  1.1846 +						ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0);
  1.1847 +						RefreshRamListSelectedCountControlStatus(hDlg);
  1.1848 +					}
  1.1849 +					{rv = true; break;}
  1.1850 +				case IDC_C_AUTOSEARCH:
  1.1851 +					AutoSearch = SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_GETCHECK, 0, 0) != 0;
  1.1852 +					AutoSearchAutoRetry = false;
  1.1853 +					if (!AutoSearch) {rv = true; break;}
  1.1854 +				case IDC_C_SEARCH:
  1.1855 +				{
  1.1856 +					systemSoundClearBuffer();
  1.1857 +
  1.1858 +					if(!rs_val_valid && !(rs_val_valid = Set_RS_Val()))
  1.1859 +						goto invalid_field;
  1.1860 +
  1.1861 +					if(ResultCount)
  1.1862 +					{
  1.1863 +						RamSearchSaveUndoStateIfNotTooBig(hDlg);
  1.1864 +
  1.1865 +						prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param);
  1.1866 +
  1.1867 +						RefreshRamListSelectedCountControlStatus(hDlg);
  1.1868 +					}
  1.1869 +
  1.1870 +					if(!ResultCount)
  1.1871 +					{
  1.1872 +
  1.1873 +						MessageBox(RamSearchHWnd,"Resetting search.","Out of results.",MB_OK|MB_ICONINFORMATION);
  1.1874 +						soft_reset_address_info();
  1.1875 +					}
  1.1876 +
  1.1877 +					{rv = true; break;}
  1.1878 +
  1.1879 +invalid_field:
  1.1880 +					MessageBox(RamSearchHWnd,"Invalid or out-of-bound entered value.","Error",MB_OK|MB_ICONSTOP);
  1.1881 +					if(AutoSearch) // stop autosearch if it just started
  1.1882 +					{
  1.1883 +						SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0);
  1.1884 +						SendMessage(hDlg, WM_COMMAND, IDC_C_AUTOSEARCH, 0);
  1.1885 +					}
  1.1886 +					{rv = true; break;}
  1.1887 +				}
  1.1888 +				case IDC_C_WATCH:
  1.1889 +				{
  1.1890 +					HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);
  1.1891 +					int selCount = ListView_GetSelectedCount(ramListControl);
  1.1892 +
  1.1893 +					bool inserted = false;
  1.1894 +					int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED);
  1.1895 +					while (watchItemIndex >= 0)
  1.1896 +					{
  1.1897 +						AddressWatcher tempWatch;
  1.1898 +						tempWatch.Address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex);
  1.1899 +						tempWatch.Size = rs_type_size;
  1.1900 +						tempWatch.Type = rs_t;
  1.1901 +						tempWatch.WrongEndian = 0; //Replace when I get little endian working
  1.1902 +						tempWatch.comment = NULL;
  1.1903 +
  1.1904 +						if (selCount == 1)
  1.1905 +							inserted |= InsertWatch(tempWatch, hDlg);
  1.1906 +						else
  1.1907 +							inserted |= InsertWatch(tempWatch, "");
  1.1908 +
  1.1909 +						watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED);
  1.1910 +					}
  1.1911 +					// bring up the ram watch window if it's not already showing so the user knows where the watch went
  1.1912 +					if(inserted && !RamWatchHWnd)
  1.1913 +						SendMessage(hWnd, WM_COMMAND, ID_RAM_WATCH, 0);
  1.1914 +					SetForegroundWindow(RamSearchHWnd);
  1.1915 +					{rv = true; break;}
  1.1916 +				}
  1.1917 +
  1.1918 +				// eliminate all selected items
  1.1919 +				case IDC_C_ELIMINATE:
  1.1920 +				{
  1.1921 +					RamSearchSaveUndoStateIfNotTooBig(hDlg);
  1.1922 +
  1.1923 +					HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);
  1.1924 +					int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2;
  1.1925 +					int selCount = ListView_GetSelectedCount(ramListControl);
  1.1926 +					int watchIndex = -1;
  1.1927 +
  1.1928 +					// time-saving trick #1:
  1.1929 +					// condense the selected items into an array of address ranges
  1.1930 +					std::vector<AddrRange> selHardwareAddrs;
  1.1931 +					for(int i = 0, j = 1024; i < selCount; ++i, --j)
  1.1932 +					{
  1.1933 +						watchIndex = ListView_GetNextItem(ramListControl, watchIndex, LVNI_SELECTED);
  1.1934 +						int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchIndex);
  1.1935 +						if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End())
  1.1936 +							selHardwareAddrs.back().size += size;
  1.1937 +						else
  1.1938 +							selHardwareAddrs.push_back(AddrRange(addr,size));
  1.1939 +
  1.1940 +						if(!j) UpdateRamSearchProgressBar(i * 50 / selCount), j = 1024;
  1.1941 +					}
  1.1942 +
  1.1943 +					// now deactivate the ranges
  1.1944 +
  1.1945 +					// time-saving trick #2:
  1.1946 +					// take advantage of the fact that the listbox items must be in the same order as the regions
  1.1947 +					MemoryList::iterator iter = s_activeMemoryRegions.begin();
  1.1948 +					int numHardwareAddrRanges = selHardwareAddrs.size();
  1.1949 +					for(int i = 0, j = 16; i < numHardwareAddrRanges; ++i, --j)
  1.1950 +					{
  1.1951 +						int addr = selHardwareAddrs[i].addr;
  1.1952 +						int size = selHardwareAddrs[i].size;
  1.1953 +						bool affected = false;
  1.1954 +						while(iter != s_activeMemoryRegions.end())
  1.1955 +						{
  1.1956 +							MemoryRegion& region = *iter;
  1.1957 +							int affNow = DeactivateRegion(region, iter, addr, size);
  1.1958 +							if(affNow)
  1.1959 +								affected = true;
  1.1960 +							else if(affected)
  1.1961 +								break;
  1.1962 +							if(affNow != 2)
  1.1963 +								++iter;
  1.1964 +						}
  1.1965 +
  1.1966 +						if(!j) UpdateRamSearchProgressBar(50 + (i * 50 / selCount)), j = 16;
  1.1967 +					}
  1.1968 +					UpdateRamSearchTitleBar();
  1.1969 +
  1.1970 +					// careful -- if the above two time-saving tricks aren't working,
  1.1971 +					// the runtime can absolutely explode (seconds -> hours) when there are lots of regions
  1.1972 +
  1.1973 +					ListView_SetItemState(ramListControl, -1, 0, LVIS_SELECTED); // deselect all
  1.1974 +					signal_new_size();
  1.1975 +					{rv = true; break;}
  1.1976 +				}
  1.1977 +				//case IDOK:
  1.1978 +				case IDCANCEL:
  1.1979 +					RamSearchHWnd = NULL;
  1.1980 +/*					if (theApp.pauseDuringCheatSearch)
  1.1981 +						EndDialog(hDlg, true);	// this should never be called on a modeless dialog
  1.1982 +					else
  1.1983 +*/
  1.1984 +						DestroyWindow(hDlg);
  1.1985 +					{rv = true; break;}
  1.1986 +			}
  1.1987 +
  1.1988 +			// check refresh for comparison preview color update
  1.1989 +			// also, update rs_val if needed
  1.1990 +			bool needRefresh = false;
  1.1991 +			switch(LOWORD(wParam))
  1.1992 +			{
  1.1993 +				case IDC_LESSTHAN:
  1.1994 +				case IDC_MORETHAN:
  1.1995 +				case IDC_NOMORETHAN:
  1.1996 +				case IDC_NOLESSTHAN:
  1.1997 +				case IDC_EQUALTO:
  1.1998 +				case IDC_DIFFERENTFROM:
  1.1999 +				case IDC_DIFFERENTBY:
  1.2000 +				case IDC_MODULO:
  1.2001 +				case IDC_PREVIOUSVALUE:
  1.2002 +				case IDC_SPECIFICVALUE:
  1.2003 +				case IDC_SPECIFICADDRESS:
  1.2004 +				case IDC_NUMBEROFCHANGES:
  1.2005 +				case IDC_SIGNED:
  1.2006 +				case IDC_UNSIGNED:
  1.2007 +				case IDC_HEX:
  1.2008 +					rs_val_valid = Set_RS_Val();
  1.2009 +					needRefresh = true;
  1.2010 +					break;
  1.2011 +				case IDC_EDIT_COMPAREVALUE:
  1.2012 +				case IDC_EDIT_COMPAREADDRESS:
  1.2013 +				case IDC_EDIT_COMPARECHANGES:
  1.2014 +				case IDC_EDIT_DIFFBY:
  1.2015 +				case IDC_EDIT_MODBY:
  1.2016 +					if(HIWORD(wParam) == EN_CHANGE)
  1.2017 +					{
  1.2018 +						rs_val_valid = Set_RS_Val();
  1.2019 +						needRefresh = true;
  1.2020 +					}
  1.2021 +					break;
  1.2022 +			}
  1.2023 +			if(needRefresh)
  1.2024 +				ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1);
  1.2025 +
  1.2026 +
  1.2027 +			return rv;
  1.2028 +		}	break;
  1.2029 +
  1.2030 +		case WM_CLOSE:
  1.2031 +			RECT r;
  1.2032 +			GetWindowRect(hDlg, &r);
  1.2033 +			regSetDwordValue("ramSearchX", r.left);
  1.2034 +			regSetDwordValue("ramSearchY", r.top);
  1.2035 +			SendMessage(RamSearchHWnd, WM_DESTROY, 0, 0);
  1.2036 +			break;
  1.2037 +		case WM_DESTROY:
  1.2038 +			RamSearchHWnd = NULL;
  1.2039 +//			theApp.modelessCheatDialogIsOpen = false;
  1.2040 +//			return true;
  1.2041 +			break;
  1.2042 +	}
  1.2043 +
  1.2044 +	return false;
  1.2045 +}
  1.2046 +
  1.2047 +void UpdateRamSearchTitleBar(int percent)
  1.2048 +{
  1.2049 +#define HEADER_STR " RAM Search - "
  1.2050 +#define PROGRESS_STR " %d%% ... "
  1.2051 +#define STATUS_STR "%d Possibilit%s (%d Region%s)"
  1.2052 +
  1.2053 +	int poss = last_rs_possible;
  1.2054 +	int regions = last_rs_regions;
  1.2055 +	if(poss <= 0)
  1.2056 +		strcpy(Str_Tmp," RAM Search");
  1.2057 +	else if(percent <= 0)
  1.2058 +		sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s");
  1.2059 +	else
  1.2060 +		sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s");
  1.2061 +	SetWindowText(RamSearchHWnd, Str_Tmp);
  1.2062 +}
  1.2063 +
  1.2064 +void UpdatePossibilities(int rs_possible, int regions)
  1.2065 +{
  1.2066 +	if(rs_possible != last_rs_possible)
  1.2067 +	{
  1.2068 +		last_rs_possible = rs_possible;
  1.2069 +		last_rs_regions = regions;
  1.2070 +		UpdateRamSearchTitleBar();
  1.2071 +	}
  1.2072 +}
  1.2073 +
  1.2074 +void SetRamSearchUndoType(HWND hDlg, int type)
  1.2075 +{
  1.2076 +	if(s_undoType != type)
  1.2077 +	{
  1.2078 +		if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1))
  1.2079 +			SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo"));
  1.2080 +		if((s_undoType>0)!=(type>0))
  1.2081 +			EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0);
  1.2082 +		s_undoType = type;
  1.2083 +	}
  1.2084 +}
  1.2085 +
  1.2086 +void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg)
  1.2087 +{
  1.2088 +	EnterCriticalSection(&s_activeMemoryRegionsCS);
  1.2089 +	if(s_activeMemoryRegions.size() < tooManyRegionsForUndo)
  1.2090 +	{
  1.2091 +		s_activeMemoryRegionsBackup = s_activeMemoryRegions;
  1.2092 +		LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.2093 +		SetRamSearchUndoType(hDlg, 1);
  1.2094 +	}
  1.2095 +	else
  1.2096 +	{
  1.2097 +		LeaveCriticalSection(&s_activeMemoryRegionsCS);
  1.2098 +		SetRamSearchUndoType(hDlg, 0);
  1.2099 +	}
  1.2100 +}
  1.2101 +
  1.2102 +struct InitRamSearch
  1.2103 +{
  1.2104 +	InitRamSearch()
  1.2105 +	{
  1.2106 +		InitializeCriticalSection(&s_activeMemoryRegionsCS);
  1.2107 +	}
  1.2108 +	~InitRamSearch()
  1.2109 +	{
  1.2110 +		DeleteCriticalSection(&s_activeMemoryRegionsCS);
  1.2111 +	}
  1.2112 +} initRamSearch;
  1.2113 +
  1.2114 +
  1.2115 +void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths) //initializes the ram search and/or ram watch listbox
  1.2116 +{
  1.2117 +	LVCOLUMN Col;
  1.2118 +	Col.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  1.2119 +	Col.fmt = LVCFMT_CENTER;
  1.2120 +	for (int i = 0; i < numColumns; i++)
  1.2121 +	{
  1.2122 +		Col.iOrder = i;
  1.2123 +		Col.iSubItem = i;
  1.2124 +		Col.pszText = (LPSTR)(Strs[i]);
  1.2125 +		Col.cx = columnWidths[i];
  1.2126 +		ListView_InsertColumn(Box,i,&Col);
  1.2127 +	}
  1.2128 +
  1.2129 +	ListView_SetExtendedListViewStyle(Box, LVS_EX_FULLROWSELECT);
  1.2130 +}