Mercurial > vba-clojure
view src/win32/ram_search.cpp @ 3:b05d00f19d80
fix some formatting
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:33:11 -0600 |
parents | f9f4f1b99eed |
children |
line wrap: on
line source
1 // A few notes about this implementation of a RAM search window:2 //3 // Speed of update was one of the highest priories.4 // This is because I wanted the RAM search window to be able to5 // update every single value in RAM every single frame, and6 // keep track of the exact number of frames across which each value has changed,7 // without causing the emulation to run noticeably slower than normal.8 //9 // The data representation was changed from one entry per valid address10 // to one entry per contiguous range of uneliminated addresses11 // which references uniform pools of per-address properties.12 // - This saves time when there are many items because13 // it minimizes the amount of data that needs to be stored and processed per address.14 // - It also saves time when there are few items because15 // it ensures that no time is wasted in iterating through16 // addresses that have already been eliminated from the search.17 //18 // The worst-case scenario is when every other item has been19 // eliminated from the search, maximizing the number of regions.20 // This implementation manages to handle even that pathological case21 // acceptably well. In fact, it still updates faster than the previous implementation.22 // The time spent setting up or clearing such a large number of regions23 // is somewhat horrendous, but it seems reasonable to have poor worst-case speed24 // during these sporadic "setup" steps to achieve an all-around faster per-update speed.25 // (You can test this case by performing the search: Modulo 2 Is Specific Address 0)28 #ifdef _WIN3229 #include "stdafx.h"30 #include "resource.h"31 #include "VBA.h"32 //#include <windows.h>33 #include <commctrl.h>34 #include "BaseTsd.h"35 #include "GBACheatsDlg.h"36 #include "GBCheatsDlg.h"37 typedef INT_PTR intptr_t;38 #else39 #include "stdint.h"40 #endif41 #include <cassert>42 #include <list>43 #include <vector>45 #include "ram_search.h"46 #include "ramwatch.h"47 #include "../gba/GBAGlobals.h"48 #include "../gb/gbGlobals.h"49 #include "../common/vbalua.h"50 #include "Reg.h"52 static inline u8* HardwareToSoftwareAddress(HWAddressType address)53 {54 if(!emulating)55 return NULL;57 // note: this currently follows the "quick" memory rules,58 // meaning it will miss whatever special cases aren't handled by read/writeMemoryQuick.59 // if this is made more accurate, it may be necessary to reduce regionSearchGranularity.60 if(systemCartridgeType == 0)61 {62 // GBA63 HWAddressType mask = ::map[address >> 24].mask;64 if(!mask || (address & 0xFFFFFF) > mask)65 return NULL;66 return &::map[address >> 24].address[address & mask];67 }68 else69 {70 // GB71 extern int32 gbEchoRAMFixOn;72 if (gbEchoRAMFixOn)73 if (address >= 0xe000 && address < 0xfe00)74 address -= 0x2000;75 if((address>>12) >= sizeof(gbMemoryMap)/sizeof(*gbMemoryMap))76 return NULL;77 return &gbMemoryMap[address>>12][address&0xfff];78 }79 }82 struct MemoryRegion83 {84 HWAddressType hardwareAddress; // hardware address of the start of this region85 unsigned int size; // number of bytes to the end of this region86 unsigned char* softwareAddress; // pointer to the start of the live emulator source values for this region88 unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions()89 unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false90 };92 int MAX_RAM_SIZE = 0;93 static unsigned char* s_prevValues = 0; // values at last search or reset94 static unsigned char* s_curValues = 0; // values at last frame update95 static unsigned short* s_numChanges = 0; // number of changes of the item starting at this virtual index address96 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 false97 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 recalculated98 static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled99 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 attempts100 static int s_prevSelCount = -1;102 HWND RamSearchHWnd;103 #define hWnd AfxGetMainWnd()->GetSafeHwnd()104 #define hInst AfxGetInstanceHandle()105 static char Str_Tmp [1024];107 int disableRamSearchUpdate = false;111 //static const MemoryRegion s_prgRegion = { 0x020000, SEGACD_RAM_PRG_SIZE, (unsigned char*)Ram_Prg, true};112 //static const MemoryRegion s_word1MRegion = { 0x200000, SEGACD_1M_RAM_SIZE, (unsigned char*)Ram_Word_1M, true};113 //static const MemoryRegion s_word2MRegion = { 0x200000, SEGACD_2M_RAM_SIZE, (unsigned char*)Ram_Word_2M, true};114 //static const MemoryRegion s_z80Region = { 0xA00000, Z80_RAM_SIZE, (unsigned char*)Ram_Z80, true};115 //static const MemoryRegion s_68kRegion = { 0xFF0000, _68K_RAM_SIZE, (unsigned char*)Ram_68k, true};116 //static const MemoryRegion s_32xRegion = {0x06000000, _32X_RAM_SIZE, (unsigned char*)_32X_Ram, false};118 // list of contiguous uneliminated memory regions119 typedef std::list<MemoryRegion> MemoryList;120 static MemoryList s_activeMemoryRegions;121 static CRITICAL_SECTION s_activeMemoryRegionsCS;123 // for undo support (could be better, but this way was really easy)124 static MemoryList s_activeMemoryRegionsBackup;125 static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo127 void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg);128 static const int tooManyRegionsForUndo = 10000;130 void ResetMemoryRegions()131 {132 systemSoundClearBuffer();133 EnterCriticalSection(&s_activeMemoryRegionsCS);135 s_activeMemoryRegions.clear();137 // use HardwareToSoftwareAddress to figure out what all the possible memory regions are,138 // split up wherever there's a discontinuity in the address in our software RAM.139 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.140 HWAddressType hwRegionStart = 0;141 u8* regionStart = NULL;142 u8* regionEnd = NULL;143 for(HWAddressType addr = 0; addr != 0x10000000+regionSearchGranularity; addr += regionSearchGranularity)144 {145 u8* swAddr = HardwareToSoftwareAddress(addr);146 if(regionEnd && swAddr != regionEnd+regionSearchGranularity)147 {148 // hit end of region149 // check to see if it mirrors an existing one (in which case we discard it)150 bool discard = false;151 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)152 {153 MemoryRegion& region = *iter;154 if(region.softwareAddress == regionStart)155 {156 unsigned int size = regionSearchGranularity + (regionEnd - regionStart);157 if(size <= region.size)158 {159 discard = true;160 }161 else162 {163 hwRegionStart += region.size;164 regionStart += region.size;165 }166 break;167 }168 }170 // don't include ROM in our RAM search (it's too huge)171 if(regionStart == rom || regionStart == gbRom)172 discard = true;174 // create the region175 if(!discard)176 {177 MemoryRegion region = { hwRegionStart, regionSearchGranularity + (regionEnd - regionStart), regionStart };178 s_activeMemoryRegions.push_back(region);179 }181 hwRegionStart = 0;182 regionStart = NULL;183 regionEnd = NULL;184 }185 if(swAddr)186 {187 if(regionStart)188 {189 // continue region190 regionEnd = swAddr;191 }192 else193 {194 // start new region195 hwRegionStart = addr;196 regionStart = swAddr;197 regionEnd = swAddr;198 }199 }200 }203 int nextVirtualIndex = 0;204 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)205 {206 MemoryRegion& region = *iter;207 region.virtualIndex = nextVirtualIndex;208 assert(((intptr_t)region.softwareAddress & 1) == 0 && "somebody needs to reimplement ReadValueAtSoftwareAddress()");209 nextVirtualIndex = region.virtualIndex + region.size;210 }211 //assert(nextVirtualIndex <= MAX_RAM_SIZE);213 if(nextVirtualIndex > MAX_RAM_SIZE)214 {215 s_prevValues = (unsigned char*)realloc(s_prevValues, sizeof(char)*(nextVirtualIndex+4));216 memset(s_prevValues, 0, sizeof(char)*(nextVirtualIndex+4));218 s_curValues = (unsigned char*)realloc(s_curValues, sizeof(char)*(nextVirtualIndex+4));219 memset(s_curValues, 0, sizeof(char)*(nextVirtualIndex+4));221 s_numChanges = (unsigned short*)realloc(s_numChanges, sizeof(short)*(nextVirtualIndex+4));222 memset(s_numChanges, 0, sizeof(short)*(nextVirtualIndex+4));224 s_itemIndexToRegionPointer = (MemoryRegion**)realloc(s_itemIndexToRegionPointer, sizeof(MemoryRegion*)*(nextVirtualIndex+4));225 memset(s_itemIndexToRegionPointer, 0, sizeof(MemoryRegion*)*(nextVirtualIndex+4));227 MAX_RAM_SIZE = nextVirtualIndex;228 }229 LeaveCriticalSection(&s_activeMemoryRegionsCS);230 }232 // eliminates a range of hardware addresses from the search results233 // returns 2 if it changed the region and moved the iterator to another region234 // returns 1 if it changed the region but didn't move the iterator235 // returns 0 if it had no effect236 // warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion...237 // doing so would be tremendously slow because DeactivateRegion invalidates the index cache238 int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, HWAddressType hardwareAddress, unsigned int size)239 {240 if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size)241 {242 // region is unaffected243 return 0;244 }245 else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size)246 {247 // erase end of region248 region.size = hardwareAddress - region.hardwareAddress;249 return 1;250 }251 else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size)252 {253 // erase start of region254 int eraseSize = (hardwareAddress + size) - region.hardwareAddress;255 region.hardwareAddress += eraseSize;256 region.size -= eraseSize;257 region.softwareAddress += eraseSize;258 region.virtualIndex += eraseSize;259 return 1;260 }261 else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size)262 {263 // erase entire region264 iter = s_activeMemoryRegions.erase(iter);265 s_itemIndicesInvalid = TRUE;266 return 2;267 }268 else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size)269 {270 // split region271 int eraseSize = (hardwareAddress + size) - region.hardwareAddress;272 MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.softwareAddress + eraseSize, region.virtualIndex + eraseSize};273 region.size = hardwareAddress - region.hardwareAddress;274 iter = s_activeMemoryRegions.insert(++iter, region2);275 s_itemIndicesInvalid = TRUE;276 return 2;277 }278 }280 /*281 // eliminates a range of hardware addresses from the search results282 // this is a simpler but usually slower interface for the above function283 void DeactivateRegion(HWAddressType hardwareAddress, unsigned int size)284 {285 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )286 {287 MemoryRegion& region = *iter;288 if(2 != DeactivateRegion(region, iter, hardwareAddress, size))289 ++iter;290 }291 }292 */294 struct AutoCritSect295 {296 AutoCritSect(CRITICAL_SECTION* cs) : m_cs(cs) { EnterCriticalSection(m_cs); }297 ~AutoCritSect() { LeaveCriticalSection(m_cs); }298 CRITICAL_SECTION* m_cs;299 };301 // warning: can be slow302 void CalculateItemIndices(int itemSize)303 {304 AutoCritSect cs(&s_activeMemoryRegionsCS);305 unsigned int itemIndex = 0;306 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)307 {308 MemoryRegion& region = *iter;309 region.itemIndex = itemIndex;310 int startSkipSize = ((unsigned int)(itemSize - (unsigned int)region.hardwareAddress)) % itemSize; // FIXME: is this still ok?311 unsigned int start = startSkipSize;312 unsigned int end = region.size;313 for(unsigned int i = start; i < end; i += itemSize)314 s_itemIndexToRegionPointer[itemIndex++] = ®ion;315 }316 s_maxItemIndex = itemIndex;317 s_itemIndicesInvalid = FALSE;318 }320 template<typename stepType, typename compareType>321 void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr)322 {323 //if(GetAsyncKeyState(VK_SHIFT) & 0x8000) // speed hack324 // return;326 if(s_prevValuesNeedUpdate)327 memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType));329 unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);332 unsigned char* sourceAddr = region.softwareAddress - region.virtualIndex;334 unsigned int indexStart = region.virtualIndex + startSkipSize;335 unsigned int indexEnd = region.virtualIndex + region.size;337 if(sizeof(compareType) == 1)338 {339 for(unsigned int i = indexStart; i < indexEnd; i++)340 {341 if(s_curValues[i] != sourceAddr[i]) // if value changed342 {343 s_curValues[i] = sourceAddr[i]; // update value344 //if(s_numChanges[i] != 0xFFFF)345 s_numChanges[i]++; // increase change count346 }347 }348 }349 else // it's more complicated for non-byte sizes because:350 { // - more than one byte can affect a given change count entry351 // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1352 // - a few of those bytes can be outside the region354 unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType);355 unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType);356 unsigned int lastIndexToCopy = lastIndexToRead;357 if(nextRegionPtr)358 {359 const MemoryRegion& nextRegion = *nextRegionPtr;360 int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType);361 unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize;362 if(lastIndexToCopy > nextIndexStart)363 lastIndexToCopy = nextIndexStart;364 }366 unsigned int nextValidChange [sizeof(compareType)];367 for(unsigned int i = 0; i < sizeof(compareType); i++)368 nextValidChange[i] = indexStart + i;370 for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++)371 {372 if(s_curValues[i] != sourceAddr[i]) // if value of this byte changed373 {374 if(i < lastIndexToCopy)375 s_curValues[i] = sourceAddr[i]; // update value376 for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte377 {378 if(i >= indexEnd+k)379 continue;380 int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1);381 if(nextValidChange[m] <= i) // if we didn't already increase the change count for this entry382 {383 //if(s_numChanges[i-k] != 0xFFFF)384 s_numChanges[i-k]++; // increase the change count for this entry385 nextValidChange[m] = i-k+sizeof(compareType); // and remember not to increase it again386 }387 }388 }389 }390 }391 }393 template<typename stepType, typename compareType>394 void UpdateRegionsT()395 {396 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();)397 {398 const MemoryRegion& region = *iter;399 ++iter;400 const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter;402 UpdateRegionT<stepType, compareType>(region, nextRegion);403 }405 s_prevValuesNeedUpdate = false;406 }408 template<typename stepType, typename compareType>409 int CountRegionItemsT()410 {411 AutoCritSect cs(&s_activeMemoryRegionsCS);412 if(sizeof(stepType) == 1)413 {414 if(s_activeMemoryRegions.empty())415 return 0;417 if(s_itemIndicesInvalid)418 CalculateItemIndices(sizeof(stepType));420 MemoryRegion& lastRegion = s_activeMemoryRegions.back();421 return lastRegion.itemIndex + lastRegion.size;422 }423 else // the branch above is faster but won't work if the step size isn't 1424 {425 int total = 0;426 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)427 {428 MemoryRegion& region = *iter;429 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);430 total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType);431 }432 return total;433 }434 }436 // returns information about the item in the form of a "fake" region437 // that has the item in it and nothing else438 template<typename stepType, typename compareType>439 void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion)440 {441 if(s_itemIndicesInvalid)442 CalculateItemIndices(sizeof(stepType));444 if(itemIndex >= s_maxItemIndex)445 {446 memset(&virtualRegion, 0, sizeof(MemoryRegion));447 return;448 }450 const MemoryRegion* regionPtr = s_itemIndexToRegionPointer[itemIndex];451 const MemoryRegion& region = *regionPtr;453 int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType);454 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);455 bytesWithinRegion += startSkipSize;457 virtualRegion.size = sizeof(compareType);458 virtualRegion.hardwareAddress = region.hardwareAddress + bytesWithinRegion;459 virtualRegion.softwareAddress = region.softwareAddress + bytesWithinRegion;460 virtualRegion.virtualIndex = region.virtualIndex + bytesWithinRegion;461 virtualRegion.itemIndex = itemIndex;462 return;463 }465 template<typename stepType, typename compareType>466 unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex)467 {468 MemoryRegion virtualRegion;469 ItemIndexToVirtualRegion<stepType,compareType>(itemIndex, virtualRegion);470 return virtualRegion.virtualIndex;471 }473 template<typename T>474 T ReadLocalValue(const unsigned char* data)475 {476 return *(const T*)data;477 }478 //template<> signed char ReadLocalValue(const unsigned char* data) { return *data; }479 //template<> unsigned char ReadLocalValue(const unsigned char* data) { return *data; }482 template<typename stepType, typename compareType>483 compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex)484 {485 return ReadLocalValue<compareType>(s_prevValues + virtualIndex);486 //return *(compareType*)(s_prevValues+virtualIndex);487 }488 template<typename stepType, typename compareType>489 compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex)490 {491 return ReadLocalValue<compareType>(s_curValues + virtualIndex);492 // return *(compareType*)(s_curValues+virtualIndex);493 }494 template<typename stepType, typename compareType>495 unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex)496 {497 unsigned short num = s_numChanges[virtualIndex];498 //for(unsigned int i = 1; i < sizeof(stepType); i++)499 // if(num < s_numChanges[virtualIndex+i])500 // num = s_numChanges[virtualIndex+i];501 return num;502 }504 template<typename stepType, typename compareType>505 compareType GetPrevValueFromItemIndex(unsigned int itemIndex)506 {507 int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);508 return GetPrevValueFromVirtualIndex<stepType,compareType>(virtualIndex);509 }510 template<typename stepType, typename compareType>511 compareType GetCurValueFromItemIndex(unsigned int itemIndex)512 {513 int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);514 return GetCurValueFromVirtualIndex<stepType,compareType>(virtualIndex);515 }516 template<typename stepType, typename compareType>517 unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex)518 {519 int virtualIndex = ItemIndexToVirtualIndex<stepType,compareType>(itemIndex);520 return GetNumChangesFromVirtualIndex<stepType,compareType>(virtualIndex);521 }522 template<typename stepType, typename compareType>523 unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex)524 {525 MemoryRegion virtualRegion;526 ItemIndexToVirtualRegion<stepType,compareType>(itemIndex, virtualRegion);527 return virtualRegion.hardwareAddress;528 }530 // this one might be unreliable, haven't used it much531 template<typename stepType, typename compareType>532 unsigned int HardwareAddressToItemIndex(HWAddressType hardwareAddress)533 {534 if(s_itemIndicesInvalid)535 CalculateItemIndices(sizeof(stepType));537 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter)538 {539 MemoryRegion& region = *iter;540 if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size)541 {542 int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType);543 return region.itemIndex + indexWithinRegion;544 }545 }547 return -1;548 }552 // workaround for MSVC 7 that doesn't support varadic C99 macros553 #define CALL_WITH_T_SIZE_TYPES_0(functionName, sizeTypeID, isSigned, requiresAligned) \554 (sizeTypeID == 'b' \555 ? (isSigned \556 ? functionName<char, signed char>() \557 : functionName<char, unsigned char>()) \558 : sizeTypeID == 'w' \559 ? (isSigned \560 ? (requiresAligned \561 ? functionName<short, signed short>() \562 : functionName<char, signed short>()) \563 : (requiresAligned \564 ? functionName<short, unsigned short>() \565 : functionName<char, unsigned short>())) \566 : sizeTypeID == 'd' \567 ? (isSigned \568 ? (requiresAligned \569 ? functionName<short, signed long>() \570 : functionName<char, signed long>()) \571 : (requiresAligned \572 ? functionName<short, unsigned long>() \573 : functionName<char, unsigned long>())) \574 : functionName<char, signed char>())576 #define CALL_WITH_T_SIZE_TYPES_1(functionName, sizeTypeID, isSigned, requiresAligned, p0) \577 (sizeTypeID == 'b' \578 ? (isSigned \579 ? functionName<char, signed char>(p0) \580 : functionName<char, unsigned char>(p0)) \581 : sizeTypeID == 'w' \582 ? (isSigned \583 ? (requiresAligned \584 ? functionName<short, signed short>(p0) \585 : functionName<char, signed short>(p0)) \586 : (requiresAligned \587 ? functionName<short, unsigned short>(p0) \588 : functionName<char, unsigned short>(p0))) \589 : sizeTypeID == 'd' \590 ? (isSigned \591 ? (requiresAligned \592 ? functionName<short, signed long>(p0) \593 : functionName<char, signed long>(p0)) \594 : (requiresAligned \595 ? functionName<short, unsigned long>(p0) \596 : functionName<char, unsigned long>(p0))) \597 : functionName<char, signed char>(p0))599 #define CALL_WITH_T_SIZE_TYPES_3(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2) \600 (sizeTypeID == 'b' \601 ? (isSigned \602 ? functionName<char, signed char>(p0, p1, p2) \603 : functionName<char, unsigned char>(p0, p1, p2)) \604 : sizeTypeID == 'w' \605 ? (isSigned \606 ? (requiresAligned \607 ? functionName<short, signed short>(p0, p1, p2) \608 : functionName<char, signed short>(p0, p1, p2)) \609 : (requiresAligned \610 ? functionName<short, unsigned short>(p0, p1, p2) \611 : functionName<char, unsigned short>(p0, p1, p2))) \612 : sizeTypeID == 'd' \613 ? (isSigned \614 ? (requiresAligned \615 ? functionName<short, signed long>(p0, p1, p2) \616 : functionName<char, signed long>(p0, p1, p2)) \617 : (requiresAligned \618 ? functionName<short, unsigned long>(p0, p1, p2) \619 : functionName<char, unsigned long>(p0, p1, p2))) \620 : functionName<char, signed char>(p0, p1, p2))622 #define CALL_WITH_T_SIZE_TYPES_4(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2, p3) \623 (sizeTypeID == 'b' \624 ? (isSigned \625 ? functionName<char, signed char>(p0, p1, p2, p3) \626 : functionName<char, unsigned char>(p0, p1, p2, p3)) \627 : sizeTypeID == 'w' \628 ? (isSigned \629 ? (requiresAligned \630 ? functionName<short, signed short>(p0, p1, p2, p3) \631 : functionName<char, signed short>(p0, p1, p2, p3)) \632 : (requiresAligned \633 ? functionName<short, unsigned short>(p0, p1, p2, p3) \634 : functionName<char, unsigned short>(p0, p1, p2, p3))) \635 : sizeTypeID == 'd' \636 ? (isSigned \637 ? (requiresAligned \638 ? functionName<short, signed long>(p0, p1, p2, p3) \639 : functionName<char, signed long>(p0, p1, p2, p3)) \640 : (requiresAligned \641 ? functionName<short, unsigned long>(p0, p1, p2, p3) \642 : functionName<char, unsigned long>(p0, p1, p2, p3))) \643 : functionName<char, signed char>(p0, p1, p2, p3))645 // version that takes a forced comparison type646 #define CALL_WITH_T_STEP_3(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2) \647 (sizeTypeID == 'b' \648 ? functionName<char, type>(p0, p1, p2) \649 : sizeTypeID == 'w' \650 ? (requiresAligned \651 ? functionName<short, type>(p0, p1, p2) \652 : functionName<char, type>(p0, p1, p2)) \653 : sizeTypeID == 'd' \654 ? (requiresAligned \655 ? functionName<short, type>(p0, p1, p2) \656 : functionName<char, type>(p0, p1, p2)) \657 : functionName<char, type>(p0, p1, p2))659 // version that takes a forced comparison type660 #define CALL_WITH_T_STEP_4(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2, p3) \661 (sizeTypeID == 'b' \662 ? functionName<char, type>(p0, p1, p2, p3) \663 : sizeTypeID == 'w' \664 ? (requiresAligned \665 ? functionName<short, type>(p0, p1, p2, p3) \666 : functionName<char, type>(p0, p1, p2, p3)) \667 : sizeTypeID == 'd' \668 ? (requiresAligned \669 ? functionName<short, type>(p0, p1, p2, p3) \670 : functionName<char, type>(p0, p1, p2, p3)) \671 : functionName<char, type>(p0, p1, p2, p3))673 // basic comparison functions:674 template <typename T> inline bool LessCmp (T x, T y, T i) { return x < y; }675 template <typename T> inline bool MoreCmp (T x, T y, T i) { return x > y; }676 template <typename T> inline bool LessEqualCmp (T x, T y, T i) { return x <= y; }677 template <typename T> inline bool MoreEqualCmp (T x, T y, T i) { return x >= y; }678 template <typename T> inline bool EqualCmp (T x, T y, T i) { return x == y; }679 template <typename T> inline bool UnequalCmp (T x, T y, T i) { return x != y; }680 template <typename T> inline bool DiffByCmp (T x, T y, T p) { return x - y == p || y - x == p; }681 template <typename T> inline bool ModIsCmp (T x, T y, T p) { return p && x % p == y; }683 // compare-to type functions:684 template<typename stepType, typename T>685 void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param)686 {687 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )688 {689 MemoryRegion& region = *iter;690 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);691 unsigned int start = region.virtualIndex + startSkipSize;692 unsigned int end = region.virtualIndex + region.size;693 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))694 if(!cmpFun(GetCurValueFromVirtualIndex<stepType,T>(i), GetPrevValueFromVirtualIndex<stepType,T>(i), param))695 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))696 goto outerContinue;697 ++iter;698 outerContinue:699 continue;700 }701 }702 template<typename stepType, typename T>703 void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param)704 {705 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )706 {707 MemoryRegion& region = *iter;708 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);709 unsigned int start = region.virtualIndex + startSkipSize;710 unsigned int end = region.virtualIndex + region.size;711 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))712 if(!cmpFun(GetCurValueFromVirtualIndex<stepType,T>(i), value, param))713 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))714 goto outerContinue;715 ++iter;716 outerContinue:717 continue;718 }719 }720 template<typename stepType, typename T>721 void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param)722 {723 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )724 {725 MemoryRegion& region = *iter;726 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);727 unsigned int start = region.virtualIndex + startSkipSize;728 unsigned int end = region.virtualIndex + region.size;729 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))730 if(!cmpFun(hwaddr, address, param))731 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))732 goto outerContinue;733 ++iter;734 outerContinue:735 continue;736 }737 }738 template<typename stepType, typename T>739 void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param)740 {741 for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); )742 {743 MemoryRegion& region = *iter;744 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType);745 unsigned int start = region.virtualIndex + startSkipSize;746 unsigned int end = region.virtualIndex + region.size;747 for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType))748 if(!cmpFun(GetNumChangesFromVirtualIndex<stepType,T>(i), changes, param))749 if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType)))750 goto outerContinue;751 ++iter;752 outerContinue:753 continue;754 }755 }757 char rs_c='s';758 char rs_o='=';759 char rs_t='s';760 int rs_param=0, rs_val=0, rs_val_valid=0;761 char rs_type_size = 'b', rs_last_type_size = rs_type_size;762 bool noMisalign = true, rs_last_no_misalign = noMisalign;763 //bool littleEndian = false;764 int last_rs_possible = -1;765 int last_rs_regions = -1;767 void prune(char c,char o,char t,int v,int p)768 {769 // repetition-reducing macros770 #define DO_SEARCH(sf) \771 switch (o) \772 { \773 case '<': DO_SEARCH_2(LessCmp,sf); break; \774 case '>': DO_SEARCH_2(MoreCmp,sf); break; \775 case '=': DO_SEARCH_2(EqualCmp,sf); break; \776 case '!': DO_SEARCH_2(UnequalCmp,sf); break; \777 case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \778 case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \779 case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \780 case '%': DO_SEARCH_2(ModIsCmp,sf); break; \781 default: assert(!"Invalid operator for this search type."); break; \782 }784 // perform the search, eliminating nonmatching values785 switch (c)786 {787 #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES_3(sf, rs_type_size, t, noMisalign, CmpFun,v,p)788 case 'r': DO_SEARCH(SearchRelative); break;789 case 's': DO_SEARCH(SearchSpecific); break;791 #undef DO_SEARCH_2792 #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned int, noMisalign, CmpFun,v,p)793 case 'a': DO_SEARCH(SearchAddress); break;795 #undef DO_SEARCH_2796 #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned short, noMisalign, CmpFun,v,p)797 case 'n': DO_SEARCH(SearchChanges); break;799 default: assert(!"Invalid search comparison type."); break;800 }802 s_prevValuesNeedUpdate = true;804 int prevNumItems = last_rs_possible;806 CompactAddrs();808 if(prevNumItems == last_rs_possible)809 {810 SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo811 }812 }817 template<typename stepType, typename T>818 bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param)819 {820 return cmpFun(GetCurValueFromItemIndex<stepType,T>(itemIndex), GetPrevValueFromItemIndex<stepType,T>(itemIndex), param);821 }822 template<typename stepType, typename T>823 bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param)824 {825 return cmpFun(GetCurValueFromItemIndex<stepType,T>(itemIndex), value, param);826 }827 template<typename stepType, typename T>828 bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param)829 {830 return cmpFun(GetHardwareAddressFromItemIndex<stepType,T>(itemIndex), address, param);831 }832 template<typename stepType, typename T>833 bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param)834 {835 return cmpFun(GetNumChangesFromItemIndex<stepType,T>(itemIndex), changes, param);836 }838 int ReadControlInt(int controlID, bool forceHex, BOOL& success)839 {840 int rv = 0;841 BOOL ok = false;843 if(!forceHex)844 {845 rv = GetDlgItemInt(RamSearchHWnd,controlID,&ok,(rs_t == 's'));846 }848 if(!ok)849 {850 if(GetDlgItemText(RamSearchHWnd,controlID,Str_Tmp,16))851 {852 for(int i = 0; Str_Tmp[i]; i++) {if(toupper(Str_Tmp[i]) == 'O') Str_Tmp[i] = '0';}853 const char* strPtr = Str_Tmp;854 bool negate = false;855 while(strPtr[0] == '-')856 strPtr++, negate = !negate;857 if(strPtr[0] == '+')858 strPtr++;859 if(strPtr[0] == '0' && tolower(strPtr[1]) == 'x')860 strPtr += 2, forceHex = true;861 if(strPtr[0] == '$')862 strPtr++, forceHex = true;863 if(!forceHex)864 {865 const char* strSearchPtr = strPtr;866 while(*strSearchPtr)867 {868 int c = tolower(*strSearchPtr++);869 if(c >= 'a' && c <= 'f')870 forceHex = true;871 }872 }873 const char* formatString = forceHex ? "%X" : ((rs_t=='s') ? "%d" : "%u");874 if(sscanf(strPtr, formatString, &rv) > 0)875 ok = true;876 if(negate)877 rv = -rv;878 }879 }881 success = ok;882 return rv;883 }886 bool Set_RS_Val()887 {888 BOOL success;890 // update rs_val891 switch(rs_c)892 {893 case 'r':894 default:895 rs_val = 0;896 break;897 case 's':898 rs_val = ReadControlInt(IDC_EDIT_COMPAREVALUE, rs_t == 'h', success);899 if(!success)900 return false;901 if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) ||902 (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) ||903 (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) ||904 (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535)))905 return false;906 break;907 case 'a':908 rs_val = ReadControlInt(IDC_EDIT_COMPAREADDRESS, true, success);909 if(!success || rs_val < 0 || rs_val > 0x06040000)910 return false;911 break;912 case 'n': {913 rs_val = ReadControlInt(IDC_EDIT_COMPARECHANGES, false, success);914 if(!success || rs_val < 0 || rs_val > 0xFFFF)915 return false;916 } break;917 }919 // also update rs_param920 switch(rs_o)921 {922 default:923 rs_param = 0;924 break;925 case 'd':926 rs_param = ReadControlInt(IDC_EDIT_DIFFBY, false, success);927 if(!success)928 return false;929 if(rs_param < 0)930 rs_param = -rs_param;931 break;932 case '%':933 rs_param = ReadControlInt(IDC_EDIT_MODBY, false, success);934 if(!success || rs_param == 0)935 return false;936 break;937 }939 // validate that rs_param fits in the comparison data type940 {941 int appliedSize = rs_type_size;942 int appliedSign = rs_t;943 if(rs_c == 'n')944 appliedSize = 'w', appliedSign = 'u';945 if(rs_c == 'a')946 appliedSize = 'd', appliedSign = 'u';947 if((appliedSize == 'b' && appliedSize == 's' && (rs_param < -128 || rs_param > 127)) ||948 (appliedSize == 'b' && appliedSize != 's' && (rs_param < 0 || rs_param > 255)) ||949 (appliedSize == 'w' && appliedSize == 's' && (rs_param < -32768 || rs_param > 32767)) ||950 (appliedSize == 'w' && appliedSize != 's' && (rs_param < 0 || rs_param > 65535)))951 return false;952 }954 return true;955 }957 bool IsSatisfied(int itemIndex)958 {959 if(!rs_val_valid)960 return true;961 int o = rs_o;962 switch (rs_c)963 {964 #undef DO_SEARCH_2965 #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);966 case 'r': DO_SEARCH(CompareRelativeAtItem); break;967 case 's': DO_SEARCH(CompareSpecificAtItem); break;969 #undef DO_SEARCH_2970 #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);971 case 'a': DO_SEARCH(CompareAddressAtItem); break;973 #undef DO_SEARCH_2974 #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);975 case 'n': DO_SEARCH(CompareChangesAtItem); break;976 }977 return false;978 }982 unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size)983 {984 unsigned int value = 0;985 if(address)986 {987 // assumes we're little-endian988 memcpy(&value, address, size);989 }990 return value;991 }992 void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size)993 {994 if(address)995 {996 // assumes we're little-endian997 memcpy(address, &value, size);998 }999 }1000 unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size)1001 {1002 return ReadValueAtSoftwareAddress(HardwareToSoftwareAddress(address), size);1003 }1004 bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsigned int size)1005 {1006 WriteValueAtSoftwareAddress(HardwareToSoftwareAddress(address), value, size);1007 return true;1008 }1009 bool IsHardwareAddressValid(HWAddressType address)1010 {1011 return HardwareToSoftwareAddress(address) != NULL;1012 }1016 int ResultCount=0;1017 bool AutoSearch=false;1018 bool AutoSearchAutoRetry=false;1019 LRESULT CALLBACK PromptWatchNameProc(HWND, UINT, WPARAM, LPARAM);1020 void UpdatePossibilities(int rs_possible, int regions);1023 void CompactAddrs()1024 {1025 int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2;1026 int prevResultCount = ResultCount;1028 CalculateItemIndices(size);1029 ResultCount = CALL_WITH_T_SIZE_TYPES_0(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign);1031 UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size());1033 if(ResultCount != prevResultCount)1034 ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount);1035 }1037 void soft_reset_address_info ()1038 {1039 s_prevValuesNeedUpdate = false;1040 ResetMemoryRegions();1041 if(!RamSearchHWnd)1042 {1043 EnterCriticalSection(&s_activeMemoryRegionsCS);1044 s_activeMemoryRegions.clear();1045 LeaveCriticalSection(&s_activeMemoryRegionsCS);1046 ResultCount = 0;1047 }1048 else1049 {1050 // force s_prevValues to be valid1051 signal_new_frame();1052 s_prevValuesNeedUpdate = true;1053 signal_new_frame();1054 }1055 if(s_numChanges)1056 memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));1057 CompactAddrs();1058 }1059 void reset_address_info ()1060 {1061 SetRamSearchUndoType(RamSearchHWnd, 0);1062 EnterCriticalSection(&s_activeMemoryRegionsCS);1063 s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo1064 LeaveCriticalSection(&s_activeMemoryRegionsCS);1065 if(s_prevValues)1066 memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE)));1067 s_prevValuesNeedUpdate = false;1068 ResetMemoryRegions();1069 if(!RamSearchHWnd)1070 {1071 EnterCriticalSection(&s_activeMemoryRegionsCS);1072 s_activeMemoryRegions.clear();1073 LeaveCriticalSection(&s_activeMemoryRegionsCS);1074 ResultCount = 0;1075 }1076 else1077 {1078 // force s_prevValues to be valid1079 signal_new_frame();1080 s_prevValuesNeedUpdate = true;1081 signal_new_frame();1082 }1083 memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));1084 CompactAddrs();1085 }1087 void signal_new_frame ()1088 {1089 EnterCriticalSection(&s_activeMemoryRegionsCS);1090 CALL_WITH_T_SIZE_TYPES_0(UpdateRegionsT, rs_type_size, rs_t=='s', noMisalign);1091 LeaveCriticalSection(&s_activeMemoryRegionsCS);1092 }1098 bool RamSearchClosed = false;1099 bool RamWatchClosed = false;1101 void ResetResults()1102 {1103 reset_address_info();1104 ResultCount = 0;1105 if (RamSearchHWnd)1106 ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount);1107 }1108 void CloseRamWindows() //Close the Ram Search & Watch windows when rom closes1109 {1110 ResetWatches();1111 ResetResults();1112 if (RamSearchHWnd)1113 {1114 SendMessage(RamSearchHWnd,WM_CLOSE,NULL,NULL);1115 RamSearchClosed = true;1116 }1117 if (RamWatchHWnd)1118 {1119 SendMessage(RamWatchHWnd,WM_CLOSE,NULL,NULL);1120 RamWatchClosed = true;1121 }1122 }1123 void ReopenRamWindows() //Reopen them when a new Rom is loaded1124 {1125 HWND hwnd = GetActiveWindow();1127 if (RamSearchClosed)1128 {1129 RamSearchClosed = false;1130 if(!RamSearchHWnd)1131 {1132 reset_address_info();1133 LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);1134 RamSearchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMSEARCH), hWnd, (DLGPROC) RamSearchProc);1135 }1136 else1137 ::SetForegroundWindow(RamSearchHWnd);1138 }1139 if (RamWatchClosed || AutoRWLoad)1140 {1141 RamWatchClosed = false;1142 if(!RamWatchHWnd)1143 {1144 if (AutoRWLoad) OpenRWRecentFile(0);1145 LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);1146 RamWatchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMWATCH), hWnd, (DLGPROC) RamWatchProc);1147 }1148 else1149 ::SetForegroundWindow(RamWatchHWnd);1150 }1152 if (hwnd == hWnd && hwnd != GetActiveWindow())1153 SetActiveWindow(hWnd); // restore focus to the main window if it had it before1154 }1160 void RefreshRamListSelectedCountControlStatus(HWND hDlg)1161 {1162 int selCount = ListView_GetSelectedCount(GetDlgItem(hDlg,IDC_RAMLIST));1163 if(selCount != s_prevSelCount)1164 {1165 if(selCount < 2 || s_prevSelCount < 2)1166 {1167 EnableWindow(GetDlgItem(hDlg, IDC_C_WATCH), (WatchCount < MAX_WATCH_COUNT) ? TRUE : FALSE);1168 EnableWindow(GetDlgItem(hDlg, IDC_C_ADDCHEAT), (selCount >= 1) ? TRUE : FALSE);1169 EnableWindow(GetDlgItem(hDlg, IDC_C_ELIMINATE), (selCount >= 1) ? TRUE : FALSE);1170 }1171 s_prevSelCount = selCount;1172 }1173 }1178 struct AddrRange1179 {1180 unsigned int addr;1181 unsigned int size;1182 unsigned int End() const { return addr + size; }1183 AddrRange(unsigned int a, unsigned int s) : addr(a),size(s){}1184 };1186 void signal_new_size ()1187 {1188 HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST);1190 int oldSize = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2;1191 int newSize = (rs_type_size=='b' || !noMisalign) ? 1 : 2;1192 bool numberOfItemsChanged = (oldSize != newSize);1194 unsigned int itemsPerPage = ListView_GetCountPerPage(lv);1195 unsigned int oldTopIndex = ListView_GetTopIndex(lv);1196 unsigned int oldSelectionIndex = ListView_GetSelectionMark(lv);1197 unsigned int oldTopAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldTopIndex);1198 unsigned int oldSelectionAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldSelectionIndex);1200 std::vector<AddrRange> selHardwareAddrs;1201 if(numberOfItemsChanged)1202 {1203 // store selection ranges1204 // unfortunately this can take a while if the user has a huge range of items selected1205 systemSoundClearBuffer();1206 int selCount = ListView_GetSelectedCount(lv);1207 int size = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2;1208 int watchIndex = -1;1209 for(int i = 0; i < selCount; ++i)1210 {1211 watchIndex = ListView_GetNextItem(lv, watchIndex, LVNI_SELECTED);1212 int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, watchIndex);1213 if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End())1214 selHardwareAddrs.back().size += size;1215 else if (!(noMisalign && oldSize < newSize && addr % newSize != 0))1216 selHardwareAddrs.push_back(AddrRange(addr,size));1217 }1218 }1220 CompactAddrs();1222 rs_last_type_size = rs_type_size;1223 rs_last_no_misalign = noMisalign;1225 if(numberOfItemsChanged)1226 {1227 // restore selection ranges1228 unsigned int newTopIndex = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, oldTopAddr);1229 unsigned int newBottomIndex = newTopIndex + itemsPerPage - 1;1230 SendMessage(lv, WM_SETREDRAW, FALSE, 0);1231 ListView_SetItemState(lv, -1, 0, LVIS_SELECTED|LVIS_FOCUSED); // deselect all1232 for(unsigned int i = 0; i < selHardwareAddrs.size(); i++)1233 {1234 // calculate index ranges of this selection1235 const AddrRange& range = selHardwareAddrs[i];1236 int selRangeTop = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, range.addr);1237 int selRangeBottom = -1;1238 for(int endAddr = range.End()-1; endAddr >= selRangeTop && selRangeBottom == -1; endAddr--)1239 selRangeBottom = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, endAddr);1240 if(selRangeBottom == -1)1241 selRangeBottom = selRangeTop;1242 if(selRangeTop == -1)1243 continue;1245 // select the entire range1246 for (int j = selRangeTop; j <= selRangeBottom; j++)1247 {1248 ListView_SetItemState(lv, j, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED);1249 }1250 }1252 // restore previous scroll position1253 if(newBottomIndex != -1)1254 ListView_EnsureVisible(lv, newBottomIndex, 0);1255 if(newTopIndex != -1)1256 ListView_EnsureVisible(lv, newTopIndex, 0);1258 SendMessage(lv, WM_SETREDRAW, TRUE, 0);1260 RefreshRamListSelectedCountControlStatus(RamSearchHWnd);1262 EnableWindow(GetDlgItem(RamSearchHWnd,IDC_MISALIGN), rs_type_size != 'b');1263 }1264 else1265 {1266 ListView_Update(lv, -1);1267 }1268 InvalidateRect(lv, NULL, TRUE);1269 //SetFocus(lv);1270 }1275 LRESULT CustomDraw (LPARAM lParam)1276 {1277 LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;1279 switch(lplvcd->nmcd.dwDrawStage)1280 {1281 case CDDS_PREPAINT :1282 return CDRF_NOTIFYITEMDRAW;1284 case CDDS_ITEMPREPAINT:1285 {1286 int rv = CDRF_DODEFAULT;1288 if(lplvcd->nmcd.dwItemSpec % 2)1289 {1290 // alternate the background color slightly1291 lplvcd->clrTextBk = RGB(248,248,255);1292 rv = CDRF_NEWFONT;1293 }1295 if(!IsSatisfied(lplvcd->nmcd.dwItemSpec))1296 {1297 // tint red any items that would be eliminated if a search were to run now1298 lplvcd->clrText = RGB(192,64,64);1299 rv = CDRF_NEWFONT;1300 }1302 return rv;1303 } break;1304 }1305 return CDRF_DODEFAULT;1306 }1308 void Update_RAM_Search() //keeps RAM values up to date in the search and watch windows1309 {1310 if(disableRamSearchUpdate)1311 return;1313 int prevValuesNeededUpdate;1314 if (AutoSearch && !ResultCount)1315 {1316 if(!AutoSearchAutoRetry)1317 {1318 systemSoundClearBuffer();1319 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);1320 if(answer == IDABORT)1321 {1322 SendDlgItemMessage(RamSearchHWnd, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0);1323 SendMessage(RamSearchHWnd, WM_COMMAND, IDC_C_AUTOSEARCH, 0);1324 }1325 if(answer == IDIGNORE)1326 AutoSearchAutoRetry = true;1327 }1328 reset_address_info();1329 prevValuesNeededUpdate = s_prevValuesNeedUpdate;1330 }1331 else1332 {1333 prevValuesNeededUpdate = s_prevValuesNeedUpdate;1334 if (RamSearchHWnd)1335 {1336 // update active RAM values1337 signal_new_frame();1338 }1340 if (AutoSearch && ResultCount)1341 {1342 systemSoundClearBuffer();1343 if(!rs_val_valid)1344 rs_val_valid = Set_RS_Val();1345 if(rs_val_valid)1346 prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param);1347 }1348 }1350 if(RamSearchHWnd)1351 {1352 HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST);1353 if(prevValuesNeededUpdate != s_prevValuesNeedUpdate)1354 {1355 // previous values got updated, refresh everything visible1356 ListView_Update(lv, -1);1357 }1358 else1359 {1360 // refresh any visible parts of the listview box that changed1361 static int changes[128];1362 int top = ListView_GetTopIndex(lv);1363 int count = ListView_GetCountPerPage(lv);1364 int start = -1;1365 for(int i = top; i <= top+count; i++)1366 {1367 int changeNum = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, i); //s_numChanges[i];1368 int changed = changeNum != changes[i-top];1369 if(changed)1370 changes[i-top] = changeNum;1372 if(start == -1)1373 {1374 if(i != top+count && changed)1375 {1376 start = i;1377 //somethingChanged = true;1378 }1379 }1380 else1381 {1382 if(i == top+count || !changed)1383 {1384 ListView_RedrawItems(lv, start, i-1);1385 start = -1;1386 }1387 }1388 }1389 }1390 }1392 if(RamWatchHWnd)1393 {1394 Update_RAM_Watch();1395 }1396 }1398 static int rs_lastPercent = -1;1399 inline void UpdateRamSearchProgressBar(int percent)1400 {1401 if(rs_lastPercent != percent)1402 {1403 rs_lastPercent = percent;1404 UpdateRamSearchTitleBar(percent);1405 }1406 }1408 static void SelectEditControl(int controlID)1409 {1410 HWND hEdit = GetDlgItem(RamSearchHWnd,controlID);1411 SetFocus(hEdit);1412 SendMessage(hEdit, EM_SETSEL, 0, -1);1413 }1415 static BOOL SelectingByKeyboard()1416 {1417 int a = GetKeyState(VK_LEFT);1418 int b = GetKeyState(VK_RIGHT);1419 int c = GetKeyState(VK_UP);1420 int d = GetKeyState(VK_DOWN); // space and tab are intentionally omitted1421 return (a | b | c | d) & 0x80;1422 }1425 LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)1426 {1427 static int watchIndex=0;1429 switch(uMsg)1430 {1431 case WM_INITDIALOG: {1432 RamSearchHWnd = hDlg;1434 SetWindowPos(hDlg, NULL, regQueryDwordValue("ramSearchX", 0), regQueryDwordValue("ramSearchY", 0), NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);1435 switch(rs_o)1436 {1437 case '<':1438 SendDlgItemMessage(hDlg, IDC_LESSTHAN, BM_SETCHECK, BST_CHECKED, 0);1439 break;1440 case '>':1441 SendDlgItemMessage(hDlg, IDC_MORETHAN, BM_SETCHECK, BST_CHECKED, 0);1442 break;1443 case 'l':1444 SendDlgItemMessage(hDlg, IDC_NOMORETHAN, BM_SETCHECK, BST_CHECKED, 0);1445 break;1446 case 'm':1447 SendDlgItemMessage(hDlg, IDC_NOLESSTHAN, BM_SETCHECK, BST_CHECKED, 0);1448 break;1449 case '=':1450 SendDlgItemMessage(hDlg, IDC_EQUALTO, BM_SETCHECK, BST_CHECKED, 0);1451 break;1452 case '!':1453 SendDlgItemMessage(hDlg, IDC_DIFFERENTFROM, BM_SETCHECK, BST_CHECKED, 0);1454 break;1455 case 'd':1456 SendDlgItemMessage(hDlg, IDC_DIFFERENTBY, BM_SETCHECK, BST_CHECKED, 0);1457 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true);1458 break;1459 case '%':1460 SendDlgItemMessage(hDlg, IDC_MODULO, BM_SETCHECK, BST_CHECKED, 0);1461 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true);1462 break;1463 }1464 switch (rs_c)1465 {1466 case 'r':1467 SendDlgItemMessage(hDlg, IDC_PREVIOUSVALUE, BM_SETCHECK, BST_CHECKED, 0);1468 break;1469 case 's':1470 SendDlgItemMessage(hDlg, IDC_SPECIFICVALUE, BM_SETCHECK, BST_CHECKED, 0);1471 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true);1472 break;1473 case 'a':1474 SendDlgItemMessage(hDlg, IDC_SPECIFICADDRESS, BM_SETCHECK, BST_CHECKED, 0);1475 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true);1476 break;1477 case 'n':1478 SendDlgItemMessage(hDlg, IDC_NUMBEROFCHANGES, BM_SETCHECK, BST_CHECKED, 0);1479 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true);1480 break;1481 }1482 switch (rs_t)1483 {1484 case 's':1485 SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0);1486 break;1487 case 'u':1488 SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0);1489 break;1490 case 'h':1491 SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0);1492 break;1493 }1494 switch (rs_type_size)1495 {1496 case 'b':1497 SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0);1498 break;1499 case 'w':1500 SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0);1501 break;1502 case 'd':1503 SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0);1504 break;1505 }1507 s_prevValuesNeedUpdate = true;1509 SendDlgItemMessage(hDlg,IDC_C_AUTOSEARCH,BM_SETCHECK,AutoSearch?BST_CHECKED:BST_UNCHECKED,0);1510 //const char* names[5] = {"Address","Value","Previous","Changes","Notes"};1511 //int widths[5] = {62,64,64,55,55};1512 const char* names[] = {"Address","Value","Previous","Changes"};1513 int widths[4] = {68,76,76,68};1514 if (!ResultCount)1515 reset_address_info();1516 else1517 {1518 signal_new_frame();1519 CompactAddrs();1520 }1521 void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths);1522 init_list_box(GetDlgItem(hDlg,IDC_RAMLIST),names,4,widths);1523 //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount);1524 if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0);1525 //if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0);1526 last_rs_possible = -1;1528 s_prevSelCount = -1;1529 RefreshRamListSelectedCountControlStatus(hDlg);1531 // force misalign checkbox to refresh1532 signal_new_size();1534 // force undo button to refresh1535 int undoType = s_undoType;1536 SetRamSearchUndoType(hDlg, -2);1537 SetRamSearchUndoType(hDlg, undoType);1539 // force possibility count to refresh1540 last_rs_possible--;1541 UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size());1543 rs_val_valid = Set_RS_Val();1545 ListView_SetCallbackMask(GetDlgItem(hDlg,IDC_RAMLIST), LVIS_FOCUSED|LVIS_SELECTED);1547 return true;1548 } break;1550 case WM_NOTIFY:1551 {1552 LPNMHDR lP = (LPNMHDR) lParam;1553 switch (lP->code)1554 {1555 case LVN_ITEMCHANGED: // selection changed event1556 {1557 NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lP;1558 if(pNMListView->uNewState & LVIS_FOCUSED ||1559 (pNMListView->uNewState ^ pNMListView->uOldState) & LVIS_SELECTED)1560 {1561 // disable buttons that we don't have the right number of selected items for1562 RefreshRamListSelectedCountControlStatus(hDlg);1563 }1564 } break;1566 case LVN_GETDISPINFO:1567 {1568 LV_DISPINFO *Item = (LV_DISPINFO *)lParam;1569 Item->item.mask = LVIF_TEXT;1570 Item->item.state = 0;1571 Item->item.iImage = 0;1572 const unsigned int iNum = Item->item.iItem;1573 static char num[11];1574 switch (Item->item.iSubItem)1575 {1576 case 0:1577 {1578 int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);1579 sprintf(num,"%08X",addr);1580 Item->item.pszText = num;1581 } return true;1582 case 1:1583 {1584 int i = CALL_WITH_T_SIZE_TYPES_1(GetCurValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);1585 const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X"));1586 switch (rs_type_size)1587 {1588 case 'b':1589 default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break;1590 case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break;1591 case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break;1592 }1593 Item->item.pszText = num;1594 } return true;1595 case 2:1596 {1597 int i = CALL_WITH_T_SIZE_TYPES_1(GetPrevValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);1598 const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X"));1599 switch (rs_type_size)1600 {1601 case 'b':1602 default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break;1603 case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break;1604 case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break;1605 }1606 Item->item.pszText = num;1607 } return true;1608 case 3:1609 {1610 int i = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum);1611 sprintf(num,"%d",i);1613 Item->item.pszText = num;1614 } return true;1615 //case 4:1616 // Item->item.pszText = rsaddrs[rsresults[iNum].Index].comment ? rsaddrs[rsresults[iNum].Index].comment : "";1617 // return true;1618 default:1619 return false;1620 }1621 }1623 case NM_CUSTOMDRAW:1624 {1625 SetWindowLong(hDlg, DWL_MSGRESULT, CustomDraw(lParam));1626 return TRUE;1627 } break;1629 //case LVN_ODCACHEHINT: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something.1630 //{1631 // LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam;1632 // return 0;1633 //}1634 //case LVN_ODFINDITEM: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something.1635 //{1636 // LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam;1637 // return 0;1638 //}1639 }1640 } break;1642 case WM_COMMAND:1643 {1644 int rv = false;1645 switch(LOWORD(wParam))1646 {1647 case IDC_SIGNED:1648 rs_t='s';1649 signal_new_size();1650 {rv = true; break;}1651 case IDC_UNSIGNED:1652 rs_t='u';1653 signal_new_size();1654 {rv = true; break;}1655 case IDC_HEX:1656 rs_t='h';1657 signal_new_size();1658 {rv = true; break;}1659 case IDC_1_BYTE:1660 rs_type_size = 'b';1661 signal_new_size();1662 {rv = true; break;}1663 case IDC_2_BYTES:1664 rs_type_size = 'w';1665 signal_new_size();1666 {rv = true; break;}1667 case IDC_4_BYTES:1668 rs_type_size = 'd';1669 signal_new_size();1670 {rv = true; break;}1671 case IDC_MISALIGN:1672 noMisalign = !noMisalign;1673 //CompactAddrs();1674 signal_new_size();1675 {rv = true; break;}1676 // case IDC_ENDIAN:1677 //// littleEndian = !littleEndian;1678 //// signal_new_size();1679 // {rv = true; break;}1680 case IDC_LESSTHAN:1681 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);1682 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);1683 rs_o = '<';1684 {rv = true; break;}1685 case IDC_MORETHAN:1686 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);1687 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);1688 rs_o = '>';1689 {rv = true; break;}1690 case IDC_NOMORETHAN:1691 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);1692 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);1693 rs_o = 'l';1694 {rv = true; break;}1695 case IDC_NOLESSTHAN:1696 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);1697 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);1698 rs_o = 'm';1699 {rv = true; break;}1700 case IDC_EQUALTO:1701 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);1702 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);1703 rs_o = '=';1704 {rv = true; break;}1705 case IDC_DIFFERENTFROM:1706 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);1707 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);1708 rs_o = '!';1709 {rv = true; break;}1710 case IDC_DIFFERENTBY:1711 {1712 rs_o = 'd';1713 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true);1714 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false);1715 if(!SelectingByKeyboard())1716 SelectEditControl(IDC_EDIT_DIFFBY);1717 } {rv = true; break;}1718 case IDC_MODULO:1719 {1720 rs_o = '%';1721 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false);1722 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true);1723 if(!SelectingByKeyboard())1724 SelectEditControl(IDC_EDIT_MODBY);1725 } {rv = true; break;}1726 case IDC_PREVIOUSVALUE:1727 rs_c='r';1728 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);1729 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);1730 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);1731 {rv = true; break;}1732 case IDC_SPECIFICVALUE:1733 {1734 rs_c = 's';1735 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true);1736 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);1737 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);1738 if(!SelectingByKeyboard())1739 SelectEditControl(IDC_EDIT_COMPAREVALUE);1740 {rv = true; break;}1741 }1742 case IDC_SPECIFICADDRESS:1743 {1744 rs_c = 'a';1745 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true);1746 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);1747 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false);1748 if(!SelectingByKeyboard())1749 SelectEditControl(IDC_EDIT_COMPAREADDRESS);1750 } {rv = true; break;}1751 case IDC_NUMBEROFCHANGES:1752 {1753 rs_c = 'n';1754 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true);1755 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false);1756 EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false);1757 if(!SelectingByKeyboard())1758 SelectEditControl(IDC_EDIT_COMPARECHANGES);1759 } {rv = true; break;}1760 case IDC_C_ADDCHEAT:1761 {1762 HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);1763 int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED);1764 while (watchItemIndex >= 0)1765 {1766 unsigned long address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex);1768 int sizeType = -1;1769 if(rs_type_size == 'b')1770 sizeType = 0;1771 else if(rs_type_size == 'w')1772 sizeType = 1;1773 else if(rs_type_size == 'd')1774 sizeType = 2;1776 int numberType = -1;1777 if(rs_t == 's')1778 numberType = 0;1779 else if(rs_t == 'u')1780 numberType = 1;1781 else if(rs_t == 'h')1782 numberType = 2;1784 if(systemCartridgeType == 0)1785 {1786 AddCheat dlg (address/*, hDlg*/);1787 if(sizeType != -1) dlg.sizeType = sizeType;1788 if(numberType != -1) dlg.numberType = numberType;1789 dlg.DoModal();1790 }1791 else1792 {1793 AddGBCheat dlg (address/*, hDlg*/);1794 if(sizeType != -1) dlg.sizeType = sizeType;1795 if(numberType != -1) dlg.numberType = numberType;1796 dlg.DoModal();1797 }1798 watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED);1799 }1800 } {rv = true; break;}1801 case IDC_C_RESET:1802 {1803 RamSearchSaveUndoStateIfNotTooBig(RamSearchHWnd);1804 int prevNumItems = last_rs_possible;1806 soft_reset_address_info();1808 if(prevNumItems == last_rs_possible)1809 SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo1811 ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all1812 //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount);1813 ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0);1814 RefreshRamListSelectedCountControlStatus(hDlg);1815 {rv = true; break;}1816 }1817 case IDC_C_RESET_CHANGES:1818 memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE)));1819 ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1);1820 //SetRamSearchUndoType(hDlg, 0);1821 {rv = true; break;}1822 case IDC_C_UNDO:1823 if(s_undoType>0)1824 {1825 systemSoundClearBuffer();1826 EnterCriticalSection(&s_activeMemoryRegionsCS);1827 if(s_activeMemoryRegions.size() < tooManyRegionsForUndo)1828 {1829 MemoryList tempMemoryList = s_activeMemoryRegions;1830 s_activeMemoryRegions = s_activeMemoryRegionsBackup;1831 s_activeMemoryRegionsBackup = tempMemoryList;1832 LeaveCriticalSection(&s_activeMemoryRegionsCS);1833 SetRamSearchUndoType(hDlg, 3 - s_undoType);1834 }1835 else1836 {1837 s_activeMemoryRegions = s_activeMemoryRegionsBackup;1838 LeaveCriticalSection(&s_activeMemoryRegionsCS);1839 SetRamSearchUndoType(hDlg, -1);1840 }1841 CompactAddrs();1842 ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all1843 ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0);1844 RefreshRamListSelectedCountControlStatus(hDlg);1845 }1846 {rv = true; break;}1847 case IDC_C_AUTOSEARCH:1848 AutoSearch = SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_GETCHECK, 0, 0) != 0;1849 AutoSearchAutoRetry = false;1850 if (!AutoSearch) {rv = true; break;}1851 case IDC_C_SEARCH:1852 {1853 systemSoundClearBuffer();1855 if(!rs_val_valid && !(rs_val_valid = Set_RS_Val()))1856 goto invalid_field;1858 if(ResultCount)1859 {1860 RamSearchSaveUndoStateIfNotTooBig(hDlg);1862 prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param);1864 RefreshRamListSelectedCountControlStatus(hDlg);1865 }1867 if(!ResultCount)1868 {1870 MessageBox(RamSearchHWnd,"Resetting search.","Out of results.",MB_OK|MB_ICONINFORMATION);1871 soft_reset_address_info();1872 }1874 {rv = true; break;}1876 invalid_field:1877 MessageBox(RamSearchHWnd,"Invalid or out-of-bound entered value.","Error",MB_OK|MB_ICONSTOP);1878 if(AutoSearch) // stop autosearch if it just started1879 {1880 SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0);1881 SendMessage(hDlg, WM_COMMAND, IDC_C_AUTOSEARCH, 0);1882 }1883 {rv = true; break;}1884 }1885 case IDC_C_WATCH:1886 {1887 HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);1888 int selCount = ListView_GetSelectedCount(ramListControl);1890 bool inserted = false;1891 int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED);1892 while (watchItemIndex >= 0)1893 {1894 AddressWatcher tempWatch;1895 tempWatch.Address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex);1896 tempWatch.Size = rs_type_size;1897 tempWatch.Type = rs_t;1898 tempWatch.WrongEndian = 0; //Replace when I get little endian working1899 tempWatch.comment = NULL;1901 if (selCount == 1)1902 inserted |= InsertWatch(tempWatch, hDlg);1903 else1904 inserted |= InsertWatch(tempWatch, "");1906 watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED);1907 }1908 // bring up the ram watch window if it's not already showing so the user knows where the watch went1909 if(inserted && !RamWatchHWnd)1910 SendMessage(hWnd, WM_COMMAND, ID_RAM_WATCH, 0);1911 SetForegroundWindow(RamSearchHWnd);1912 {rv = true; break;}1913 }1915 // eliminate all selected items1916 case IDC_C_ELIMINATE:1917 {1918 RamSearchSaveUndoStateIfNotTooBig(hDlg);1920 HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST);1921 int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2;1922 int selCount = ListView_GetSelectedCount(ramListControl);1923 int watchIndex = -1;1925 // time-saving trick #1:1926 // condense the selected items into an array of address ranges1927 std::vector<AddrRange> selHardwareAddrs;1928 for(int i = 0, j = 1024; i < selCount; ++i, --j)1929 {1930 watchIndex = ListView_GetNextItem(ramListControl, watchIndex, LVNI_SELECTED);1931 int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchIndex);1932 if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End())1933 selHardwareAddrs.back().size += size;1934 else1935 selHardwareAddrs.push_back(AddrRange(addr,size));1937 if(!j) UpdateRamSearchProgressBar(i * 50 / selCount), j = 1024;1938 }1940 // now deactivate the ranges1942 // time-saving trick #2:1943 // take advantage of the fact that the listbox items must be in the same order as the regions1944 MemoryList::iterator iter = s_activeMemoryRegions.begin();1945 int numHardwareAddrRanges = selHardwareAddrs.size();1946 for(int i = 0, j = 16; i < numHardwareAddrRanges; ++i, --j)1947 {1948 int addr = selHardwareAddrs[i].addr;1949 int size = selHardwareAddrs[i].size;1950 bool affected = false;1951 while(iter != s_activeMemoryRegions.end())1952 {1953 MemoryRegion& region = *iter;1954 int affNow = DeactivateRegion(region, iter, addr, size);1955 if(affNow)1956 affected = true;1957 else if(affected)1958 break;1959 if(affNow != 2)1960 ++iter;1961 }1963 if(!j) UpdateRamSearchProgressBar(50 + (i * 50 / selCount)), j = 16;1964 }1965 UpdateRamSearchTitleBar();1967 // careful -- if the above two time-saving tricks aren't working,1968 // the runtime can absolutely explode (seconds -> hours) when there are lots of regions1970 ListView_SetItemState(ramListControl, -1, 0, LVIS_SELECTED); // deselect all1971 signal_new_size();1972 {rv = true; break;}1973 }1974 //case IDOK:1975 case IDCANCEL:1976 RamSearchHWnd = NULL;1977 /* if (theApp.pauseDuringCheatSearch)1978 EndDialog(hDlg, true); // this should never be called on a modeless dialog1979 else1980 */1981 DestroyWindow(hDlg);1982 {rv = true; break;}1983 }1985 // check refresh for comparison preview color update1986 // also, update rs_val if needed1987 bool needRefresh = false;1988 switch(LOWORD(wParam))1989 {1990 case IDC_LESSTHAN:1991 case IDC_MORETHAN:1992 case IDC_NOMORETHAN:1993 case IDC_NOLESSTHAN:1994 case IDC_EQUALTO:1995 case IDC_DIFFERENTFROM:1996 case IDC_DIFFERENTBY:1997 case IDC_MODULO:1998 case IDC_PREVIOUSVALUE:1999 case IDC_SPECIFICVALUE:2000 case IDC_SPECIFICADDRESS:2001 case IDC_NUMBEROFCHANGES:2002 case IDC_SIGNED:2003 case IDC_UNSIGNED:2004 case IDC_HEX:2005 rs_val_valid = Set_RS_Val();2006 needRefresh = true;2007 break;2008 case IDC_EDIT_COMPAREVALUE:2009 case IDC_EDIT_COMPAREADDRESS:2010 case IDC_EDIT_COMPARECHANGES:2011 case IDC_EDIT_DIFFBY:2012 case IDC_EDIT_MODBY:2013 if(HIWORD(wParam) == EN_CHANGE)2014 {2015 rs_val_valid = Set_RS_Val();2016 needRefresh = true;2017 }2018 break;2019 }2020 if(needRefresh)2021 ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1);2024 return rv;2025 } break;2027 case WM_CLOSE:2028 RECT r;2029 GetWindowRect(hDlg, &r);2030 regSetDwordValue("ramSearchX", r.left);2031 regSetDwordValue("ramSearchY", r.top);2032 SendMessage(RamSearchHWnd, WM_DESTROY, 0, 0);2033 break;2034 case WM_DESTROY:2035 RamSearchHWnd = NULL;2036 // theApp.modelessCheatDialogIsOpen = false;2037 // return true;2038 break;2039 }2041 return false;2042 }2044 void UpdateRamSearchTitleBar(int percent)2045 {2046 #define HEADER_STR " RAM Search - "2047 #define PROGRESS_STR " %d%% ... "2048 #define STATUS_STR "%d Possibilit%s (%d Region%s)"2050 int poss = last_rs_possible;2051 int regions = last_rs_regions;2052 if(poss <= 0)2053 strcpy(Str_Tmp," RAM Search");2054 else if(percent <= 0)2055 sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s");2056 else2057 sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s");2058 SetWindowText(RamSearchHWnd, Str_Tmp);2059 }2061 void UpdatePossibilities(int rs_possible, int regions)2062 {2063 if(rs_possible != last_rs_possible)2064 {2065 last_rs_possible = rs_possible;2066 last_rs_regions = regions;2067 UpdateRamSearchTitleBar();2068 }2069 }2071 void SetRamSearchUndoType(HWND hDlg, int type)2072 {2073 if(s_undoType != type)2074 {2075 if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1))2076 SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo"));2077 if((s_undoType>0)!=(type>0))2078 EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0);2079 s_undoType = type;2080 }2081 }2083 void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg)2084 {2085 EnterCriticalSection(&s_activeMemoryRegionsCS);2086 if(s_activeMemoryRegions.size() < tooManyRegionsForUndo)2087 {2088 s_activeMemoryRegionsBackup = s_activeMemoryRegions;2089 LeaveCriticalSection(&s_activeMemoryRegionsCS);2090 SetRamSearchUndoType(hDlg, 1);2091 }2092 else2093 {2094 LeaveCriticalSection(&s_activeMemoryRegionsCS);2095 SetRamSearchUndoType(hDlg, 0);2096 }2097 }2099 struct InitRamSearch2100 {2101 InitRamSearch()2102 {2103 InitializeCriticalSection(&s_activeMemoryRegionsCS);2104 }2105 ~InitRamSearch()2106 {2107 DeleteCriticalSection(&s_activeMemoryRegionsCS);2108 }2109 } initRamSearch;2112 void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths) //initializes the ram search and/or ram watch listbox2113 {2114 LVCOLUMN Col;2115 Col.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;2116 Col.fmt = LVCFMT_CENTER;2117 for (int i = 0; i < numColumns; i++)2118 {2119 Col.iOrder = i;2120 Col.iSubItem = i;2121 Col.pszText = (LPSTR)(Strs[i]);2122 Col.cx = columnWidths[i];2123 ListView_InsertColumn(Box,i,&Col);2124 }2126 ListView_SetExtendedListViewStyle(Box, LVS_EX_FULLROWSELECT);2127 }