Mercurial > vba-clojure
comparison src/win32/ram_search.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
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 to | |
5 // update every single value in RAM every single frame, and | |
6 // 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 address | |
10 // to one entry per contiguous range of uneliminated addresses | |
11 // which references uniform pools of per-address properties. | |
12 // - This saves time when there are many items because | |
13 // 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 because | |
15 // it ensures that no time is wasted in iterating through | |
16 // addresses that have already been eliminated from the search. | |
17 // | |
18 // The worst-case scenario is when every other item has been | |
19 // eliminated from the search, maximizing the number of regions. | |
20 // This implementation manages to handle even that pathological case | |
21 // 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 regions | |
23 // is somewhat horrendous, but it seems reasonable to have poor worst-case speed | |
24 // 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) | |
26 | |
27 | |
28 #ifdef _WIN32 | |
29 #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 #else | |
39 #include "stdint.h" | |
40 #endif | |
41 #include <cassert> | |
42 #include <list> | |
43 #include <vector> | |
44 | |
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" | |
51 | |
52 static inline u8* HardwareToSoftwareAddress(HWAddressType address) | |
53 { | |
54 if(!emulating) | |
55 return NULL; | |
56 | |
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 // GBA | |
63 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 else | |
69 { | |
70 // GB | |
71 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 } | |
80 | |
81 | |
82 struct MemoryRegion | |
83 { | |
84 HWAddressType hardwareAddress; // hardware address of the start of this region | |
85 unsigned int size; // number of bytes to the end of this region | |
86 unsigned char* softwareAddress; // pointer to the start of the live emulator source values for this region | |
87 | |
88 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 false | |
90 }; | |
91 | |
92 int MAX_RAM_SIZE = 0; | |
93 static unsigned char* s_prevValues = 0; // values at last search or reset | |
94 static unsigned char* s_curValues = 0; // values at last frame update | |
95 static unsigned short* s_numChanges = 0; // number of changes of the item starting at this virtual index address | |
96 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 | |
97 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 | |
98 static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled | |
99 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 | |
100 static int s_prevSelCount = -1; | |
101 | |
102 HWND RamSearchHWnd; | |
103 #define hWnd AfxGetMainWnd()->GetSafeHwnd() | |
104 #define hInst AfxGetInstanceHandle() | |
105 static char Str_Tmp [1024]; | |
106 | |
107 int disableRamSearchUpdate = false; | |
108 | |
109 | |
110 | |
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}; | |
117 | |
118 // list of contiguous uneliminated memory regions | |
119 typedef std::list<MemoryRegion> MemoryList; | |
120 static MemoryList s_activeMemoryRegions; | |
121 static CRITICAL_SECTION s_activeMemoryRegionsCS; | |
122 | |
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 redo | |
126 | |
127 void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg); | |
128 static const int tooManyRegionsForUndo = 10000; | |
129 | |
130 void ResetMemoryRegions() | |
131 { | |
132 systemSoundClearBuffer(); | |
133 EnterCriticalSection(&s_activeMemoryRegionsCS); | |
134 | |
135 s_activeMemoryRegions.clear(); | |
136 | |
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 region | |
149 // 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 else | |
162 { | |
163 hwRegionStart += region.size; | |
164 regionStart += region.size; | |
165 } | |
166 break; | |
167 } | |
168 } | |
169 | |
170 // don't include ROM in our RAM search (it's too huge) | |
171 if(regionStart == rom || regionStart == gbRom) | |
172 discard = true; | |
173 | |
174 // create the region | |
175 if(!discard) | |
176 { | |
177 MemoryRegion region = { hwRegionStart, regionSearchGranularity + (regionEnd - regionStart), regionStart }; | |
178 s_activeMemoryRegions.push_back(region); | |
179 } | |
180 | |
181 hwRegionStart = 0; | |
182 regionStart = NULL; | |
183 regionEnd = NULL; | |
184 } | |
185 if(swAddr) | |
186 { | |
187 if(regionStart) | |
188 { | |
189 // continue region | |
190 regionEnd = swAddr; | |
191 } | |
192 else | |
193 { | |
194 // start new region | |
195 hwRegionStart = addr; | |
196 regionStart = swAddr; | |
197 regionEnd = swAddr; | |
198 } | |
199 } | |
200 } | |
201 | |
202 | |
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); | |
212 | |
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)); | |
217 | |
218 s_curValues = (unsigned char*)realloc(s_curValues, sizeof(char)*(nextVirtualIndex+4)); | |
219 memset(s_curValues, 0, sizeof(char)*(nextVirtualIndex+4)); | |
220 | |
221 s_numChanges = (unsigned short*)realloc(s_numChanges, sizeof(short)*(nextVirtualIndex+4)); | |
222 memset(s_numChanges, 0, sizeof(short)*(nextVirtualIndex+4)); | |
223 | |
224 s_itemIndexToRegionPointer = (MemoryRegion**)realloc(s_itemIndexToRegionPointer, sizeof(MemoryRegion*)*(nextVirtualIndex+4)); | |
225 memset(s_itemIndexToRegionPointer, 0, sizeof(MemoryRegion*)*(nextVirtualIndex+4)); | |
226 | |
227 MAX_RAM_SIZE = nextVirtualIndex; | |
228 } | |
229 LeaveCriticalSection(&s_activeMemoryRegionsCS); | |
230 } | |
231 | |
232 // eliminates a range of hardware addresses from the search results | |
233 // returns 2 if it changed the region and moved the iterator to another region | |
234 // returns 1 if it changed the region but didn't move the iterator | |
235 // returns 0 if it had no effect | |
236 // 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 cache | |
238 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 unaffected | |
243 return 0; | |
244 } | |
245 else if(hardwareAddress > region.hardwareAddress && hardwareAddress + size >= region.hardwareAddress + region.size) | |
246 { | |
247 // erase end of region | |
248 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 region | |
254 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 region | |
264 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 region | |
271 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 } | |
279 | |
280 /* | |
281 // eliminates a range of hardware addresses from the search results | |
282 // this is a simpler but usually slower interface for the above function | |
283 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 */ | |
293 | |
294 struct AutoCritSect | |
295 { | |
296 AutoCritSect(CRITICAL_SECTION* cs) : m_cs(cs) { EnterCriticalSection(m_cs); } | |
297 ~AutoCritSect() { LeaveCriticalSection(m_cs); } | |
298 CRITICAL_SECTION* m_cs; | |
299 }; | |
300 | |
301 // warning: can be slow | |
302 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 } | |
319 | |
320 template<typename stepType, typename compareType> | |
321 void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr) | |
322 { | |
323 //if(GetAsyncKeyState(VK_SHIFT) & 0x8000) // speed hack | |
324 // return; | |
325 | |
326 if(s_prevValuesNeedUpdate) | |
327 memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); | |
328 | |
329 unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); | |
330 | |
331 | |
332 unsigned char* sourceAddr = region.softwareAddress - region.virtualIndex; | |
333 | |
334 unsigned int indexStart = region.virtualIndex + startSkipSize; | |
335 unsigned int indexEnd = region.virtualIndex + region.size; | |
336 | |
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 changed | |
342 { | |
343 s_curValues[i] = sourceAddr[i]; // update value | |
344 //if(s_numChanges[i] != 0xFFFF) | |
345 s_numChanges[i]++; // increase change count | |
346 } | |
347 } | |
348 } | |
349 else // it's more complicated for non-byte sizes because: | |
350 { // - more than one byte can affect a given change count entry | |
351 // - when more than one of those bytes changes simultaneously the entry's change count should only increase by 1 | |
352 // - a few of those bytes can be outside the region | |
353 | |
354 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 } | |
365 | |
366 unsigned int nextValidChange [sizeof(compareType)]; | |
367 for(unsigned int i = 0; i < sizeof(compareType); i++) | |
368 nextValidChange[i] = indexStart + i; | |
369 | |
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 changed | |
373 { | |
374 if(i < lastIndexToCopy) | |
375 s_curValues[i] = sourceAddr[i]; // update value | |
376 for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte | |
377 { | |
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 entry | |
382 { | |
383 //if(s_numChanges[i-k] != 0xFFFF) | |
384 s_numChanges[i-k]++; // increase the change count for this entry | |
385 nextValidChange[m] = i-k+sizeof(compareType); // and remember not to increase it again | |
386 } | |
387 } | |
388 } | |
389 } | |
390 } | |
391 } | |
392 | |
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; | |
401 | |
402 UpdateRegionT<stepType, compareType>(region, nextRegion); | |
403 } | |
404 | |
405 s_prevValuesNeedUpdate = false; | |
406 } | |
407 | |
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; | |
416 | |
417 if(s_itemIndicesInvalid) | |
418 CalculateItemIndices(sizeof(stepType)); | |
419 | |
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 1 | |
424 { | |
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 } | |
435 | |
436 // returns information about the item in the form of a "fake" region | |
437 // that has the item in it and nothing else | |
438 template<typename stepType, typename compareType> | |
439 void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegion) | |
440 { | |
441 if(s_itemIndicesInvalid) | |
442 CalculateItemIndices(sizeof(stepType)); | |
443 | |
444 if(itemIndex >= s_maxItemIndex) | |
445 { | |
446 memset(&virtualRegion, 0, sizeof(MemoryRegion)); | |
447 return; | |
448 } | |
449 | |
450 const MemoryRegion* regionPtr = s_itemIndexToRegionPointer[itemIndex]; | |
451 const MemoryRegion& region = *regionPtr; | |
452 | |
453 int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType); | |
454 int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); | |
455 bytesWithinRegion += startSkipSize; | |
456 | |
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 } | |
464 | |
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 } | |
472 | |
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; } | |
480 | |
481 | |
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 } | |
503 | |
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 } | |
529 | |
530 // this one might be unreliable, haven't used it much | |
531 template<typename stepType, typename compareType> | |
532 unsigned int HardwareAddressToItemIndex(HWAddressType hardwareAddress) | |
533 { | |
534 if(s_itemIndicesInvalid) | |
535 CalculateItemIndices(sizeof(stepType)); | |
536 | |
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 } | |
546 | |
547 return -1; | |
548 } | |
549 | |
550 | |
551 | |
552 // workaround for MSVC 7 that doesn't support varadic C99 macros | |
553 #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>()) | |
575 | |
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)) | |
598 | |
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)) | |
621 | |
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)) | |
644 | |
645 // version that takes a forced comparison type | |
646 #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)) | |
658 | |
659 // version that takes a forced comparison type | |
660 #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)) | |
672 | |
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; } | |
682 | |
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 } | |
756 | |
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; | |
766 | |
767 void prune(char c,char o,char t,int v,int p) | |
768 { | |
769 // repetition-reducing macros | |
770 #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 } | |
783 | |
784 // perform the search, eliminating nonmatching values | |
785 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; | |
790 | |
791 #undef DO_SEARCH_2 | |
792 #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; | |
794 | |
795 #undef DO_SEARCH_2 | |
796 #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; | |
798 | |
799 default: assert(!"Invalid search comparison type."); break; | |
800 } | |
801 | |
802 s_prevValuesNeedUpdate = true; | |
803 | |
804 int prevNumItems = last_rs_possible; | |
805 | |
806 CompactAddrs(); | |
807 | |
808 if(prevNumItems == last_rs_possible) | |
809 { | |
810 SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo | |
811 } | |
812 } | |
813 | |
814 | |
815 | |
816 | |
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 } | |
837 | |
838 int ReadControlInt(int controlID, bool forceHex, BOOL& success) | |
839 { | |
840 int rv = 0; | |
841 BOOL ok = false; | |
842 | |
843 if(!forceHex) | |
844 { | |
845 rv = GetDlgItemInt(RamSearchHWnd,controlID,&ok,(rs_t == 's')); | |
846 } | |
847 | |
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 } | |
880 | |
881 success = ok; | |
882 return rv; | |
883 } | |
884 | |
885 | |
886 bool Set_RS_Val() | |
887 { | |
888 BOOL success; | |
889 | |
890 // update rs_val | |
891 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 } | |
918 | |
919 // also update rs_param | |
920 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 } | |
938 | |
939 // validate that rs_param fits in the comparison data type | |
940 { | |
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 } | |
953 | |
954 return true; | |
955 } | |
956 | |
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_2 | |
965 #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; | |
968 | |
969 #undef DO_SEARCH_2 | |
970 #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; | |
972 | |
973 #undef DO_SEARCH_2 | |
974 #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 } | |
979 | |
980 | |
981 | |
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-endian | |
988 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-endian | |
997 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 } | |
1013 | |
1014 | |
1015 | |
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); | |
1021 | |
1022 | |
1023 void CompactAddrs() | |
1024 { | |
1025 int size = (rs_type_size=='b' || !noMisalign) ? 1 : 2; | |
1026 int prevResultCount = ResultCount; | |
1027 | |
1028 CalculateItemIndices(size); | |
1029 ResultCount = CALL_WITH_T_SIZE_TYPES_0(CountRegionItemsT, rs_type_size,rs_t=='s',noMisalign); | |
1030 | |
1031 UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); | |
1032 | |
1033 if(ResultCount != prevResultCount) | |
1034 ListView_SetItemCount(GetDlgItem(RamSearchHWnd,IDC_RAMLIST),ResultCount); | |
1035 } | |
1036 | |
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 else | |
1049 { | |
1050 // force s_prevValues to be valid | |
1051 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 undo | |
1064 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 else | |
1077 { | |
1078 // force s_prevValues to be valid | |
1079 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 } | |
1086 | |
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 } | |
1093 | |
1094 | |
1095 | |
1096 | |
1097 | |
1098 bool RamSearchClosed = false; | |
1099 bool RamWatchClosed = false; | |
1100 | |
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 closes | |
1109 { | |
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 loaded | |
1124 { | |
1125 HWND hwnd = GetActiveWindow(); | |
1126 | |
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 else | |
1137 ::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 else | |
1149 ::SetForegroundWindow(RamWatchHWnd); | |
1150 } | |
1151 | |
1152 if (hwnd == hWnd && hwnd != GetActiveWindow()) | |
1153 SetActiveWindow(hWnd); // restore focus to the main window if it had it before | |
1154 } | |
1155 | |
1156 | |
1157 | |
1158 | |
1159 | |
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 } | |
1174 | |
1175 | |
1176 | |
1177 | |
1178 struct AddrRange | |
1179 { | |
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 }; | |
1185 | |
1186 void signal_new_size () | |
1187 { | |
1188 HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); | |
1189 | |
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); | |
1193 | |
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); | |
1199 | |
1200 std::vector<AddrRange> selHardwareAddrs; | |
1201 if(numberOfItemsChanged) | |
1202 { | |
1203 // store selection ranges | |
1204 // unfortunately this can take a while if the user has a huge range of items selected | |
1205 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 } | |
1219 | |
1220 CompactAddrs(); | |
1221 | |
1222 rs_last_type_size = rs_type_size; | |
1223 rs_last_no_misalign = noMisalign; | |
1224 | |
1225 if(numberOfItemsChanged) | |
1226 { | |
1227 // restore selection ranges | |
1228 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 all | |
1232 for(unsigned int i = 0; i < selHardwareAddrs.size(); i++) | |
1233 { | |
1234 // calculate index ranges of this selection | |
1235 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; | |
1244 | |
1245 // select the entire range | |
1246 for (int j = selRangeTop; j <= selRangeBottom; j++) | |
1247 { | |
1248 ListView_SetItemState(lv, j, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); | |
1249 } | |
1250 } | |
1251 | |
1252 // restore previous scroll position | |
1253 if(newBottomIndex != -1) | |
1254 ListView_EnsureVisible(lv, newBottomIndex, 0); | |
1255 if(newTopIndex != -1) | |
1256 ListView_EnsureVisible(lv, newTopIndex, 0); | |
1257 | |
1258 SendMessage(lv, WM_SETREDRAW, TRUE, 0); | |
1259 | |
1260 RefreshRamListSelectedCountControlStatus(RamSearchHWnd); | |
1261 | |
1262 EnableWindow(GetDlgItem(RamSearchHWnd,IDC_MISALIGN), rs_type_size != 'b'); | |
1263 } | |
1264 else | |
1265 { | |
1266 ListView_Update(lv, -1); | |
1267 } | |
1268 InvalidateRect(lv, NULL, TRUE); | |
1269 //SetFocus(lv); | |
1270 } | |
1271 | |
1272 | |
1273 | |
1274 | |
1275 LRESULT CustomDraw (LPARAM lParam) | |
1276 { | |
1277 LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; | |
1278 | |
1279 switch(lplvcd->nmcd.dwDrawStage) | |
1280 { | |
1281 case CDDS_PREPAINT : | |
1282 return CDRF_NOTIFYITEMDRAW; | |
1283 | |
1284 case CDDS_ITEMPREPAINT: | |
1285 { | |
1286 int rv = CDRF_DODEFAULT; | |
1287 | |
1288 if(lplvcd->nmcd.dwItemSpec % 2) | |
1289 { | |
1290 // alternate the background color slightly | |
1291 lplvcd->clrTextBk = RGB(248,248,255); | |
1292 rv = CDRF_NEWFONT; | |
1293 } | |
1294 | |
1295 if(!IsSatisfied(lplvcd->nmcd.dwItemSpec)) | |
1296 { | |
1297 // tint red any items that would be eliminated if a search were to run now | |
1298 lplvcd->clrText = RGB(192,64,64); | |
1299 rv = CDRF_NEWFONT; | |
1300 } | |
1301 | |
1302 return rv; | |
1303 } break; | |
1304 } | |
1305 return CDRF_DODEFAULT; | |
1306 } | |
1307 | |
1308 void Update_RAM_Search() //keeps RAM values up to date in the search and watch windows | |
1309 { | |
1310 if(disableRamSearchUpdate) | |
1311 return; | |
1312 | |
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 else | |
1332 { | |
1333 prevValuesNeededUpdate = s_prevValuesNeedUpdate; | |
1334 if (RamSearchHWnd) | |
1335 { | |
1336 // update active RAM values | |
1337 signal_new_frame(); | |
1338 } | |
1339 | |
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 } | |
1349 | |
1350 if(RamSearchHWnd) | |
1351 { | |
1352 HWND lv = GetDlgItem(RamSearchHWnd,IDC_RAMLIST); | |
1353 if(prevValuesNeededUpdate != s_prevValuesNeedUpdate) | |
1354 { | |
1355 // previous values got updated, refresh everything visible | |
1356 ListView_Update(lv, -1); | |
1357 } | |
1358 else | |
1359 { | |
1360 // refresh any visible parts of the listview box that changed | |
1361 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; | |
1371 | |
1372 if(start == -1) | |
1373 { | |
1374 if(i != top+count && changed) | |
1375 { | |
1376 start = i; | |
1377 //somethingChanged = true; | |
1378 } | |
1379 } | |
1380 else | |
1381 { | |
1382 if(i == top+count || !changed) | |
1383 { | |
1384 ListView_RedrawItems(lv, start, i-1); | |
1385 start = -1; | |
1386 } | |
1387 } | |
1388 } | |
1389 } | |
1390 } | |
1391 | |
1392 if(RamWatchHWnd) | |
1393 { | |
1394 Update_RAM_Watch(); | |
1395 } | |
1396 } | |
1397 | |
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 } | |
1407 | |
1408 static void SelectEditControl(int controlID) | |
1409 { | |
1410 HWND hEdit = GetDlgItem(RamSearchHWnd,controlID); | |
1411 SetFocus(hEdit); | |
1412 SendMessage(hEdit, EM_SETSEL, 0, -1); | |
1413 } | |
1414 | |
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 omitted | |
1421 return (a | b | c | d) & 0x80; | |
1422 } | |
1423 | |
1424 | |
1425 LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) | |
1426 { | |
1427 static int watchIndex=0; | |
1428 | |
1429 switch(uMsg) | |
1430 { | |
1431 case WM_INITDIALOG: { | |
1432 RamSearchHWnd = hDlg; | |
1433 | |
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 } | |
1506 | |
1507 s_prevValuesNeedUpdate = true; | |
1508 | |
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 else | |
1517 { | |
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; | |
1527 | |
1528 s_prevSelCount = -1; | |
1529 RefreshRamListSelectedCountControlStatus(hDlg); | |
1530 | |
1531 // force misalign checkbox to refresh | |
1532 signal_new_size(); | |
1533 | |
1534 // force undo button to refresh | |
1535 int undoType = s_undoType; | |
1536 SetRamSearchUndoType(hDlg, -2); | |
1537 SetRamSearchUndoType(hDlg, undoType); | |
1538 | |
1539 // force possibility count to refresh | |
1540 last_rs_possible--; | |
1541 UpdatePossibilities(ResultCount, (int)s_activeMemoryRegions.size()); | |
1542 | |
1543 rs_val_valid = Set_RS_Val(); | |
1544 | |
1545 ListView_SetCallbackMask(GetDlgItem(hDlg,IDC_RAMLIST), LVIS_FOCUSED|LVIS_SELECTED); | |
1546 | |
1547 return true; | |
1548 } break; | |
1549 | |
1550 case WM_NOTIFY: | |
1551 { | |
1552 LPNMHDR lP = (LPNMHDR) lParam; | |
1553 switch (lP->code) | |
1554 { | |
1555 case LVN_ITEMCHANGED: // selection changed event | |
1556 { | |
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 for | |
1562 RefreshRamListSelectedCountControlStatus(hDlg); | |
1563 } | |
1564 } break; | |
1565 | |
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); | |
1612 | |
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 } | |
1622 | |
1623 case NM_CUSTOMDRAW: | |
1624 { | |
1625 SetWindowLong(hDlg, DWL_MSGRESULT, CustomDraw(lParam)); | |
1626 return TRUE; | |
1627 } break; | |
1628 | |
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; | |
1641 | |
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); | |
1767 | |
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; | |
1775 | |
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; | |
1783 | |
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 else | |
1792 { | |
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; | |
1805 | |
1806 soft_reset_address_info(); | |
1807 | |
1808 if(prevNumItems == last_rs_possible) | |
1809 SetRamSearchUndoType(RamSearchHWnd, 0); // nothing to undo | |
1810 | |
1811 ListView_SetItemState(GetDlgItem(hDlg,IDC_RAMLIST), -1, 0, LVIS_SELECTED); // deselect all | |
1812 //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 else | |
1836 { | |
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 all | |
1843 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(); | |
1854 | |
1855 if(!rs_val_valid && !(rs_val_valid = Set_RS_Val())) | |
1856 goto invalid_field; | |
1857 | |
1858 if(ResultCount) | |
1859 { | |
1860 RamSearchSaveUndoStateIfNotTooBig(hDlg); | |
1861 | |
1862 prune(rs_c,rs_o,rs_t=='s',rs_val,rs_param); | |
1863 | |
1864 RefreshRamListSelectedCountControlStatus(hDlg); | |
1865 } | |
1866 | |
1867 if(!ResultCount) | |
1868 { | |
1869 | |
1870 MessageBox(RamSearchHWnd,"Resetting search.","Out of results.",MB_OK|MB_ICONINFORMATION); | |
1871 soft_reset_address_info(); | |
1872 } | |
1873 | |
1874 {rv = true; break;} | |
1875 | |
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 started | |
1879 { | |
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); | |
1889 | |
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 working | |
1899 tempWatch.comment = NULL; | |
1900 | |
1901 if (selCount == 1) | |
1902 inserted |= InsertWatch(tempWatch, hDlg); | |
1903 else | |
1904 inserted |= InsertWatch(tempWatch, ""); | |
1905 | |
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 went | |
1909 if(inserted && !RamWatchHWnd) | |
1910 SendMessage(hWnd, WM_COMMAND, ID_RAM_WATCH, 0); | |
1911 SetForegroundWindow(RamSearchHWnd); | |
1912 {rv = true; break;} | |
1913 } | |
1914 | |
1915 // eliminate all selected items | |
1916 case IDC_C_ELIMINATE: | |
1917 { | |
1918 RamSearchSaveUndoStateIfNotTooBig(hDlg); | |
1919 | |
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; | |
1924 | |
1925 // time-saving trick #1: | |
1926 // condense the selected items into an array of address ranges | |
1927 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 else | |
1935 selHardwareAddrs.push_back(AddrRange(addr,size)); | |
1936 | |
1937 if(!j) UpdateRamSearchProgressBar(i * 50 / selCount), j = 1024; | |
1938 } | |
1939 | |
1940 // now deactivate the ranges | |
1941 | |
1942 // time-saving trick #2: | |
1943 // take advantage of the fact that the listbox items must be in the same order as the regions | |
1944 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 } | |
1962 | |
1963 if(!j) UpdateRamSearchProgressBar(50 + (i * 50 / selCount)), j = 16; | |
1964 } | |
1965 UpdateRamSearchTitleBar(); | |
1966 | |
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 regions | |
1969 | |
1970 ListView_SetItemState(ramListControl, -1, 0, LVIS_SELECTED); // deselect all | |
1971 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 dialog | |
1979 else | |
1980 */ | |
1981 DestroyWindow(hDlg); | |
1982 {rv = true; break;} | |
1983 } | |
1984 | |
1985 // check refresh for comparison preview color update | |
1986 // also, update rs_val if needed | |
1987 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); | |
2022 | |
2023 | |
2024 return rv; | |
2025 } break; | |
2026 | |
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 } | |
2040 | |
2041 return false; | |
2042 } | |
2043 | |
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)" | |
2049 | |
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 else | |
2057 sprintf(Str_Tmp, PROGRESS_STR STATUS_STR, percent, poss, poss==1?"y":"ies", regions, regions==1?"":"s"); | |
2058 SetWindowText(RamSearchHWnd, Str_Tmp); | |
2059 } | |
2060 | |
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 } | |
2070 | |
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 } | |
2082 | |
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 else | |
2093 { | |
2094 LeaveCriticalSection(&s_activeMemoryRegionsCS); | |
2095 SetRamSearchUndoType(hDlg, 0); | |
2096 } | |
2097 } | |
2098 | |
2099 struct InitRamSearch | |
2100 { | |
2101 InitRamSearch() | |
2102 { | |
2103 InitializeCriticalSection(&s_activeMemoryRegionsCS); | |
2104 } | |
2105 ~InitRamSearch() | |
2106 { | |
2107 DeleteCriticalSection(&s_activeMemoryRegionsCS); | |
2108 } | |
2109 } initRamSearch; | |
2110 | |
2111 | |
2112 void init_list_box(HWND Box, const char* Strs[], int numColumns, int *columnWidths) //initializes the ram search and/or ram watch listbox | |
2113 { | |
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 } | |
2125 | |
2126 ListView_SetExtendedListViewStyle(Box, LVS_EX_FULLROWSELECT); | |
2127 } |