rlm@1: // A few notes about this implementation of a RAM search window: rlm@1: // rlm@1: // Speed of update was one of the highest priories. rlm@1: // This is because I wanted the RAM search window to be able to rlm@1: // update every single value in RAM every single frame, and rlm@1: // keep track of the exact number of frames across which each value has changed, rlm@1: // without causing the emulation to run noticeably slower than normal. rlm@1: // rlm@1: // The data representation was changed from one entry per valid address rlm@1: // to one entry per contiguous range of uneliminated addresses rlm@1: // which references uniform pools of per-address properties. rlm@1: // - This saves time when there are many items because rlm@1: // it minimizes the amount of data that needs to be stored and processed per address. rlm@1: // - It also saves time when there are few items because rlm@1: // it ensures that no time is wasted in iterating through rlm@1: // addresses that have already been eliminated from the search. rlm@1: // rlm@1: // The worst-case scenario is when every other item has been rlm@1: // eliminated from the search, maximizing the number of regions. rlm@1: // This implementation manages to handle even that pathological case rlm@1: // acceptably well. In fact, it still updates faster than the previous implementation. rlm@1: // The time spent setting up or clearing such a large number of regions rlm@1: // is somewhat horrendous, but it seems reasonable to have poor worst-case speed rlm@1: // during these sporadic "setup" steps to achieve an all-around faster per-update speed. rlm@1: // (You can test this case by performing the search: Modulo 2 Is Specific Address 0) rlm@1: rlm@1: rlm@1: #ifdef _WIN32 rlm@1: #include "stdafx.h" rlm@1: #include "resource.h" rlm@1: #include "VBA.h" rlm@1: //#include rlm@1: #include rlm@1: #include "BaseTsd.h" rlm@1: #include "GBACheatsDlg.h" rlm@1: #include "GBCheatsDlg.h" rlm@1: typedef INT_PTR intptr_t; rlm@1: #else rlm@1: #include "stdint.h" rlm@1: #endif rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #include "ram_search.h" rlm@1: #include "ramwatch.h" rlm@1: #include "../gba/GBAGlobals.h" rlm@1: #include "../gb/gbGlobals.h" rlm@1: #include "../common/vbalua.h" rlm@1: #include "Reg.h" rlm@1: rlm@1: static inline u8* HardwareToSoftwareAddress(HWAddressType address) rlm@1: { rlm@1: if(!emulating) rlm@1: return NULL; rlm@1: rlm@1: // note: this currently follows the "quick" memory rules, rlm@1: // meaning it will miss whatever special cases aren't handled by read/writeMemoryQuick. rlm@1: // if this is made more accurate, it may be necessary to reduce regionSearchGranularity. rlm@1: if(systemCartridgeType == 0) rlm@1: { rlm@1: // GBA rlm@1: HWAddressType mask = ::map[address >> 24].mask; rlm@1: if(!mask || (address & 0xFFFFFF) > mask) rlm@1: return NULL; rlm@1: return &::map[address >> 24].address[address & mask]; rlm@1: } rlm@1: else rlm@1: { rlm@1: // GB rlm@1: extern int32 gbEchoRAMFixOn; rlm@1: if (gbEchoRAMFixOn) rlm@1: if (address >= 0xe000 && address < 0xfe00) rlm@1: address -= 0x2000; rlm@1: if((address>>12) >= sizeof(gbMemoryMap)/sizeof(*gbMemoryMap)) rlm@1: return NULL; rlm@1: return &gbMemoryMap[address>>12][address&0xfff]; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: struct MemoryRegion rlm@1: { rlm@1: HWAddressType hardwareAddress; // hardware address of the start of this region rlm@1: unsigned int size; // number of bytes to the end of this region rlm@1: unsigned char* softwareAddress; // pointer to the start of the live emulator source values for this region rlm@1: rlm@1: unsigned int virtualIndex; // index into s_prevValues, s_curValues, and s_numChanges, valid after being initialized in ResetMemoryRegions() rlm@1: unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false rlm@1: }; rlm@1: rlm@1: int MAX_RAM_SIZE = 0; rlm@1: static unsigned char* s_prevValues = 0; // values at last search or reset rlm@1: static unsigned char* s_curValues = 0; // values at last frame update rlm@1: static unsigned short* s_numChanges = 0; // number of changes of the item starting at this virtual index address rlm@1: 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 rlm@1: 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 rlm@1: static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled rlm@1: 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 rlm@1: static int s_prevSelCount = -1; rlm@1: rlm@1: HWND RamSearchHWnd; rlm@1: #define hWnd AfxGetMainWnd()->GetSafeHwnd() rlm@1: #define hInst AfxGetInstanceHandle() rlm@1: static char Str_Tmp [1024]; rlm@1: rlm@1: int disableRamSearchUpdate = false; rlm@1: rlm@1: rlm@1: rlm@1: //static const MemoryRegion s_prgRegion = { 0x020000, SEGACD_RAM_PRG_SIZE, (unsigned char*)Ram_Prg, true}; rlm@1: //static const MemoryRegion s_word1MRegion = { 0x200000, SEGACD_1M_RAM_SIZE, (unsigned char*)Ram_Word_1M, true}; rlm@1: //static const MemoryRegion s_word2MRegion = { 0x200000, SEGACD_2M_RAM_SIZE, (unsigned char*)Ram_Word_2M, true}; rlm@1: //static const MemoryRegion s_z80Region = { 0xA00000, Z80_RAM_SIZE, (unsigned char*)Ram_Z80, true}; rlm@1: //static const MemoryRegion s_68kRegion = { 0xFF0000, _68K_RAM_SIZE, (unsigned char*)Ram_68k, true}; rlm@1: //static const MemoryRegion s_32xRegion = {0x06000000, _32X_RAM_SIZE, (unsigned char*)_32X_Ram, false}; rlm@1: rlm@1: // list of contiguous uneliminated memory regions rlm@1: typedef std::list MemoryList; rlm@1: static MemoryList s_activeMemoryRegions; rlm@1: static CRITICAL_SECTION s_activeMemoryRegionsCS; rlm@1: rlm@1: // for undo support (could be better, but this way was really easy) rlm@1: static MemoryList s_activeMemoryRegionsBackup; rlm@1: static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can redo rlm@1: rlm@1: void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg); rlm@1: static const int tooManyRegionsForUndo = 10000; rlm@1: rlm@1: void ResetMemoryRegions() rlm@1: { rlm@1: systemSoundClearBuffer(); rlm@1: EnterCriticalSection(&s_activeMemoryRegionsCS); rlm@1: rlm@1: s_activeMemoryRegions.clear(); rlm@1: rlm@1: // use HardwareToSoftwareAddress to figure out what all the possible memory regions are, rlm@1: // split up wherever there's a discontinuity in the address in our software RAM. rlm@1: 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. rlm@1: HWAddressType hwRegionStart = 0; rlm@1: u8* regionStart = NULL; rlm@1: u8* regionEnd = NULL; rlm@1: for(HWAddressType addr = 0; addr != 0x10000000+regionSearchGranularity; addr += regionSearchGranularity) rlm@1: { rlm@1: u8* swAddr = HardwareToSoftwareAddress(addr); rlm@1: if(regionEnd && swAddr != regionEnd+regionSearchGranularity) rlm@1: { rlm@1: // hit end of region rlm@1: // check to see if it mirrors an existing one (in which case we discard it) rlm@1: bool discard = false; rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: if(region.softwareAddress == regionStart) rlm@1: { rlm@1: unsigned int size = regionSearchGranularity + (regionEnd - regionStart); rlm@1: if(size <= region.size) rlm@1: { rlm@1: discard = true; rlm@1: } rlm@1: else rlm@1: { rlm@1: hwRegionStart += region.size; rlm@1: regionStart += region.size; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // don't include ROM in our RAM search (it's too huge) rlm@1: if(regionStart == rom || regionStart == gbRom) rlm@1: discard = true; rlm@1: rlm@1: // create the region rlm@1: if(!discard) rlm@1: { rlm@1: MemoryRegion region = { hwRegionStart, regionSearchGranularity + (regionEnd - regionStart), regionStart }; rlm@1: s_activeMemoryRegions.push_back(region); rlm@1: } rlm@1: rlm@1: hwRegionStart = 0; rlm@1: regionStart = NULL; rlm@1: regionEnd = NULL; rlm@1: } rlm@1: if(swAddr) rlm@1: { rlm@1: if(regionStart) rlm@1: { rlm@1: // continue region rlm@1: regionEnd = swAddr; rlm@1: } rlm@1: else rlm@1: { rlm@1: // start new region rlm@1: hwRegionStart = addr; rlm@1: regionStart = swAddr; rlm@1: regionEnd = swAddr; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: int nextVirtualIndex = 0; rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: region.virtualIndex = nextVirtualIndex; rlm@1: assert(((intptr_t)region.softwareAddress & 1) == 0 && "somebody needs to reimplement ReadValueAtSoftwareAddress()"); rlm@1: nextVirtualIndex = region.virtualIndex + region.size; rlm@1: } rlm@1: //assert(nextVirtualIndex <= MAX_RAM_SIZE); rlm@1: rlm@1: if(nextVirtualIndex > MAX_RAM_SIZE) rlm@1: { rlm@1: s_prevValues = (unsigned char*)realloc(s_prevValues, sizeof(char)*(nextVirtualIndex+4)); rlm@1: memset(s_prevValues, 0, sizeof(char)*(nextVirtualIndex+4)); rlm@1: rlm@1: s_curValues = (unsigned char*)realloc(s_curValues, sizeof(char)*(nextVirtualIndex+4)); rlm@1: memset(s_curValues, 0, sizeof(char)*(nextVirtualIndex+4)); rlm@1: rlm@1: s_numChanges = (unsigned short*)realloc(s_numChanges, sizeof(short)*(nextVirtualIndex+4)); rlm@1: memset(s_numChanges, 0, sizeof(short)*(nextVirtualIndex+4)); rlm@1: rlm@1: s_itemIndexToRegionPointer = (MemoryRegion**)realloc(s_itemIndexToRegionPointer, sizeof(MemoryRegion*)*(nextVirtualIndex+4)); rlm@1: memset(s_itemIndexToRegionPointer, 0, sizeof(MemoryRegion*)*(nextVirtualIndex+4)); rlm@1: rlm@1: MAX_RAM_SIZE = nextVirtualIndex; rlm@1: } rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: } rlm@1: rlm@1: // eliminates a range of hardware addresses from the search results rlm@1: // returns 2 if it changed the region and moved the iterator to another region rlm@1: // returns 1 if it changed the region but didn't move the iterator rlm@1: // returns 0 if it had no effect rlm@1: // warning: don't call anything that takes an itemIndex in a loop that calls DeactivateRegion... rlm@1: // doing so would be tremendously slow because DeactivateRegion invalidates the index cache rlm@1: int DeactivateRegion(MemoryRegion& region, MemoryList::iterator& iter, HWAddressType hardwareAddress, unsigned int size) rlm@1: { rlm@1: if(hardwareAddress + size <= region.hardwareAddress || hardwareAddress >= region.hardwareAddress + region.size) rlm@1: { rlm@1: // region is unaffected rlm@1: return 0; rlm@1: } rlm@1: else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) rlm@1: { rlm@1: // erase end of region rlm@1: region.size = hardwareAddress - region.hardwareAddress; rlm@1: return 1; rlm@1: } rlm@1: else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) rlm@1: { rlm@1: // erase start of region rlm@1: int eraseSize = (hardwareAddress + size) - region.hardwareAddress; rlm@1: region.hardwareAddress += eraseSize; rlm@1: region.size -= eraseSize; rlm@1: region.softwareAddress += eraseSize; rlm@1: region.virtualIndex += eraseSize; rlm@1: return 1; rlm@1: } rlm@1: else if(hardwareAddress <= region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) rlm@1: { rlm@1: // erase entire region rlm@1: iter = s_activeMemoryRegions.erase(iter); rlm@1: s_itemIndicesInvalid = TRUE; rlm@1: return 2; rlm@1: } rlm@1: else //if(hardwareAddress > region.hardwareAddress && hardwareAddress + size < region.hardwareAddress + region.size) rlm@1: { rlm@1: // split region rlm@1: int eraseSize = (hardwareAddress + size) - region.hardwareAddress; rlm@1: MemoryRegion region2 = {region.hardwareAddress + eraseSize, region.size - eraseSize, region.softwareAddress + eraseSize, region.virtualIndex + eraseSize}; rlm@1: region.size = hardwareAddress - region.hardwareAddress; rlm@1: iter = s_activeMemoryRegions.insert(++iter, region2); rlm@1: s_itemIndicesInvalid = TRUE; rlm@1: return 2; rlm@1: } rlm@1: } rlm@1: rlm@1: /* rlm@1: // eliminates a range of hardware addresses from the search results rlm@1: // this is a simpler but usually slower interface for the above function rlm@1: void DeactivateRegion(HWAddressType hardwareAddress, unsigned int size) rlm@1: { rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: if(2 != DeactivateRegion(region, iter, hardwareAddress, size)) rlm@1: ++iter; rlm@1: } rlm@1: } rlm@1: */ rlm@1: rlm@1: struct AutoCritSect rlm@1: { rlm@1: AutoCritSect(CRITICAL_SECTION* cs) : m_cs(cs) { EnterCriticalSection(m_cs); } rlm@1: ~AutoCritSect() { LeaveCriticalSection(m_cs); } rlm@1: CRITICAL_SECTION* m_cs; rlm@1: }; rlm@1: rlm@1: // warning: can be slow rlm@1: void CalculateItemIndices(int itemSize) rlm@1: { rlm@1: AutoCritSect cs(&s_activeMemoryRegionsCS); rlm@1: unsigned int itemIndex = 0; rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: region.itemIndex = itemIndex; rlm@1: int startSkipSize = ((unsigned int)(itemSize - (unsigned int)region.hardwareAddress)) % itemSize; // FIXME: is this still ok? rlm@1: unsigned int start = startSkipSize; rlm@1: unsigned int end = region.size; rlm@1: for(unsigned int i = start; i < end; i += itemSize) rlm@1: s_itemIndexToRegionPointer[itemIndex++] = ®ion; rlm@1: } rlm@1: s_maxItemIndex = itemIndex; rlm@1: s_itemIndicesInvalid = FALSE; rlm@1: } rlm@1: rlm@1: template rlm@1: void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr) rlm@1: { rlm@1: //if(GetAsyncKeyState(VK_SHIFT) & 0x8000) // speed hack rlm@1: // return; rlm@1: rlm@1: if(s_prevValuesNeedUpdate) rlm@1: memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); rlm@1: rlm@1: unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); rlm@1: rlm@1: rlm@1: unsigned char* sourceAddr = region.softwareAddress - region.virtualIndex; rlm@1: rlm@1: unsigned int indexStart = region.virtualIndex + startSkipSize; rlm@1: unsigned int indexEnd = region.virtualIndex + region.size; rlm@1: rlm@1: if(sizeof(compareType) == 1) rlm@1: { rlm@1: for(unsigned int i = indexStart; i < indexEnd; i++) rlm@1: { rlm@1: if(s_curValues[i] != sourceAddr[i]) // if value changed rlm@1: { rlm@1: s_curValues[i] = sourceAddr[i]; // update value rlm@1: //if(s_numChanges[i] != 0xFFFF) rlm@1: s_numChanges[i]++; // increase change count rlm@1: } rlm@1: } rlm@1: } rlm@1: else // it's more complicated for non-byte sizes because: rlm@1: { // - more than one byte can affect a given change count entry rlm@1: // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1 rlm@1: // - a few of those bytes can be outside the region rlm@1: rlm@1: unsigned int endSkipSize = ((unsigned int)(startSkipSize - region.size)) % sizeof(stepType); rlm@1: unsigned int lastIndexToRead = indexEnd + endSkipSize + sizeof(compareType) - sizeof(stepType); rlm@1: unsigned int lastIndexToCopy = lastIndexToRead; rlm@1: if(nextRegionPtr) rlm@1: { rlm@1: const MemoryRegion& nextRegion = *nextRegionPtr; rlm@1: int nextStartSkipSize = ((unsigned int)(sizeof(stepType) - nextRegion.hardwareAddress)) % sizeof(stepType); rlm@1: unsigned int nextIndexStart = nextRegion.virtualIndex + nextStartSkipSize; rlm@1: if(lastIndexToCopy > nextIndexStart) rlm@1: lastIndexToCopy = nextIndexStart; rlm@1: } rlm@1: rlm@1: unsigned int nextValidChange [sizeof(compareType)]; rlm@1: for(unsigned int i = 0; i < sizeof(compareType); i++) rlm@1: nextValidChange[i] = indexStart + i; rlm@1: rlm@1: for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++) rlm@1: { rlm@1: if(s_curValues[i] != sourceAddr[i]) // if value of this byte changed rlm@1: { rlm@1: if(i < lastIndexToCopy) rlm@1: s_curValues[i] = sourceAddr[i]; // update value rlm@1: for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte rlm@1: { rlm@1: if(i >= indexEnd+k) rlm@1: continue; rlm@1: int m = (j-k+sizeof(compareType)) & (sizeof(compareType)-1); rlm@1: if(nextValidChange[m] <= i) // if we didn't already increase the change count for this entry rlm@1: { rlm@1: //if(s_numChanges[i-k] != 0xFFFF) rlm@1: s_numChanges[i-k]++; // increase the change count for this entry rlm@1: nextValidChange[m] = i-k+sizeof(compareType); // and remember not to increase it again rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: template rlm@1: void UpdateRegionsT() rlm@1: { rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end();) rlm@1: { rlm@1: const MemoryRegion& region = *iter; rlm@1: ++iter; rlm@1: const MemoryRegion* nextRegion = (iter == s_activeMemoryRegions.end()) ? NULL : &*iter; rlm@1: rlm@1: UpdateRegionT(region, nextRegion); rlm@1: } rlm@1: rlm@1: s_prevValuesNeedUpdate = false; rlm@1: } rlm@1: rlm@1: template rlm@1: int CountRegionItemsT() rlm@1: { rlm@1: AutoCritSect cs(&s_activeMemoryRegionsCS); rlm@1: if(sizeof(stepType) == 1) rlm@1: { rlm@1: if(s_activeMemoryRegions.empty()) rlm@1: return 0; rlm@1: rlm@1: if(s_itemIndicesInvalid) rlm@1: CalculateItemIndices(sizeof(stepType)); rlm@1: rlm@1: MemoryRegion& lastRegion = s_activeMemoryRegions.back(); rlm@1: return lastRegion.itemIndex + lastRegion.size; rlm@1: } rlm@1: else // the branch above is faster but won't work if the step size isn't 1 rlm@1: { rlm@1: int total = 0; rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); rlm@1: total += (region.size - startSkipSize + (sizeof(stepType)-1)) / sizeof(stepType); rlm@1: } rlm@1: return total; rlm@1: } rlm@1: } rlm@1: rlm@1: // returns information about the item in the form of a "fake" region rlm@1: // that has the item in it and nothing else rlm@1: template rlm@1: void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion) rlm@1: { rlm@1: if(s_itemIndicesInvalid) rlm@1: CalculateItemIndices(sizeof(stepType)); rlm@1: rlm@1: if(itemIndex >= s_maxItemIndex) rlm@1: { rlm@1: memset(&virtualRegion, 0, sizeof(MemoryRegion)); rlm@1: return; rlm@1: } rlm@1: rlm@1: const MemoryRegion* regionPtr = s_itemIndexToRegionPointer[itemIndex]; rlm@1: const MemoryRegion& region = *regionPtr; rlm@1: rlm@1: int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType); rlm@1: int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); rlm@1: bytesWithinRegion += startSkipSize; rlm@1: rlm@1: virtualRegion.size = sizeof(compareType); rlm@1: virtualRegion.hardwareAddress = region.hardwareAddress + bytesWithinRegion; rlm@1: virtualRegion.softwareAddress = region.softwareAddress + bytesWithinRegion; rlm@1: virtualRegion.virtualIndex = region.virtualIndex + bytesWithinRegion; rlm@1: virtualRegion.itemIndex = itemIndex; rlm@1: return; rlm@1: } rlm@1: rlm@1: template rlm@1: unsigned int ItemIndexToVirtualIndex(unsigned int itemIndex) rlm@1: { rlm@1: MemoryRegion virtualRegion; rlm@1: ItemIndexToVirtualRegion(itemIndex, virtualRegion); rlm@1: return virtualRegion.virtualIndex; rlm@1: } rlm@1: rlm@1: template rlm@1: T ReadLocalValue(const unsigned char* data) rlm@1: { rlm@1: return *(const T*)data; rlm@1: } rlm@1: //template<> signed char ReadLocalValue(const unsigned char* data) { return *data; } rlm@1: //template<> unsigned char ReadLocalValue(const unsigned char* data) { return *data; } rlm@1: rlm@1: rlm@1: template rlm@1: compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex) rlm@1: { rlm@1: return ReadLocalValue(s_prevValues + virtualIndex); rlm@1: //return *(compareType*)(s_prevValues+virtualIndex); rlm@1: } rlm@1: template rlm@1: compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex) rlm@1: { rlm@1: return ReadLocalValue(s_curValues + virtualIndex); rlm@1: // return *(compareType*)(s_curValues+virtualIndex); rlm@1: } rlm@1: template rlm@1: unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex) rlm@1: { rlm@1: unsigned short num = s_numChanges[virtualIndex]; rlm@1: //for(unsigned int i = 1; i < sizeof(stepType); i++) rlm@1: // if(num < s_numChanges[virtualIndex+i]) rlm@1: // num = s_numChanges[virtualIndex+i]; rlm@1: return num; rlm@1: } rlm@1: rlm@1: template rlm@1: compareType GetPrevValueFromItemIndex(unsigned int itemIndex) rlm@1: { rlm@1: int virtualIndex = ItemIndexToVirtualIndex(itemIndex); rlm@1: return GetPrevValueFromVirtualIndex(virtualIndex); rlm@1: } rlm@1: template rlm@1: compareType GetCurValueFromItemIndex(unsigned int itemIndex) rlm@1: { rlm@1: int virtualIndex = ItemIndexToVirtualIndex(itemIndex); rlm@1: return GetCurValueFromVirtualIndex(virtualIndex); rlm@1: } rlm@1: template rlm@1: unsigned short GetNumChangesFromItemIndex(unsigned int itemIndex) rlm@1: { rlm@1: int virtualIndex = ItemIndexToVirtualIndex(itemIndex); rlm@1: return GetNumChangesFromVirtualIndex(virtualIndex); rlm@1: } rlm@1: template rlm@1: unsigned int GetHardwareAddressFromItemIndex(unsigned int itemIndex) rlm@1: { rlm@1: MemoryRegion virtualRegion; rlm@1: ItemIndexToVirtualRegion(itemIndex, virtualRegion); rlm@1: return virtualRegion.hardwareAddress; rlm@1: } rlm@1: rlm@1: // this one might be unreliable, haven't used it much rlm@1: template rlm@1: unsigned int HardwareAddressToItemIndex(HWAddressType hardwareAddress) rlm@1: { rlm@1: if(s_itemIndicesInvalid) rlm@1: CalculateItemIndices(sizeof(stepType)); rlm@1: rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ++iter) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: if(hardwareAddress >= region.hardwareAddress && hardwareAddress < region.hardwareAddress + region.size) rlm@1: { rlm@1: int indexWithinRegion = (hardwareAddress - region.hardwareAddress) / sizeof(stepType); rlm@1: return region.itemIndex + indexWithinRegion; rlm@1: } rlm@1: } rlm@1: rlm@1: return -1; rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: // workaround for MSVC 7 that doesn't support varadic C99 macros rlm@1: #define CALL_WITH_T_SIZE_TYPES_0(functionName, sizeTypeID, isSigned, requiresAligned) \ rlm@1: (sizeTypeID == 'b' \ rlm@1: ? (isSigned \ rlm@1: ? functionName() \ rlm@1: : functionName()) \ rlm@1: : sizeTypeID == 'w' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName() \ rlm@1: : functionName()) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName() \ rlm@1: : functionName())) \ rlm@1: : sizeTypeID == 'd' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName() \ rlm@1: : functionName()) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName() \ rlm@1: : functionName())) \ rlm@1: : functionName()) rlm@1: rlm@1: #define CALL_WITH_T_SIZE_TYPES_1(functionName, sizeTypeID, isSigned, requiresAligned, p0) \ rlm@1: (sizeTypeID == 'b' \ rlm@1: ? (isSigned \ rlm@1: ? functionName(p0) \ rlm@1: : functionName(p0)) \ rlm@1: : sizeTypeID == 'w' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0) \ rlm@1: : functionName(p0)) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName(p0) \ rlm@1: : functionName(p0))) \ rlm@1: : sizeTypeID == 'd' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0) \ rlm@1: : functionName(p0)) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName(p0) \ rlm@1: : functionName(p0))) \ rlm@1: : functionName(p0)) rlm@1: rlm@1: #define CALL_WITH_T_SIZE_TYPES_3(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2) \ rlm@1: (sizeTypeID == 'b' \ rlm@1: ? (isSigned \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : functionName(p0, p1, p2)) \ rlm@1: : sizeTypeID == 'w' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : functionName(p0, p1, p2)) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : functionName(p0, p1, p2))) \ rlm@1: : sizeTypeID == 'd' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : functionName(p0, p1, p2)) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : functionName(p0, p1, p2))) \ rlm@1: : functionName(p0, p1, p2)) rlm@1: rlm@1: #define CALL_WITH_T_SIZE_TYPES_4(functionName, sizeTypeID, isSigned, requiresAligned, p0, p1, p2, p3) \ rlm@1: (sizeTypeID == 'b' \ rlm@1: ? (isSigned \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : functionName(p0, p1, p2, p3)) \ rlm@1: : sizeTypeID == 'w' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : functionName(p0, p1, p2, p3)) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : functionName(p0, p1, p2, p3))) \ rlm@1: : sizeTypeID == 'd' \ rlm@1: ? (isSigned \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : functionName(p0, p1, p2, p3)) \ rlm@1: : (requiresAligned \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : functionName(p0, p1, p2, p3))) \ rlm@1: : functionName(p0, p1, p2, p3)) rlm@1: rlm@1: // version that takes a forced comparison type rlm@1: #define CALL_WITH_T_STEP_3(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2) \ rlm@1: (sizeTypeID == 'b' \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : sizeTypeID == 'w' \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : functionName(p0, p1, p2)) \ rlm@1: : sizeTypeID == 'd' \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2) \ rlm@1: : functionName(p0, p1, p2)) \ rlm@1: : functionName(p0, p1, p2)) rlm@1: rlm@1: // version that takes a forced comparison type rlm@1: #define CALL_WITH_T_STEP_4(functionName, sizeTypeID, type, requiresAligned, p0, p1, p2, p3) \ rlm@1: (sizeTypeID == 'b' \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : sizeTypeID == 'w' \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : functionName(p0, p1, p2, p3)) \ rlm@1: : sizeTypeID == 'd' \ rlm@1: ? (requiresAligned \ rlm@1: ? functionName(p0, p1, p2, p3) \ rlm@1: : functionName(p0, p1, p2, p3)) \ rlm@1: : functionName(p0, p1, p2, p3)) rlm@1: rlm@1: // basic comparison functions: rlm@1: template inline bool LessCmp (T x, T y, T i) { return x < y; } rlm@1: template inline bool MoreCmp (T x, T y, T i) { return x > y; } rlm@1: template inline bool LessEqualCmp (T x, T y, T i) { return x <= y; } rlm@1: template inline bool MoreEqualCmp (T x, T y, T i) { return x >= y; } rlm@1: template inline bool EqualCmp (T x, T y, T i) { return x == y; } rlm@1: template inline bool UnequalCmp (T x, T y, T i) { return x != y; } rlm@1: template inline bool DiffByCmp (T x, T y, T p) { return x - y == p || y - x == p; } rlm@1: template inline bool ModIsCmp (T x, T y, T p) { return p && x % p == y; } rlm@1: rlm@1: // compare-to type functions: rlm@1: template rlm@1: void SearchRelative (bool(*cmpFun)(T,T,T), T ignored, T param) rlm@1: { rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); rlm@1: unsigned int start = region.virtualIndex + startSkipSize; rlm@1: unsigned int end = region.virtualIndex + region.size; rlm@1: for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) rlm@1: if(!cmpFun(GetCurValueFromVirtualIndex(i), GetPrevValueFromVirtualIndex(i), param)) rlm@1: if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) rlm@1: goto outerContinue; rlm@1: ++iter; rlm@1: outerContinue: rlm@1: continue; rlm@1: } rlm@1: } rlm@1: template rlm@1: void SearchSpecific (bool(*cmpFun)(T,T,T), T value, T param) rlm@1: { rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); rlm@1: unsigned int start = region.virtualIndex + startSkipSize; rlm@1: unsigned int end = region.virtualIndex + region.size; rlm@1: for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) rlm@1: if(!cmpFun(GetCurValueFromVirtualIndex(i), value, param)) rlm@1: if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) rlm@1: goto outerContinue; rlm@1: ++iter; rlm@1: outerContinue: rlm@1: continue; rlm@1: } rlm@1: } rlm@1: template rlm@1: void SearchAddress (bool(*cmpFun)(T,T,T), T address, T param) rlm@1: { rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); rlm@1: unsigned int start = region.virtualIndex + startSkipSize; rlm@1: unsigned int end = region.virtualIndex + region.size; rlm@1: for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) rlm@1: if(!cmpFun(hwaddr, address, param)) rlm@1: if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) rlm@1: goto outerContinue; rlm@1: ++iter; rlm@1: outerContinue: rlm@1: continue; rlm@1: } rlm@1: } rlm@1: template rlm@1: void SearchChanges (bool(*cmpFun)(T,T,T), T changes, T param) rlm@1: { rlm@1: for(MemoryList::iterator iter = s_activeMemoryRegions.begin(); iter != s_activeMemoryRegions.end(); ) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); rlm@1: unsigned int start = region.virtualIndex + startSkipSize; rlm@1: unsigned int end = region.virtualIndex + region.size; rlm@1: for(unsigned int i = start, hwaddr = region.hardwareAddress; i < end; i += sizeof(stepType), hwaddr += sizeof(stepType)) rlm@1: if(!cmpFun(GetNumChangesFromVirtualIndex(i), changes, param)) rlm@1: if(2 == DeactivateRegion(region, iter, hwaddr, sizeof(stepType))) rlm@1: goto outerContinue; rlm@1: ++iter; rlm@1: outerContinue: rlm@1: continue; rlm@1: } rlm@1: } rlm@1: rlm@1: char rs_c='s'; rlm@1: char rs_o='='; rlm@1: char rs_t='s'; rlm@1: int rs_param=0, rs_val=0, rs_val_valid=0; rlm@1: char rs_type_size = 'b', rs_last_type_size = rs_type_size; rlm@1: bool noMisalign = true, rs_last_no_misalign = noMisalign; rlm@1: //bool littleEndian = false; rlm@1: int last_rs_possible = -1; rlm@1: int last_rs_regions = -1; rlm@1: rlm@1: void prune(char c,char o,char t,int v,int p) rlm@1: { rlm@1: // repetition-reducing macros rlm@1: #define DO_SEARCH(sf) \ rlm@1: switch (o) \ rlm@1: { \ rlm@1: case '<': DO_SEARCH_2(LessCmp,sf); break; \ rlm@1: case '>': DO_SEARCH_2(MoreCmp,sf); break; \ rlm@1: case '=': DO_SEARCH_2(EqualCmp,sf); break; \ rlm@1: case '!': DO_SEARCH_2(UnequalCmp,sf); break; \ rlm@1: case 'l': DO_SEARCH_2(LessEqualCmp,sf); break; \ rlm@1: case 'm': DO_SEARCH_2(MoreEqualCmp,sf); break; \ rlm@1: case 'd': DO_SEARCH_2(DiffByCmp,sf); break; \ rlm@1: case '%': DO_SEARCH_2(ModIsCmp,sf); break; \ rlm@1: default: assert(!"Invalid operator for this search type."); break; \ rlm@1: } rlm@1: rlm@1: // perform the search, eliminating nonmatching values rlm@1: switch (c) rlm@1: { rlm@1: #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_SIZE_TYPES_3(sf, rs_type_size, t, noMisalign, CmpFun,v,p) rlm@1: case 'r': DO_SEARCH(SearchRelative); break; rlm@1: case 's': DO_SEARCH(SearchSpecific); break; rlm@1: rlm@1: #undef DO_SEARCH_2 rlm@1: #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned int, noMisalign, CmpFun,v,p) rlm@1: case 'a': DO_SEARCH(SearchAddress); break; rlm@1: rlm@1: #undef DO_SEARCH_2 rlm@1: #define DO_SEARCH_2(CmpFun,sf) CALL_WITH_T_STEP_3(sf, rs_type_size, unsigned short, noMisalign, CmpFun,v,p) rlm@1: case 'n': DO_SEARCH(SearchChanges); break; rlm@1: rlm@1: default: assert(!"Invalid search comparison type."); break; rlm@1: } rlm@1: rlm@1: s_prevValuesNeedUpdate = true; rlm@1: rlm@1: int prevNumItems = last_rs_possible; rlm@1: rlm@1: CompactAddrs(); rlm@1: rlm@1: if(prevNumItems == last_rs_possible) rlm@1: { rlm@1: SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: template rlm@1: bool CompareRelativeAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T ignored, T param) rlm@1: { rlm@1: return cmpFun(GetCurValueFromItemIndex(itemIndex), GetPrevValueFromItemIndex(itemIndex), param); rlm@1: } rlm@1: template rlm@1: bool CompareSpecificAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T value, T param) rlm@1: { rlm@1: return cmpFun(GetCurValueFromItemIndex(itemIndex), value, param); rlm@1: } rlm@1: template rlm@1: bool CompareAddressAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T address, T param) rlm@1: { rlm@1: return cmpFun(GetHardwareAddressFromItemIndex(itemIndex), address, param); rlm@1: } rlm@1: template rlm@1: bool CompareChangesAtItem (bool(*cmpFun)(T,T,T), int itemIndex, T changes, T param) rlm@1: { rlm@1: return cmpFun(GetNumChangesFromItemIndex(itemIndex), changes, param); rlm@1: } rlm@1: rlm@1: int ReadControlInt(int controlID, bool forceHex, BOOL& success) rlm@1: { rlm@1: int rv = 0; rlm@1: BOOL ok = false; rlm@1: rlm@1: if(!forceHex) rlm@1: { rlm@1: rv = GetDlgItemInt(RamSearchHWnd,controlID,&ok,(rs_t == 's')); rlm@1: } rlm@1: rlm@1: if(!ok) rlm@1: { rlm@1: if(GetDlgItemText(RamSearchHWnd,controlID,Str_Tmp,16)) rlm@1: { rlm@1: for(int i = 0; Str_Tmp[i]; i++) {if(toupper(Str_Tmp[i]) == 'O') Str_Tmp[i] = '0';} rlm@1: const char* strPtr = Str_Tmp; rlm@1: bool negate = false; rlm@1: while(strPtr[0] == '-') rlm@1: strPtr++, negate = !negate; rlm@1: if(strPtr[0] == '+') rlm@1: strPtr++; rlm@1: if(strPtr[0] == '0' && tolower(strPtr[1]) == 'x') rlm@1: strPtr += 2, forceHex = true; rlm@1: if(strPtr[0] == '$') rlm@1: strPtr++, forceHex = true; rlm@1: if(!forceHex) rlm@1: { rlm@1: const char* strSearchPtr = strPtr; rlm@1: while(*strSearchPtr) rlm@1: { rlm@1: int c = tolower(*strSearchPtr++); rlm@1: if(c >= 'a' && c <= 'f') rlm@1: forceHex = true; rlm@1: } rlm@1: } rlm@1: const char* formatString = forceHex ? "%X" : ((rs_t=='s') ? "%d" : "%u"); rlm@1: if(sscanf(strPtr, formatString, &rv) > 0) rlm@1: ok = true; rlm@1: if(negate) rlm@1: rv = -rv; rlm@1: } rlm@1: } rlm@1: rlm@1: success = ok; rlm@1: return rv; rlm@1: } rlm@1: rlm@1: rlm@1: bool Set_RS_Val() rlm@1: { rlm@1: BOOL success; rlm@1: rlm@1: // update rs_val rlm@1: switch(rs_c) rlm@1: { rlm@1: case 'r': rlm@1: default: rlm@1: rs_val = 0; rlm@1: break; rlm@1: case 's': rlm@1: rs_val = ReadControlInt(IDC_EDIT_COMPAREVALUE, rs_t == 'h', success); rlm@1: if(!success) rlm@1: return false; rlm@1: if((rs_type_size == 'b' && rs_t == 's' && (rs_val < -128 || rs_val > 127)) || rlm@1: (rs_type_size == 'b' && rs_t != 's' && (rs_val < 0 || rs_val > 255)) || rlm@1: (rs_type_size == 'w' && rs_t == 's' && (rs_val < -32768 || rs_val > 32767)) || rlm@1: (rs_type_size == 'w' && rs_t != 's' && (rs_val < 0 || rs_val > 65535))) rlm@1: return false; rlm@1: break; rlm@1: case 'a': rlm@1: rs_val = ReadControlInt(IDC_EDIT_COMPAREADDRESS, true, success); rlm@1: if(!success || rs_val < 0 || rs_val > 0x06040000) rlm@1: return false; rlm@1: break; rlm@1: case 'n': { rlm@1: rs_val = ReadControlInt(IDC_EDIT_COMPARECHANGES, false, success); rlm@1: if(!success || rs_val < 0 || rs_val > 0xFFFF) rlm@1: return false; rlm@1: } break; rlm@1: } rlm@1: rlm@1: // also update rs_param rlm@1: switch(rs_o) rlm@1: { rlm@1: default: rlm@1: rs_param = 0; rlm@1: break; rlm@1: case 'd': rlm@1: rs_param = ReadControlInt(IDC_EDIT_DIFFBY, false, success); rlm@1: if(!success) rlm@1: return false; rlm@1: if(rs_param < 0) rlm@1: rs_param = -rs_param; rlm@1: break; rlm@1: case '%': rlm@1: rs_param = ReadControlInt(IDC_EDIT_MODBY, false, success); rlm@1: if(!success || rs_param == 0) rlm@1: return false; rlm@1: break; rlm@1: } rlm@1: rlm@1: // validate that rs_param fits in the comparison data type rlm@1: { rlm@1: int appliedSize = rs_type_size; rlm@1: int appliedSign = rs_t; rlm@1: if(rs_c == 'n') rlm@1: appliedSize = 'w', appliedSign = 'u'; rlm@1: if(rs_c == 'a') rlm@1: appliedSize = 'd', appliedSign = 'u'; rlm@1: if((appliedSize == 'b' && appliedSize == 's' && (rs_param < -128 || rs_param > 127)) || rlm@1: (appliedSize == 'b' && appliedSize != 's' && (rs_param < 0 || rs_param > 255)) || rlm@1: (appliedSize == 'w' && appliedSize == 's' && (rs_param < -32768 || rs_param > 32767)) || rlm@1: (appliedSize == 'w' && appliedSize != 's' && (rs_param < 0 || rs_param > 65535))) rlm@1: return false; rlm@1: } rlm@1: rlm@1: return true; rlm@1: } rlm@1: rlm@1: bool IsSatisfied(int itemIndex) rlm@1: { rlm@1: if(!rs_val_valid) rlm@1: return true; rlm@1: int o = rs_o; rlm@1: switch (rs_c) rlm@1: { rlm@1: #undef DO_SEARCH_2 rlm@1: #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); rlm@1: case 'r': DO_SEARCH(CompareRelativeAtItem); break; rlm@1: case 's': DO_SEARCH(CompareSpecificAtItem); break; rlm@1: rlm@1: #undef DO_SEARCH_2 rlm@1: #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); rlm@1: case 'a': DO_SEARCH(CompareAddressAtItem); break; rlm@1: rlm@1: #undef DO_SEARCH_2 rlm@1: #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); rlm@1: case 'n': DO_SEARCH(CompareChangesAtItem); break; rlm@1: } rlm@1: return false; rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: unsigned int ReadValueAtSoftwareAddress(const unsigned char* address, unsigned int size) rlm@1: { rlm@1: unsigned int value = 0; rlm@1: if(address) rlm@1: { rlm@1: // assumes we're little-endian rlm@1: memcpy(&value, address, size); rlm@1: } rlm@1: return value; rlm@1: } rlm@1: void WriteValueAtSoftwareAddress(unsigned char* address, unsigned int value, unsigned int size) rlm@1: { rlm@1: if(address) rlm@1: { rlm@1: // assumes we're little-endian rlm@1: memcpy(address, &value, size); rlm@1: } rlm@1: } rlm@1: unsigned int ReadValueAtHardwareAddress(HWAddressType address, unsigned int size) rlm@1: { rlm@1: return ReadValueAtSoftwareAddress(HardwareToSoftwareAddress(address), size); rlm@1: } rlm@1: bool WriteValueAtHardwareAddress(HWAddressType address, unsigned int value, unsigned int size) rlm@1: { rlm@1: WriteValueAtSoftwareAddress(HardwareToSoftwareAddress(address), value, size); rlm@1: return true; rlm@1: } rlm@1: bool IsHardwareAddressValid(HWAddressType address) rlm@1: { rlm@1: return HardwareToSoftwareAddress(address) != NULL; rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: int ResultCount=0; rlm@1: bool AutoSearch=false; rlm@1: bool AutoSearchAutoRetry=false; rlm@1: LRESULT CALLBACK PromptWatchNameProc(HWND, UINT, WPARAM, LPARAM); rlm@1: void UpdatePossibilities(int rs_possible, int regions); rlm@1: rlm@1: rlm@1: void CompactAddrs() rlm@1: { rlm@1: int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; rlm@1: int prevResultCount = ResultCount; rlm@1: rlm@1: CalculateItemIndices(size); rlm@1: ResultCount = CALL_WITH_T_SIZE_TYPES_0(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign); rlm@1: rlm@1: UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); rlm@1: rlm@1: if(ResultCount != prevResultCount) rlm@1: ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount); rlm@1: } rlm@1: rlm@1: void soft_reset_address_info () rlm@1: { rlm@1: s_prevValuesNeedUpdate = false; rlm@1: ResetMemoryRegions(); rlm@1: if(!RamSearchHWnd) rlm@1: { rlm@1: EnterCriticalSection(&s_activeMemoryRegionsCS); rlm@1: s_activeMemoryRegions.clear(); rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: ResultCount = 0; rlm@1: } rlm@1: else rlm@1: { rlm@1: // force s_prevValues to be valid rlm@1: signal_new_frame(); rlm@1: s_prevValuesNeedUpdate = true; rlm@1: signal_new_frame(); rlm@1: } rlm@1: if(s_numChanges) rlm@1: memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE))); rlm@1: CompactAddrs(); rlm@1: } rlm@1: void reset_address_info () rlm@1: { rlm@1: SetRamSearchUndoType(RamSearchHWnd, 0); rlm@1: EnterCriticalSection(&s_activeMemoryRegionsCS); rlm@1: s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: if(s_prevValues) rlm@1: memcpy(s_prevValues, s_curValues, (sizeof(*s_prevValues)*(MAX_RAM_SIZE))); rlm@1: s_prevValuesNeedUpdate = false; rlm@1: ResetMemoryRegions(); rlm@1: if(!RamSearchHWnd) rlm@1: { rlm@1: EnterCriticalSection(&s_activeMemoryRegionsCS); rlm@1: s_activeMemoryRegions.clear(); rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: ResultCount = 0; rlm@1: } rlm@1: else rlm@1: { rlm@1: // force s_prevValues to be valid rlm@1: signal_new_frame(); rlm@1: s_prevValuesNeedUpdate = true; rlm@1: signal_new_frame(); rlm@1: } rlm@1: memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE))); rlm@1: CompactAddrs(); rlm@1: } rlm@1: rlm@1: void signal_new_frame () rlm@1: { rlm@1: EnterCriticalSection(&s_activeMemoryRegionsCS); rlm@1: CALL_WITH_T_SIZE_TYPES_0(UpdateRegionsT, rs_type_size, rs_t=='s', noMisalign); rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: bool RamSearchClosed = false; rlm@1: bool RamWatchClosed = false; rlm@1: rlm@1: void ResetResults() rlm@1: { rlm@1: reset_address_info(); rlm@1: ResultCount = 0; rlm@1: if (RamSearchHWnd) rlm@1: ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount); rlm@1: } rlm@1: void CloseRamWindows() //Close the Ram Search & Watch windows when rom closes rlm@1: { rlm@1: ResetWatches(); rlm@1: ResetResults(); rlm@1: if (RamSearchHWnd) rlm@1: { rlm@1: SendMessage(RamSearchHWnd,WM_CLOSE,NULL,NULL); rlm@1: RamSearchClosed = true; rlm@1: } rlm@1: if (RamWatchHWnd) rlm@1: { rlm@1: SendMessage(RamWatchHWnd,WM_CLOSE,NULL,NULL); rlm@1: RamWatchClosed = true; rlm@1: } rlm@1: } rlm@1: void ReopenRamWindows() //Reopen them when a new Rom is loaded rlm@1: { rlm@1: HWND hwnd = GetActiveWindow(); rlm@1: rlm@1: if (RamSearchClosed) rlm@1: { rlm@1: RamSearchClosed = false; rlm@1: if(!RamSearchHWnd) rlm@1: { rlm@1: reset_address_info(); rlm@1: LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); rlm@1: RamSearchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMSEARCH), hWnd, (DLGPROC) RamSearchProc); rlm@1: } rlm@1: else rlm@1: ::SetForegroundWindow(RamSearchHWnd); rlm@1: } rlm@1: if (RamWatchClosed || AutoRWLoad) rlm@1: { rlm@1: RamWatchClosed = false; rlm@1: if(!RamWatchHWnd) rlm@1: { rlm@1: if (AutoRWLoad) OpenRWRecentFile(0); rlm@1: LRESULT CALLBACK RamWatchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); rlm@1: RamWatchHWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_RAMWATCH), hWnd, (DLGPROC) RamWatchProc); rlm@1: } rlm@1: else rlm@1: ::SetForegroundWindow(RamWatchHWnd); rlm@1: } rlm@1: rlm@1: if (hwnd == hWnd && hwnd != GetActiveWindow()) rlm@1: SetActiveWindow(hWnd); // restore focus to the main window if it had it before rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: void RefreshRamListSelectedCountControlStatus(HWND hDlg) rlm@1: { rlm@1: int selCount = ListView_GetSelectedCount(GetDlgItem(hDlg,IDC_RAMLIST)); rlm@1: if(selCount != s_prevSelCount) rlm@1: { rlm@1: if(selCount < 2 || s_prevSelCount < 2) rlm@1: { rlm@1: EnableWindow(GetDlgItem(hDlg, IDC_C_WATCH), (WatchCount < MAX_WATCH_COUNT) ? TRUE : FALSE); rlm@1: EnableWindow(GetDlgItem(hDlg, IDC_C_ADDCHEAT), (selCount >= 1) ? TRUE : FALSE); rlm@1: EnableWindow(GetDlgItem(hDlg, IDC_C_ELIMINATE), (selCount >= 1) ? TRUE : FALSE); rlm@1: } rlm@1: s_prevSelCount = selCount; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: struct AddrRange rlm@1: { rlm@1: unsigned int addr; rlm@1: unsigned int size; rlm@1: unsigned int End() const { return addr + size; } rlm@1: AddrRange(unsigned int a, unsigned int s) : addr(a),size(s){} rlm@1: }; rlm@1: rlm@1: void signal_new_size () rlm@1: { rlm@1: HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); rlm@1: rlm@1: int oldSize = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2; rlm@1: int newSize = (rs_type_size=='b' || !noMisalign) ? 1 : 2; rlm@1: bool numberOfItemsChanged = (oldSize != newSize); rlm@1: rlm@1: unsigned int itemsPerPage = ListView_GetCountPerPage(lv); rlm@1: unsigned int oldTopIndex = ListView_GetTopIndex(lv); rlm@1: unsigned int oldSelectionIndex = ListView_GetSelectionMark(lv); rlm@1: unsigned int oldTopAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldTopIndex); rlm@1: unsigned int oldSelectionAddr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, oldSelectionIndex); rlm@1: rlm@1: std::vector selHardwareAddrs; rlm@1: if(numberOfItemsChanged) rlm@1: { rlm@1: // store selection ranges rlm@1: // unfortunately this can take a while if the user has a huge range of items selected rlm@1: systemSoundClearBuffer(); rlm@1: int selCount = ListView_GetSelectedCount(lv); rlm@1: int size = (rs_last_type_size=='b' || !rs_last_no_misalign) ? 1 : 2; rlm@1: int watchIndex = -1; rlm@1: for(int i = 0; i < selCount; ++i) rlm@1: { rlm@1: watchIndex = ListView_GetNextItem(lv, watchIndex, LVNI_SELECTED); rlm@1: int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_last_type_size,rs_t=='s',rs_last_no_misalign, watchIndex); rlm@1: if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End()) rlm@1: selHardwareAddrs.back().size += size; rlm@1: else if (!(noMisalign && oldSize < newSize && addr % newSize != 0)) rlm@1: selHardwareAddrs.push_back(AddrRange(addr,size)); rlm@1: } rlm@1: } rlm@1: rlm@1: CompactAddrs(); rlm@1: rlm@1: rs_last_type_size = rs_type_size; rlm@1: rs_last_no_misalign = noMisalign; rlm@1: rlm@1: if(numberOfItemsChanged) rlm@1: { rlm@1: // restore selection ranges rlm@1: unsigned int newTopIndex = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, oldTopAddr); rlm@1: unsigned int newBottomIndex = newTopIndex + itemsPerPage - 1; rlm@1: SendMessage(lv, WM_SETREDRAW, FALSE, 0); rlm@1: ListView_SetItemState(lv, -1, 0, LVIS_SELECTED|LVIS_FOCUSED); // deselect all rlm@1: for(unsigned int i = 0; i < selHardwareAddrs.size(); i++) rlm@1: { rlm@1: // calculate index ranges of this selection rlm@1: const AddrRange& range = selHardwareAddrs[i]; rlm@1: int selRangeTop = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, range.addr); rlm@1: int selRangeBottom = -1; rlm@1: for(int endAddr = range.End()-1; endAddr >= selRangeTop && selRangeBottom == -1; endAddr--) rlm@1: selRangeBottom = CALL_WITH_T_SIZE_TYPES_1(HardwareAddressToItemIndex, rs_type_size,rs_t=='s',noMisalign, endAddr); rlm@1: if(selRangeBottom == -1) rlm@1: selRangeBottom = selRangeTop; rlm@1: if(selRangeTop == -1) rlm@1: continue; rlm@1: rlm@1: // select the entire range rlm@1: for (int j = selRangeTop; j <= selRangeBottom; j++) rlm@1: { rlm@1: ListView_SetItemState(lv, j, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); rlm@1: } rlm@1: } rlm@1: rlm@1: // restore previous scroll position rlm@1: if(newBottomIndex != -1) rlm@1: ListView_EnsureVisible(lv, newBottomIndex, 0); rlm@1: if(newTopIndex != -1) rlm@1: ListView_EnsureVisible(lv, newTopIndex, 0); rlm@1: rlm@1: SendMessage(lv, WM_SETREDRAW, TRUE, 0); rlm@1: rlm@1: RefreshRamListSelectedCountControlStatus(RamSearchHWnd); rlm@1: rlm@1: EnableWindow(GetDlgItem(RamSearchHWnd,IDC_MISALIGN), rs_type_size != 'b'); rlm@1: } rlm@1: else rlm@1: { rlm@1: ListView_Update(lv, -1); rlm@1: } rlm@1: InvalidateRect(lv, NULL, TRUE); rlm@1: //SetFocus(lv); rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: LRESULT CustomDraw (LPARAM lParam) rlm@1: { rlm@1: LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; rlm@1: rlm@1: switch(lplvcd->nmcd.dwDrawStage) rlm@1: { rlm@1: case CDDS_PREPAINT : rlm@1: return CDRF_NOTIFYITEMDRAW; rlm@1: rlm@1: case CDDS_ITEMPREPAINT: rlm@1: { rlm@1: int rv = CDRF_DODEFAULT; rlm@1: rlm@1: if(lplvcd->nmcd.dwItemSpec % 2) rlm@1: { rlm@1: // alternate the background color slightly rlm@1: lplvcd->clrTextBk = RGB(248,248,255); rlm@1: rv = CDRF_NEWFONT; rlm@1: } rlm@1: rlm@1: if(!IsSatisfied(lplvcd->nmcd.dwItemSpec)) rlm@1: { rlm@1: // tint red any items that would be eliminated if a search were to run now rlm@1: lplvcd->clrText = RGB(192,64,64); rlm@1: rv = CDRF_NEWFONT; rlm@1: } rlm@1: rlm@1: return rv; rlm@1: } break; rlm@1: } rlm@1: return CDRF_DODEFAULT; rlm@1: } rlm@1: rlm@1: void Update_RAM_Search() //keeps RAM values up to date in the search and watch windows rlm@1: { rlm@1: if(disableRamSearchUpdate) rlm@1: return; rlm@1: rlm@1: int prevValuesNeededUpdate; rlm@1: if (AutoSearch && !ResultCount) rlm@1: { rlm@1: if(!AutoSearchAutoRetry) rlm@1: { rlm@1: systemSoundClearBuffer(); rlm@1: 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); rlm@1: if(answer == IDABORT) rlm@1: { rlm@1: SendDlgItemMessage(RamSearchHWnd, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0); rlm@1: SendMessage(RamSearchHWnd, WM_COMMAND, IDC_C_AUTOSEARCH, 0); rlm@1: } rlm@1: if(answer == IDIGNORE) rlm@1: AutoSearchAutoRetry = true; rlm@1: } rlm@1: reset_address_info(); rlm@1: prevValuesNeededUpdate = s_prevValuesNeedUpdate; rlm@1: } rlm@1: else rlm@1: { rlm@1: prevValuesNeededUpdate = s_prevValuesNeedUpdate; rlm@1: if (RamSearchHWnd) rlm@1: { rlm@1: // update active RAM values rlm@1: signal_new_frame(); rlm@1: } rlm@1: rlm@1: if (AutoSearch && ResultCount) rlm@1: { rlm@1: systemSoundClearBuffer(); rlm@1: if(!rs_val_valid) rlm@1: rs_val_valid = Set_RS_Val(); rlm@1: if(rs_val_valid) rlm@1: prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param); rlm@1: } rlm@1: } rlm@1: rlm@1: if(RamSearchHWnd) rlm@1: { rlm@1: HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); rlm@1: if(prevValuesNeededUpdate != s_prevValuesNeedUpdate) rlm@1: { rlm@1: // previous values got updated, refresh everything visible rlm@1: ListView_Update(lv, -1); rlm@1: } rlm@1: else rlm@1: { rlm@1: // refresh any visible parts of the listview box that changed rlm@1: static int changes[128]; rlm@1: int top = ListView_GetTopIndex(lv); rlm@1: int count = ListView_GetCountPerPage(lv); rlm@1: int start = -1; rlm@1: for(int i = top; i <= top+count; i++) rlm@1: { rlm@1: int changeNum = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, i); //s_numChanges[i]; rlm@1: int changed = changeNum != changes[i-top]; rlm@1: if(changed) rlm@1: changes[i-top] = changeNum; rlm@1: rlm@1: if(start == -1) rlm@1: { rlm@1: if(i != top+count && changed) rlm@1: { rlm@1: start = i; rlm@1: //somethingChanged = true; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if(i == top+count || !changed) rlm@1: { rlm@1: ListView_RedrawItems(lv, start, i-1); rlm@1: start = -1; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if(RamWatchHWnd) rlm@1: { rlm@1: Update_RAM_Watch(); rlm@1: } rlm@1: } rlm@1: rlm@1: static int rs_lastPercent = -1; rlm@1: inline void UpdateRamSearchProgressBar(int percent) rlm@1: { rlm@1: if(rs_lastPercent != percent) rlm@1: { rlm@1: rs_lastPercent = percent; rlm@1: UpdateRamSearchTitleBar(percent); rlm@1: } rlm@1: } rlm@1: rlm@1: static void SelectEditControl(int controlID) rlm@1: { rlm@1: HWND hEdit = GetDlgItem(RamSearchHWnd,controlID); rlm@1: SetFocus(hEdit); rlm@1: SendMessage(hEdit, EM_SETSEL, 0, -1); rlm@1: } rlm@1: rlm@1: static BOOL SelectingByKeyboard() rlm@1: { rlm@1: int a = GetKeyState(VK_LEFT); rlm@1: int b = GetKeyState(VK_RIGHT); rlm@1: int c = GetKeyState(VK_UP); rlm@1: int d = GetKeyState(VK_DOWN); // space and tab are intentionally omitted rlm@1: return (a | b | c | d) & 0x80; rlm@1: } rlm@1: rlm@1: rlm@1: LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) rlm@1: { rlm@1: static int watchIndex=0; rlm@1: rlm@1: switch(uMsg) rlm@1: { rlm@1: case WM_INITDIALOG: { rlm@1: RamSearchHWnd = hDlg; rlm@1: rlm@1: SetWindowPos(hDlg, NULL, regQueryDwordValue("ramSearchX", 0), regQueryDwordValue("ramSearchY", 0), NULL, NULL, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); rlm@1: switch(rs_o) rlm@1: { rlm@1: case '<': rlm@1: SendDlgItemMessage(hDlg, IDC_LESSTHAN, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case '>': rlm@1: SendDlgItemMessage(hDlg, IDC_MORETHAN, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 'l': rlm@1: SendDlgItemMessage(hDlg, IDC_NOMORETHAN, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 'm': rlm@1: SendDlgItemMessage(hDlg, IDC_NOLESSTHAN, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case '=': rlm@1: SendDlgItemMessage(hDlg, IDC_EQUALTO, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case '!': rlm@1: SendDlgItemMessage(hDlg, IDC_DIFFERENTFROM, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 'd': rlm@1: SendDlgItemMessage(hDlg, IDC_DIFFERENTBY, BM_SETCHECK, BST_CHECKED, 0); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true); rlm@1: break; rlm@1: case '%': rlm@1: SendDlgItemMessage(hDlg, IDC_MODULO, BM_SETCHECK, BST_CHECKED, 0); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true); rlm@1: break; rlm@1: } rlm@1: switch (rs_c) rlm@1: { rlm@1: case 'r': rlm@1: SendDlgItemMessage(hDlg, IDC_PREVIOUSVALUE, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 's': rlm@1: SendDlgItemMessage(hDlg, IDC_SPECIFICVALUE, BM_SETCHECK, BST_CHECKED, 0); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true); rlm@1: break; rlm@1: case 'a': rlm@1: SendDlgItemMessage(hDlg, IDC_SPECIFICADDRESS, BM_SETCHECK, BST_CHECKED, 0); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true); rlm@1: break; rlm@1: case 'n': rlm@1: SendDlgItemMessage(hDlg, IDC_NUMBEROFCHANGES, BM_SETCHECK, BST_CHECKED, 0); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true); rlm@1: break; rlm@1: } rlm@1: switch (rs_t) rlm@1: { rlm@1: case 's': rlm@1: SendDlgItemMessage(hDlg, IDC_SIGNED, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 'u': rlm@1: SendDlgItemMessage(hDlg, IDC_UNSIGNED, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 'h': rlm@1: SendDlgItemMessage(hDlg, IDC_HEX, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: } rlm@1: switch (rs_type_size) rlm@1: { rlm@1: case 'b': rlm@1: SendDlgItemMessage(hDlg, IDC_1_BYTE, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 'w': rlm@1: SendDlgItemMessage(hDlg, IDC_2_BYTES, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: case 'd': rlm@1: SendDlgItemMessage(hDlg, IDC_4_BYTES, BM_SETCHECK, BST_CHECKED, 0); rlm@1: break; rlm@1: } rlm@1: rlm@1: s_prevValuesNeedUpdate = true; rlm@1: rlm@1: SendDlgItemMessage(hDlg,IDC_C_AUTOSEARCH,BM_SETCHECK,AutoSearch?BST_CHECKED:BST_UNCHECKED,0); rlm@1: //const char* names[5] = {"Address","Value","Previous","Changes","Notes"}; rlm@1: //int widths[5] = {62,64,64,55,55}; rlm@1: const char* names[] = {"Address","Value","Previous","Changes"}; rlm@1: int widths[4] = {68,76,76,68}; rlm@1: if (!ResultCount) rlm@1: reset_address_info(); rlm@1: else rlm@1: { rlm@1: signal_new_frame(); rlm@1: CompactAddrs(); rlm@1: } rlm@1: void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths); rlm@1: init_list_box(GetDlgItem(hDlg,IDC_RAMLIST),names,4,widths); rlm@1: //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount); rlm@1: if (!noMisalign) SendDlgItemMessage(hDlg, IDC_MISALIGN, BM_SETCHECK, BST_CHECKED, 0); rlm@1: //if (littleEndian) SendDlgItemMessage(hDlg, IDC_ENDIAN, BM_SETCHECK, BST_CHECKED, 0); rlm@1: last_rs_possible = -1; rlm@1: rlm@1: s_prevSelCount = -1; rlm@1: RefreshRamListSelectedCountControlStatus(hDlg); rlm@1: rlm@1: // force misalign checkbox to refresh rlm@1: signal_new_size(); rlm@1: rlm@1: // force undo button to refresh rlm@1: int undoType = s_undoType; rlm@1: SetRamSearchUndoType(hDlg, -2); rlm@1: SetRamSearchUndoType(hDlg, undoType); rlm@1: rlm@1: // force possibility count to refresh rlm@1: last_rs_possible--; rlm@1: UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); rlm@1: rlm@1: rs_val_valid = Set_RS_Val(); rlm@1: rlm@1: ListView_SetCallbackMask(GetDlgItem(hDlg,IDC_RAMLIST), LVIS_FOCUSED|LVIS_SELECTED); rlm@1: rlm@1: return true; rlm@1: } break; rlm@1: rlm@1: case WM_NOTIFY: rlm@1: { rlm@1: LPNMHDR lP = (LPNMHDR) lParam; rlm@1: switch (lP->code) rlm@1: { rlm@1: case LVN_ITEMCHANGED: // selection changed event rlm@1: { rlm@1: NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)lP; rlm@1: if(pNMListView->uNewState & LVIS_FOCUSED || rlm@1: (pNMListView->uNewState ^ pNMListView->uOldState) & LVIS_SELECTED) rlm@1: { rlm@1: // disable buttons that we don't have the right number of selected items for rlm@1: RefreshRamListSelectedCountControlStatus(hDlg); rlm@1: } rlm@1: } break; rlm@1: rlm@1: case LVN_GETDISPINFO: rlm@1: { rlm@1: LV_DISPINFO *Item = (LV_DISPINFO *)lParam; rlm@1: Item->item.mask = LVIF_TEXT; rlm@1: Item->item.state = 0; rlm@1: Item->item.iImage = 0; rlm@1: const unsigned int iNum = Item->item.iItem; rlm@1: static char num[11]; rlm@1: switch (Item->item.iSubItem) rlm@1: { rlm@1: case 0: rlm@1: { rlm@1: int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); rlm@1: sprintf(num,"%08X",addr); rlm@1: Item->item.pszText = num; rlm@1: } return true; rlm@1: case 1: rlm@1: { rlm@1: int i = CALL_WITH_T_SIZE_TYPES_1(GetCurValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); rlm@1: const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X")); rlm@1: switch (rs_type_size) rlm@1: { rlm@1: case 'b': rlm@1: default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; rlm@1: case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; rlm@1: case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; rlm@1: } rlm@1: Item->item.pszText = num; rlm@1: } return true; rlm@1: case 2: rlm@1: { rlm@1: int i = CALL_WITH_T_SIZE_TYPES_1(GetPrevValueFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); rlm@1: const char* formatString = ((rs_t=='s') ? "%d" : (rs_t=='u') ? "%u" : (rs_type_size=='d' ? "%08X" : rs_type_size=='w' ? "%04X" : "%02X")); rlm@1: switch (rs_type_size) rlm@1: { rlm@1: case 'b': rlm@1: default: sprintf(num, formatString, rs_t=='s' ? (char)(i&0xff) : (unsigned char)(i&0xff)); break; rlm@1: case 'w': sprintf(num, formatString, rs_t=='s' ? (short)(i&0xffff) : (unsigned short)(i&0xffff)); break; rlm@1: case 'd': sprintf(num, formatString, rs_t=='s' ? (long)(i&0xffffffff) : (unsigned long)(i&0xffffffff)); break; rlm@1: } rlm@1: Item->item.pszText = num; rlm@1: } return true; rlm@1: case 3: rlm@1: { rlm@1: int i = CALL_WITH_T_SIZE_TYPES_1(GetNumChangesFromItemIndex, rs_type_size,rs_t=='s',noMisalign, iNum); rlm@1: sprintf(num,"%d",i); rlm@1: rlm@1: Item->item.pszText = num; rlm@1: } return true; rlm@1: //case 4: rlm@1: // Item->item.pszText = rsaddrs[rsresults[iNum].Index].comment ? rsaddrs[rsresults[iNum].Index].comment : ""; rlm@1: // return true; rlm@1: default: rlm@1: return false; rlm@1: } rlm@1: } rlm@1: rlm@1: case NM_CUSTOMDRAW: rlm@1: { rlm@1: SetWindowLong(hDlg, DWL_MSGRESULT, CustomDraw(lParam)); rlm@1: return TRUE; rlm@1: } break; rlm@1: rlm@1: //case LVN_ODCACHEHINT: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something. rlm@1: //{ rlm@1: // LPNMLVCACHEHINT lpCacheHint = (LPNMLVCACHEHINT)lParam; rlm@1: // return 0; rlm@1: //} rlm@1: //case LVN_ODFINDITEM: //Copied this bit from the MSDN virtual listbox code sample. Eventually it should probably do something. rlm@1: //{ rlm@1: // LPNMLVFINDITEM lpFindItem = (LPNMLVFINDITEM)lParam; rlm@1: // return 0; rlm@1: //} rlm@1: } rlm@1: } break; rlm@1: rlm@1: case WM_COMMAND: rlm@1: { rlm@1: int rv = false; rlm@1: switch(LOWORD(wParam)) rlm@1: { rlm@1: case IDC_SIGNED: rlm@1: rs_t='s'; rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: case IDC_UNSIGNED: rlm@1: rs_t='u'; rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: case IDC_HEX: rlm@1: rs_t='h'; rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: case IDC_1_BYTE: rlm@1: rs_type_size = 'b'; rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: case IDC_2_BYTES: rlm@1: rs_type_size = 'w'; rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: case IDC_4_BYTES: rlm@1: rs_type_size = 'd'; rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: case IDC_MISALIGN: rlm@1: noMisalign = !noMisalign; rlm@1: //CompactAddrs(); rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: // case IDC_ENDIAN: rlm@1: //// littleEndian = !littleEndian; rlm@1: //// signal_new_size(); rlm@1: // {rv = true; break;} rlm@1: case IDC_LESSTHAN: rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); rlm@1: rs_o = '<'; rlm@1: {rv = true; break;} rlm@1: case IDC_MORETHAN: rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); rlm@1: rs_o = '>'; rlm@1: {rv = true; break;} rlm@1: case IDC_NOMORETHAN: rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); rlm@1: rs_o = 'l'; rlm@1: {rv = true; break;} rlm@1: case IDC_NOLESSTHAN: rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); rlm@1: rs_o = 'm'; rlm@1: {rv = true; break;} rlm@1: case IDC_EQUALTO: rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); rlm@1: rs_o = '='; rlm@1: {rv = true; break;} rlm@1: case IDC_DIFFERENTFROM: rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); rlm@1: rs_o = '!'; rlm@1: {rv = true; break;} rlm@1: case IDC_DIFFERENTBY: rlm@1: { rlm@1: rs_o = 'd'; rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),true); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),false); rlm@1: if(!SelectingByKeyboard()) rlm@1: SelectEditControl(IDC_EDIT_DIFFBY); rlm@1: } {rv = true; break;} rlm@1: case IDC_MODULO: rlm@1: { rlm@1: rs_o = '%'; rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_DIFFBY),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_MODBY),true); rlm@1: if(!SelectingByKeyboard()) rlm@1: SelectEditControl(IDC_EDIT_MODBY); rlm@1: } {rv = true; break;} rlm@1: case IDC_PREVIOUSVALUE: rlm@1: rs_c='r'; rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); rlm@1: {rv = true; break;} rlm@1: case IDC_SPECIFICVALUE: rlm@1: { rlm@1: rs_c = 's'; rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),true); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); rlm@1: if(!SelectingByKeyboard()) rlm@1: SelectEditControl(IDC_EDIT_COMPAREVALUE); rlm@1: {rv = true; break;} rlm@1: } rlm@1: case IDC_SPECIFICADDRESS: rlm@1: { rlm@1: rs_c = 'a'; rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),true); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),false); rlm@1: if(!SelectingByKeyboard()) rlm@1: SelectEditControl(IDC_EDIT_COMPAREADDRESS); rlm@1: } {rv = true; break;} rlm@1: case IDC_NUMBEROFCHANGES: rlm@1: { rlm@1: rs_c = 'n'; rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPARECHANGES),true); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREVALUE),false); rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_EDIT_COMPAREADDRESS),false); rlm@1: if(!SelectingByKeyboard()) rlm@1: SelectEditControl(IDC_EDIT_COMPARECHANGES); rlm@1: } {rv = true; break;} rlm@1: case IDC_C_ADDCHEAT: rlm@1: { rlm@1: HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST); rlm@1: int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED); rlm@1: while (watchItemIndex >= 0) rlm@1: { rlm@1: unsigned long address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex); rlm@1: rlm@1: int sizeType = -1; rlm@1: if(rs_type_size == 'b') rlm@1: sizeType = 0; rlm@1: else if(rs_type_size == 'w') rlm@1: sizeType = 1; rlm@1: else if(rs_type_size == 'd') rlm@1: sizeType = 2; rlm@1: rlm@1: int numberType = -1; rlm@1: if(rs_t == 's') rlm@1: numberType = 0; rlm@1: else if(rs_t == 'u') rlm@1: numberType = 1; rlm@1: else if(rs_t == 'h') rlm@1: numberType = 2; rlm@1: rlm@1: if(systemCartridgeType == 0) rlm@1: { rlm@1: AddCheat dlg (address/*, hDlg*/); rlm@1: if(sizeType != -1) dlg.sizeType = sizeType; rlm@1: if(numberType != -1) dlg.numberType = numberType; rlm@1: dlg.DoModal(); rlm@1: } rlm@1: else rlm@1: { rlm@1: AddGBCheat dlg (address/*, hDlg*/); rlm@1: if(sizeType != -1) dlg.sizeType = sizeType; rlm@1: if(numberType != -1) dlg.numberType = numberType; rlm@1: dlg.DoModal(); rlm@1: } rlm@1: watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED); rlm@1: } rlm@1: } {rv = true; break;} rlm@1: case IDC_C_RESET: rlm@1: { rlm@1: RamSearchSaveUndoStateIfNotTooBig(RamSearchHWnd); rlm@1: int prevNumItems = last_rs_possible; rlm@1: rlm@1: soft_reset_address_info(); rlm@1: rlm@1: if(prevNumItems == last_rs_possible) rlm@1: SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo rlm@1: rlm@1: ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all rlm@1: //ListView_SetItemCount(GetDlgItem(hDlg,IDC_RAMLIST),ResultCount); rlm@1: ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0); rlm@1: RefreshRamListSelectedCountControlStatus(hDlg); rlm@1: {rv = true; break;} rlm@1: } rlm@1: case IDC_C_RESET_CHANGES: rlm@1: memset(s_numChanges, 0, (sizeof(*s_numChanges)*(MAX_RAM_SIZE))); rlm@1: ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); rlm@1: //SetRamSearchUndoType(hDlg, 0); rlm@1: {rv = true; break;} rlm@1: case IDC_C_UNDO: rlm@1: if(s_undoType>0) rlm@1: { rlm@1: systemSoundClearBuffer(); rlm@1: EnterCriticalSection(&s_activeMemoryRegionsCS); rlm@1: if(s_activeMemoryRegions.size() < tooManyRegionsForUndo) rlm@1: { rlm@1: MemoryList tempMemoryList = s_activeMemoryRegions; rlm@1: s_activeMemoryRegions = s_activeMemoryRegionsBackup; rlm@1: s_activeMemoryRegionsBackup = tempMemoryList; rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: SetRamSearchUndoType(hDlg, 3 - s_undoType); rlm@1: } rlm@1: else rlm@1: { rlm@1: s_activeMemoryRegions = s_activeMemoryRegionsBackup; rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: SetRamSearchUndoType(hDlg, -1); rlm@1: } rlm@1: CompactAddrs(); rlm@1: ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all rlm@1: ListView_SetSelectionMark(GetDlgItem(hDlg,IDC_RAMLIST), 0); rlm@1: RefreshRamListSelectedCountControlStatus(hDlg); rlm@1: } rlm@1: {rv = true; break;} rlm@1: case IDC_C_AUTOSEARCH: rlm@1: AutoSearch = SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_GETCHECK, 0, 0) != 0; rlm@1: AutoSearchAutoRetry = false; rlm@1: if (!AutoSearch) {rv = true; break;} rlm@1: case IDC_C_SEARCH: rlm@1: { rlm@1: systemSoundClearBuffer(); rlm@1: rlm@1: if(!rs_val_valid && !(rs_val_valid = Set_RS_Val())) rlm@1: goto invalid_field; rlm@1: rlm@1: if(ResultCount) rlm@1: { rlm@1: RamSearchSaveUndoStateIfNotTooBig(hDlg); rlm@1: rlm@1: prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param); rlm@1: rlm@1: RefreshRamListSelectedCountControlStatus(hDlg); rlm@1: } rlm@1: rlm@1: if(!ResultCount) rlm@1: { rlm@1: rlm@1: MessageBox(RamSearchHWnd,"Resetting search.","Out of results.",MB_OK|MB_ICONINFORMATION); rlm@1: soft_reset_address_info(); rlm@1: } rlm@1: rlm@1: {rv = true; break;} rlm@1: rlm@1: invalid_field: rlm@1: MessageBox(RamSearchHWnd,"Invalid or out-of-bound entered value.","Error",MB_OK|MB_ICONSTOP); rlm@1: if(AutoSearch) // stop autosearch if it just started rlm@1: { rlm@1: SendDlgItemMessage(hDlg, IDC_C_AUTOSEARCH, BM_SETCHECK, BST_UNCHECKED, 0); rlm@1: SendMessage(hDlg, WM_COMMAND, IDC_C_AUTOSEARCH, 0); rlm@1: } rlm@1: {rv = true; break;} rlm@1: } rlm@1: case IDC_C_WATCH: rlm@1: { rlm@1: HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST); rlm@1: int selCount = ListView_GetSelectedCount(ramListControl); rlm@1: rlm@1: bool inserted = false; rlm@1: int watchItemIndex = ListView_GetNextItem(ramListControl, -1, LVNI_SELECTED); rlm@1: while (watchItemIndex >= 0) rlm@1: { rlm@1: AddressWatcher tempWatch; rlm@1: tempWatch.Address = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchItemIndex); rlm@1: tempWatch.Size = rs_type_size; rlm@1: tempWatch.Type = rs_t; rlm@1: tempWatch.WrongEndian = 0; //Replace when I get little endian working rlm@1: tempWatch.comment = NULL; rlm@1: rlm@1: if (selCount == 1) rlm@1: inserted |= InsertWatch(tempWatch, hDlg); rlm@1: else rlm@1: inserted |= InsertWatch(tempWatch, ""); rlm@1: rlm@1: watchItemIndex = ListView_GetNextItem(ramListControl, watchItemIndex, LVNI_SELECTED); rlm@1: } rlm@1: // bring up the ram watch window if it's not already showing so the user knows where the watch went rlm@1: if(inserted && !RamWatchHWnd) rlm@1: SendMessage(hWnd, WM_COMMAND, ID_RAM_WATCH, 0); rlm@1: SetForegroundWindow(RamSearchHWnd); rlm@1: {rv = true; break;} rlm@1: } rlm@1: rlm@1: // eliminate all selected items rlm@1: case IDC_C_ELIMINATE: rlm@1: { rlm@1: RamSearchSaveUndoStateIfNotTooBig(hDlg); rlm@1: rlm@1: HWND ramListControl = GetDlgItem(hDlg,IDC_RAMLIST); rlm@1: int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; rlm@1: int selCount = ListView_GetSelectedCount(ramListControl); rlm@1: int watchIndex = -1; rlm@1: rlm@1: // time-saving trick #1: rlm@1: // condense the selected items into an array of address ranges rlm@1: std::vector selHardwareAddrs; rlm@1: for(int i = 0, j = 1024; i < selCount; ++i, --j) rlm@1: { rlm@1: watchIndex = ListView_GetNextItem(ramListControl, watchIndex, LVNI_SELECTED); rlm@1: int addr = CALL_WITH_T_SIZE_TYPES_1(GetHardwareAddressFromItemIndex, rs_type_size,rs_t=='s',noMisalign, watchIndex); rlm@1: if(!selHardwareAddrs.empty() && addr == selHardwareAddrs.back().End()) rlm@1: selHardwareAddrs.back().size += size; rlm@1: else rlm@1: selHardwareAddrs.push_back(AddrRange(addr,size)); rlm@1: rlm@1: if(!j) UpdateRamSearchProgressBar(i * 50 / selCount), j = 1024; rlm@1: } rlm@1: rlm@1: // now deactivate the ranges rlm@1: rlm@1: // time-saving trick #2: rlm@1: // take advantage of the fact that the listbox items must be in the same order as the regions rlm@1: MemoryList::iterator iter = s_activeMemoryRegions.begin(); rlm@1: int numHardwareAddrRanges = selHardwareAddrs.size(); rlm@1: for(int i = 0, j = 16; i < numHardwareAddrRanges; ++i, --j) rlm@1: { rlm@1: int addr = selHardwareAddrs[i].addr; rlm@1: int size = selHardwareAddrs[i].size; rlm@1: bool affected = false; rlm@1: while(iter != s_activeMemoryRegions.end()) rlm@1: { rlm@1: MemoryRegion& region = *iter; rlm@1: int affNow = DeactivateRegion(region, iter, addr, size); rlm@1: if(affNow) rlm@1: affected = true; rlm@1: else if(affected) rlm@1: break; rlm@1: if(affNow != 2) rlm@1: ++iter; rlm@1: } rlm@1: rlm@1: if(!j) UpdateRamSearchProgressBar(50 + (i * 50 / selCount)), j = 16; rlm@1: } rlm@1: UpdateRamSearchTitleBar(); rlm@1: rlm@1: // careful -- if the above two time-saving tricks aren't working, rlm@1: // the runtime can absolutely explode (seconds -> hours) when there are lots of regions rlm@1: rlm@1: ListView_SetItemState(ramListControl, -1, 0, LVIS_SELECTED); // deselect all rlm@1: signal_new_size(); rlm@1: {rv = true; break;} rlm@1: } rlm@1: //case IDOK: rlm@1: case IDCANCEL: rlm@1: RamSearchHWnd = NULL; rlm@1: /* if (theApp.pauseDuringCheatSearch) rlm@1: EndDialog(hDlg, true); // this should never be called on a modeless dialog rlm@1: else rlm@1: */ rlm@1: DestroyWindow(hDlg); rlm@1: {rv = true; break;} rlm@1: } rlm@1: rlm@1: // check refresh for comparison preview color update rlm@1: // also, update rs_val if needed rlm@1: bool needRefresh = false; rlm@1: switch(LOWORD(wParam)) rlm@1: { rlm@1: case IDC_LESSTHAN: rlm@1: case IDC_MORETHAN: rlm@1: case IDC_NOMORETHAN: rlm@1: case IDC_NOLESSTHAN: rlm@1: case IDC_EQUALTO: rlm@1: case IDC_DIFFERENTFROM: rlm@1: case IDC_DIFFERENTBY: rlm@1: case IDC_MODULO: rlm@1: case IDC_PREVIOUSVALUE: rlm@1: case IDC_SPECIFICVALUE: rlm@1: case IDC_SPECIFICADDRESS: rlm@1: case IDC_NUMBEROFCHANGES: rlm@1: case IDC_SIGNED: rlm@1: case IDC_UNSIGNED: rlm@1: case IDC_HEX: rlm@1: rs_val_valid = Set_RS_Val(); rlm@1: needRefresh = true; rlm@1: break; rlm@1: case IDC_EDIT_COMPAREVALUE: rlm@1: case IDC_EDIT_COMPAREADDRESS: rlm@1: case IDC_EDIT_COMPARECHANGES: rlm@1: case IDC_EDIT_DIFFBY: rlm@1: case IDC_EDIT_MODBY: rlm@1: if(HIWORD(wParam) == EN_CHANGE) rlm@1: { rlm@1: rs_val_valid = Set_RS_Val(); rlm@1: needRefresh = true; rlm@1: } rlm@1: break; rlm@1: } rlm@1: if(needRefresh) rlm@1: ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); rlm@1: rlm@1: rlm@1: return rv; rlm@1: } break; rlm@1: rlm@1: case WM_CLOSE: rlm@1: RECT r; rlm@1: GetWindowRect(hDlg, &r); rlm@1: regSetDwordValue("ramSearchX", r.left); rlm@1: regSetDwordValue("ramSearchY", r.top); rlm@1: SendMessage(RamSearchHWnd, WM_DESTROY, 0, 0); rlm@1: break; rlm@1: case WM_DESTROY: rlm@1: RamSearchHWnd = NULL; rlm@1: // theApp.modelessCheatDialogIsOpen = false; rlm@1: // return true; rlm@1: break; rlm@1: } rlm@1: rlm@1: return false; rlm@1: } rlm@1: rlm@1: void UpdateRamSearchTitleBar(int percent) rlm@1: { rlm@1: #define HEADER_STR " RAM Search - " rlm@1: #define PROGRESS_STR " %d%% ... " rlm@1: #define STATUS_STR "%d Possibilit%s (%d Region%s)" rlm@1: rlm@1: int poss = last_rs_possible; rlm@1: int regions = last_rs_regions; rlm@1: if(poss <= 0) rlm@1: strcpy(Str_Tmp," RAM Search"); rlm@1: else if(percent <= 0) rlm@1: sprintf(Str_Tmp, HEADER_STR STATUS_STR, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); rlm@1: else rlm@1: sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); rlm@1: SetWindowText(RamSearchHWnd, Str_Tmp); rlm@1: } rlm@1: rlm@1: void UpdatePossibilities(int rs_possible, int regions) rlm@1: { rlm@1: if(rs_possible != last_rs_possible) rlm@1: { rlm@1: last_rs_possible = rs_possible; rlm@1: last_rs_regions = regions; rlm@1: UpdateRamSearchTitleBar(); rlm@1: } rlm@1: } rlm@1: rlm@1: void SetRamSearchUndoType(HWND hDlg, int type) rlm@1: { rlm@1: if(s_undoType != type) rlm@1: { rlm@1: if((s_undoType!=2 && s_undoType!=-1)!=(type!=2 && type!=-1)) rlm@1: SendDlgItemMessage(hDlg,IDC_C_UNDO,WM_SETTEXT,0,(LPARAM)((type == 2 || type == -1) ? "Redo" : "Undo")); rlm@1: if((s_undoType>0)!=(type>0)) rlm@1: EnableWindow(GetDlgItem(hDlg,IDC_C_UNDO),type>0); rlm@1: s_undoType = type; rlm@1: } rlm@1: } rlm@1: rlm@1: void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg) rlm@1: { rlm@1: EnterCriticalSection(&s_activeMemoryRegionsCS); rlm@1: if(s_activeMemoryRegions.size() < tooManyRegionsForUndo) rlm@1: { rlm@1: s_activeMemoryRegionsBackup = s_activeMemoryRegions; rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: SetRamSearchUndoType(hDlg, 1); rlm@1: } rlm@1: else rlm@1: { rlm@1: LeaveCriticalSection(&s_activeMemoryRegionsCS); rlm@1: SetRamSearchUndoType(hDlg, 0); rlm@1: } rlm@1: } rlm@1: rlm@1: struct InitRamSearch rlm@1: { rlm@1: InitRamSearch() rlm@1: { rlm@1: InitializeCriticalSection(&s_activeMemoryRegionsCS); rlm@1: } rlm@1: ~InitRamSearch() rlm@1: { rlm@1: DeleteCriticalSection(&s_activeMemoryRegionsCS); rlm@1: } rlm@1: } initRamSearch; rlm@1: rlm@1: rlm@1: void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths) //initializes the ram search and/or ram watch listbox rlm@1: { rlm@1: LVCOLUMN Col; rlm@1: Col.mask = LVCF_FMT | LVCF_ORDER | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH; rlm@1: Col.fmt = LVCFMT_CENTER; rlm@1: for (int i = 0; i < numColumns; i++) rlm@1: { rlm@1: Col.iOrder = i; rlm@1: Col.iSubItem = i; rlm@1: Col.pszText = (LPSTR)(Strs[i]); rlm@1: Col.cx = columnWidths[i]; rlm@1: ListView_InsertColumn(Box,i,&Col); rlm@1: } rlm@1: rlm@1: ListView_SetExtendedListViewStyle(Box, LVS_EX_FULLROWSELECT); rlm@1: }