mirror of https://github.com/snes9xgit/snes9x.git
win32: add memory viewer (built-in hex editor)
Note: - write to APU hardware register doesn't work properly.
This commit is contained in:
parent
a1a3cfc986
commit
3e0d47a2cb
|
@ -0,0 +1,861 @@
|
|||
//MemView dialog was copied and adapted from DeSmuME: http://sourceforge.net/projects/desmume/
|
||||
//Authors: DeSmuME team
|
||||
|
||||
// gocha:
|
||||
// 1. According to Normmatt, YopYop had released the final version of original desmume as public domain.
|
||||
// 2. I asked DeSmuME team about the problem between GPL and Snes9x license, but no one raised any objections.
|
||||
// Therefore, I decided to include this code into snes9x-rr project.
|
||||
// Dear DeSmuME coders: if it is not allowed, please tell me.
|
||||
|
||||
/* Copyright (C) 2006 yopyop
|
||||
Copyright (C) 2006-2010 DeSmuME team
|
||||
|
||||
This file is part of DeSmuME
|
||||
|
||||
DeSmuME is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DeSmuME is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DeSmuME; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define NOMINMAX
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
#include "CWindow.h"
|
||||
#include "wsnes9x.h"
|
||||
#include "rsrc/resource.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define hAppInst GUI.hInstance
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The Toolkit - Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DWORD GetFontQuality()
|
||||
{
|
||||
BOOL aaEnabled = FALSE;
|
||||
UINT aaType = FE_FONTSMOOTHINGSTANDARD;
|
||||
|
||||
SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &aaEnabled, 0);
|
||||
if (aaEnabled == FALSE)
|
||||
return NONANTIALIASED_QUALITY;
|
||||
|
||||
if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &aaType, 0) == FALSE)
|
||||
return ANTIALIASED_QUALITY;
|
||||
|
||||
if (aaType == FE_FONTSMOOTHINGCLEARTYPE)
|
||||
return CLEARTYPE_QUALITY;
|
||||
else
|
||||
return ANTIALIASED_QUALITY;
|
||||
}
|
||||
|
||||
int DrawText(HDC hDC, TCHAR* text, int X, int Y, int Width, int Height, UINT format)
|
||||
{
|
||||
RECT rc;
|
||||
SetRect(&rc, X, Y, X+Width, Y+Height);
|
||||
return DrawText(hDC, text, -1, &rc, format);
|
||||
}
|
||||
|
||||
void GetFontSize(HWND hWnd, HFONT hFont, LPSIZE size)
|
||||
{
|
||||
HDC dc = GetDC(hWnd);
|
||||
HFONT oldfont = (HFONT)SelectObject(dc, hFont);
|
||||
|
||||
GetTextExtentPoint32(dc, TEXT(" "), 1, size);
|
||||
|
||||
SelectObject(dc, oldfont);
|
||||
ReleaseDC(hWnd, dc);
|
||||
}
|
||||
|
||||
void MakeBitmapPseudoTransparent(HBITMAP hBmp, COLORREF cKeyColor, COLORREF cNewKeyColor)
|
||||
{
|
||||
uint8 keyr = (cKeyColor >> 16) & 0xFF;
|
||||
uint8 keyg = (cKeyColor >> 8) & 0xFF;
|
||||
uint8 keyb = cKeyColor & 0xFF;
|
||||
uint8 nkeyr = (cNewKeyColor >> 16) & 0xFF;
|
||||
uint8 nkeyg = (cNewKeyColor >> 8) & 0xFF;
|
||||
uint8 nkeyb = cNewKeyColor & 0xFF;
|
||||
|
||||
BITMAP bmp;
|
||||
BITMAPINFO bmpinfo;
|
||||
uint8* bmpdata = NULL;
|
||||
|
||||
HDC dc = CreateCompatibleDC(NULL);
|
||||
|
||||
GetObject(hBmp, sizeof(BITMAP), &bmp);
|
||||
|
||||
memset(&bmpinfo, 0, sizeof(BITMAPINFO));
|
||||
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFO);
|
||||
bmpinfo.bmiHeader.biBitCount = 24;
|
||||
bmpinfo.bmiHeader.biCompression = BI_RGB;
|
||||
bmpinfo.bmiHeader.biHeight = bmp.bmHeight;
|
||||
bmpinfo.bmiHeader.biWidth = bmp.bmWidth;
|
||||
bmpinfo.bmiHeader.biPlanes = bmp.bmPlanes;
|
||||
bmpdata = new uint8[bmp.bmHeight * bmp.bmWidth * 3];
|
||||
|
||||
GetDIBits(dc, hBmp, 0, bmp.bmHeight, (LPVOID)bmpdata, &bmpinfo, DIB_RGB_COLORS);
|
||||
|
||||
int y2 = 0;
|
||||
for (int y = 0; y < bmp.bmHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < bmp.bmWidth; x++)
|
||||
{
|
||||
int idx = y2 + x*3;
|
||||
uint8 r = bmpdata[idx + 0];
|
||||
uint8 g = bmpdata[idx + 1];
|
||||
uint8 b = bmpdata[idx + 2];
|
||||
|
||||
if ((r == keyr) && (g == keyg) && (b == keyb))
|
||||
{
|
||||
bmpdata[idx + 0] = nkeyr;
|
||||
bmpdata[idx + 1] = nkeyg;
|
||||
bmpdata[idx + 2] = nkeyb;
|
||||
}
|
||||
}
|
||||
y2 += bmp.bmWidth * 3;
|
||||
}
|
||||
|
||||
SetDIBits(dc, hBmp, 0, bmp.bmHeight, (LPVOID)bmpdata, &bmpinfo, DIB_RGB_COLORS);
|
||||
DeleteDC(dc);
|
||||
delete[] bmpdata;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Window class handling
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
vector<tstring> ReggedWndClasses;
|
||||
|
||||
bool RegWndClass(tstring name, WNDPROC wndProc, UINT style, int extraSize)
|
||||
{
|
||||
return RegWndClass(name, wndProc, style, NULL, extraSize);
|
||||
}
|
||||
|
||||
bool RegWndClass(tstring name, WNDPROC wndProc, UINT style, HICON icon, int extraSize)
|
||||
{
|
||||
// If the class is already regged, don't re-reg it
|
||||
if (find(ReggedWndClasses.begin(), ReggedWndClasses.end(), name) != ReggedWndClasses.end())
|
||||
return true;
|
||||
|
||||
WNDCLASSEX wc;
|
||||
|
||||
wc.cbSize = sizeof(wc);
|
||||
wc.lpszClassName = name.c_str();
|
||||
wc.hInstance = hAppInst;
|
||||
wc.lpfnWndProc = wndProc;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hIcon = icon;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
|
||||
wc.style = style;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = DWLP_USER + extraSize;
|
||||
wc.hIconSm = 0;
|
||||
|
||||
if (RegisterClassEx(&wc) != 0)
|
||||
{
|
||||
// If registration succeeded, add the class name into the list
|
||||
ReggedWndClasses.push_back(name);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void UnregWndClass(tstring name)
|
||||
{
|
||||
vector<tstring>::iterator it = find(ReggedWndClasses.begin(), ReggedWndClasses.end(), name);
|
||||
|
||||
// If the class wasn't regged, we can't unreg it :P
|
||||
if (it == ReggedWndClasses.end())
|
||||
return;
|
||||
|
||||
// Otherwise unreg the class and remove its name from the list
|
||||
// ONLY if unregging was successful. Unregging will fail if one
|
||||
// or more windows using the class still exist.
|
||||
if (UnregisterClass(name.c_str(), hAppInst) != 0)
|
||||
ReggedWndClasses.erase(it);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Base toolwindow class
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CToolWindow::CToolWindow(TCHAR* _className, WNDPROC _proc, TCHAR* _title, int _width, int _height)
|
||||
: hWnd(NULL)
|
||||
, className(_className)
|
||||
, proc((DLGPROC)_proc)
|
||||
, title(_title)
|
||||
, width(_width)
|
||||
, height(_height)
|
||||
, whichInit(0)
|
||||
{
|
||||
}
|
||||
|
||||
CToolWindow::CToolWindow(int _ID, DLGPROC _proc, TCHAR* _title)
|
||||
: hWnd(NULL)
|
||||
, ID(_ID)
|
||||
, proc(_proc)
|
||||
, title(_title)
|
||||
, whichInit(1)
|
||||
{
|
||||
}
|
||||
|
||||
void CToolWindow::PostInitialize()
|
||||
{
|
||||
if(whichInit==0)
|
||||
{
|
||||
DWORD style = WS_CAPTION | WS_SYSMENU | WS_SIZEBOX | WS_MINIMIZEBOX | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||||
RECT rc;
|
||||
|
||||
rc.left = 0;
|
||||
rc.right = width;
|
||||
rc.top = 0;
|
||||
rc.bottom = height;
|
||||
AdjustWindowRect(&rc, style, FALSE);
|
||||
|
||||
hWnd = CreateWindow(className, title.c_str(), style, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
rc.right - rc.left, rc.bottom - rc.top, HWND_DESKTOP, NULL, hAppInst, (LPVOID)this);
|
||||
}
|
||||
else
|
||||
{
|
||||
hWnd = CreateDialogParam(hAppInst, MAKEINTRESOURCE(ID), HWND_DESKTOP, proc, (LPARAM)this);
|
||||
if (hWnd == NULL)
|
||||
return;
|
||||
|
||||
SetWindowText(hWnd, title.c_str());
|
||||
//SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon(hAppInst, MAKEINTRESOURCE(ICONDESMUME)));
|
||||
}
|
||||
}
|
||||
|
||||
CToolWindow::~CToolWindow()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Toolwindow handling
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CToolWindow* ToolWindowList = NULL;
|
||||
|
||||
bool OpenToolWindow(CToolWindow* wnd)
|
||||
{
|
||||
// A hWnd value of NULL indicates failure to create the window.
|
||||
// In this case, just delete the toolwindow and return failure.
|
||||
if (wnd->hWnd == NULL)
|
||||
{
|
||||
delete wnd;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the toolwindow to the list
|
||||
if (ToolWindowList == NULL)
|
||||
{
|
||||
ToolWindowList = wnd;
|
||||
wnd->prev = NULL;
|
||||
wnd->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
wnd->prev = NULL;
|
||||
wnd->next = ToolWindowList;
|
||||
wnd->next->prev = wnd;
|
||||
ToolWindowList = wnd;
|
||||
}
|
||||
|
||||
// Show the toolwindow (otherwise it won't show :P )
|
||||
wnd->Show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CloseToolWindow(CToolWindow* wnd)
|
||||
{
|
||||
// Remove the toolwindow from the list
|
||||
if (wnd == ToolWindowList)
|
||||
{
|
||||
ToolWindowList = wnd->next;
|
||||
if (wnd->next) wnd->next->prev = NULL;
|
||||
wnd->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
wnd->prev->next = wnd->next;
|
||||
if (wnd->next) wnd->next->prev = wnd->prev;
|
||||
wnd->prev = NULL;
|
||||
wnd->next = NULL;
|
||||
}
|
||||
|
||||
// Delete the toolwindow object
|
||||
// its destructor will destroy the window
|
||||
delete wnd;
|
||||
}
|
||||
|
||||
void CloseAllToolWindows()
|
||||
{
|
||||
CToolWindow* wnd;
|
||||
CToolWindow* wnd_next;
|
||||
|
||||
wnd = ToolWindowList;
|
||||
while (wnd)
|
||||
{
|
||||
wnd_next = wnd->next;
|
||||
|
||||
wnd->prev = NULL;
|
||||
wnd->next = NULL;
|
||||
delete wnd;
|
||||
|
||||
wnd = wnd_next;
|
||||
}
|
||||
|
||||
ToolWindowList = NULL;
|
||||
}
|
||||
|
||||
void RefreshAllToolWindows()
|
||||
{
|
||||
CToolWindow* wnd;
|
||||
|
||||
if (ToolWindowList == NULL)
|
||||
return;
|
||||
|
||||
wnd = ToolWindowList;
|
||||
while (wnd)
|
||||
{
|
||||
wnd->Refresh();
|
||||
wnd = wnd->next;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The Toolkit - Toolbar API wrapper
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CToolBar::CToolBar(HWND hParent)
|
||||
: hidden(false)
|
||||
{
|
||||
// Create the toolbar
|
||||
// Note: dropdown buttons look like crap without TBSTYLE_FLAT
|
||||
hWnd = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
|
||||
WS_CHILD | WS_VISIBLE | WS_BORDER | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
|
||||
0, 0, 0, 0, hParent, NULL, hAppInst, NULL);
|
||||
|
||||
// Send it a few messages to finish setting it up
|
||||
SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
|
||||
SendMessage(hWnd, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS);
|
||||
}
|
||||
|
||||
CToolBar::~CToolBar()
|
||||
{
|
||||
// Delete all the HBITMAPs we kept stored
|
||||
for (TBitmapList::iterator it = hBitmaps.begin();
|
||||
it != hBitmaps.end(); it++)
|
||||
{
|
||||
DeleteObject(it->second.second);
|
||||
}
|
||||
|
||||
hBitmaps.clear();
|
||||
}
|
||||
|
||||
void CToolBar::Show(bool bShow)
|
||||
{
|
||||
DWORD style = GetWindowLong(hWnd, GWL_STYLE);
|
||||
|
||||
if (bShow)
|
||||
{
|
||||
hidden = false;
|
||||
style |= WS_VISIBLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
hidden = true;
|
||||
style &= ~WS_VISIBLE;
|
||||
}
|
||||
|
||||
SetWindowLong(hWnd, GWL_STYLE, style);
|
||||
}
|
||||
|
||||
void CToolBar::OnSize()
|
||||
{
|
||||
SetWindowPos(hWnd, NULL,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
SWP_NOZORDER | SWP_NOMOVE);
|
||||
}
|
||||
|
||||
void CToolBar::AppendButton(int uID, int uBitmapID, DWORD dwState, bool bDropdown)
|
||||
{
|
||||
HBITMAP hbmp;
|
||||
TBADDBITMAP bmp;
|
||||
TBBUTTON btn;
|
||||
|
||||
// Get the bitmap and replace the key color (magenta) with the right color
|
||||
hbmp = LoadBitmap(hAppInst, MAKEINTRESOURCE(uBitmapID));
|
||||
MakeBitmapPseudoTransparent(hbmp, RGB(255, 0, 255), GetSysColor(COLOR_BTNFACE));
|
||||
|
||||
// Add the bitmap to the toolbar's image list
|
||||
bmp.hInst = NULL;
|
||||
bmp.nID = (UINT_PTR)hbmp;
|
||||
|
||||
int bmpid = SendMessage(hWnd, TB_ADDBITMAP, 1, (LPARAM)&bmp);
|
||||
|
||||
// Save the bitmap (if it gets deleted, the toolbar is too)
|
||||
hBitmaps[uBitmapID] = TBitmapPair(bmpid, hbmp);
|
||||
|
||||
// And finally add the button
|
||||
memset(&btn, 0, sizeof(TBBUTTON));
|
||||
btn.fsStyle = bDropdown ? TBSTYLE_DROPDOWN : TBSTYLE_BUTTON;
|
||||
btn.fsState = (BYTE) dwState;
|
||||
btn.idCommand = uID;
|
||||
btn.iString = -1;
|
||||
btn.iBitmap = bmpid;
|
||||
|
||||
SendMessage(hWnd, TB_ADDBUTTONS, 1, (LPARAM)&btn);
|
||||
}
|
||||
|
||||
void CToolBar::AppendSeparator()
|
||||
{
|
||||
TBBUTTON btn;
|
||||
|
||||
memset(&btn, 0, sizeof(TBBUTTON));
|
||||
btn.fsStyle = TBSTYLE_SEP;
|
||||
btn.idCommand = -1;
|
||||
btn.iString = -1;
|
||||
|
||||
SendMessage(hWnd, TB_ADDBUTTONS, 1, (LPARAM)&btn);
|
||||
}
|
||||
|
||||
void CToolBar::ChangeButtonBitmap(int uID, int uBitmapID)
|
||||
{
|
||||
int bmpid = 0;
|
||||
|
||||
// If we don't already have the bitmap, retrieve it,
|
||||
// adapt it and store it in the list
|
||||
TBitmapList::iterator it = hBitmaps.find(uBitmapID);
|
||||
|
||||
if (it == hBitmaps.end())
|
||||
{
|
||||
HBITMAP hbmp;
|
||||
TBADDBITMAP bmp;
|
||||
|
||||
hbmp = LoadBitmap(hAppInst, MAKEINTRESOURCE(uBitmapID));
|
||||
MakeBitmapPseudoTransparent(hbmp, RGB(255, 0, 255), GetSysColor(COLOR_BTNFACE));
|
||||
|
||||
bmp.hInst = NULL;
|
||||
bmp.nID = (UINT_PTR)hbmp;
|
||||
|
||||
bmpid = SendMessage(hWnd, TB_ADDBITMAP, 1, (LPARAM)&bmp);
|
||||
|
||||
hBitmaps[uBitmapID] = TBitmapPair(bmpid, hbmp);
|
||||
}
|
||||
else
|
||||
bmpid = hBitmaps[uBitmapID].first;
|
||||
|
||||
// Finally change the bitmap
|
||||
SendMessage(hWnd, TB_CHANGEBITMAP, uID, MAKELPARAM(bmpid, 0));
|
||||
}
|
||||
|
||||
void CToolBar::EnableButtonDropdown(int uID, bool bDropdown)
|
||||
{
|
||||
TBBUTTONINFO btninfo;
|
||||
|
||||
memset(&btninfo, 0, sizeof(TBBUTTONINFO));
|
||||
btninfo.cbSize = sizeof(TBBUTTONINFO);
|
||||
btninfo.dwMask = TBIF_STYLE;
|
||||
|
||||
SendMessage(hWnd, TB_GETBUTTONINFO, uID, (LPARAM)&btninfo);
|
||||
|
||||
btninfo.dwMask = TBIF_STYLE;
|
||||
if (bDropdown)
|
||||
{
|
||||
btninfo.fsStyle &= ~TBSTYLE_BUTTON;
|
||||
btninfo.fsStyle |= TBSTYLE_DROPDOWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
btninfo.fsStyle |= TBSTYLE_BUTTON;
|
||||
btninfo.fsStyle &= ~TBSTYLE_DROPDOWN;
|
||||
}
|
||||
|
||||
SendMessage(hWnd, TB_SETBUTTONINFO, uID, (LPARAM)&btninfo);
|
||||
}
|
||||
|
||||
int CToolBar::GetHeight()
|
||||
{
|
||||
if (hidden) return 0;
|
||||
|
||||
RECT rc; GetWindowRect(hWnd, &rc);
|
||||
return rc.bottom - rc.top - 1;
|
||||
}
|
||||
|
||||
|
||||
WINCLASS::WINCLASS(LPTSTR rclass, HINSTANCE hInst)
|
||||
{
|
||||
memset(regclass, 0, sizeof(regclass));
|
||||
memcpy(regclass, rclass, lstrlen(rclass));
|
||||
|
||||
hwnd = NULL;
|
||||
hmenu = NULL;
|
||||
hInstance = hInst;
|
||||
|
||||
minWidth = 0;
|
||||
minHeight = 0;
|
||||
}
|
||||
|
||||
WINCLASS::~WINCLASS()
|
||||
{
|
||||
}
|
||||
|
||||
bool WINCLASS::create(LPTSTR caption, int x, int y, int width, int height, int style, HMENU menu)
|
||||
{
|
||||
if (hwnd != NULL) return false;
|
||||
|
||||
hwnd = CreateWindow(regclass, caption, style, x, y, width, height, NULL, menu, hInstance, NULL);
|
||||
|
||||
if (hwnd != NULL) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WINCLASS::createEx(LPTSTR caption, int x, int y, int width, int height, int style, int styleEx, HMENU menu)
|
||||
{
|
||||
if (hwnd != NULL) return false;
|
||||
|
||||
hwnd = CreateWindowEx(styleEx, regclass, caption, style, x, y, width, height, NULL, menu, hInstance, NULL);
|
||||
|
||||
if (hwnd != NULL) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WINCLASS::setMenu(HMENU menu)
|
||||
{
|
||||
hmenu = menu;
|
||||
return SetMenu(hwnd, hmenu)!=FALSE;
|
||||
}
|
||||
|
||||
bool WINCLASS::addMenuItem(uint32 item, bool byPos, LPCMENUITEMINFO info)
|
||||
{
|
||||
return InsertMenuItem(hmenu, item, byPos ? TRUE : FALSE, info) != FALSE;
|
||||
}
|
||||
|
||||
DWORD WINCLASS::checkMenu(UINT idd, bool check)
|
||||
{
|
||||
return CheckMenuItem(hmenu, idd, MF_BYCOMMAND | (check?MF_CHECKED:MF_UNCHECKED));
|
||||
}
|
||||
|
||||
HWND WINCLASS::getHWnd()
|
||||
{
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
void WINCLASS::Show(int mode)
|
||||
{
|
||||
ShowWindow(hwnd, mode);
|
||||
}
|
||||
|
||||
void WINCLASS::Hide()
|
||||
{
|
||||
ShowWindow(hwnd, SW_HIDE);
|
||||
}
|
||||
|
||||
void WINCLASS::setMinSize(int width, int height)
|
||||
{
|
||||
minWidth = width;
|
||||
minHeight = height;
|
||||
}
|
||||
|
||||
static void MyAdjustWindowRectEx(RECT* rect, HWND hwnd)
|
||||
{
|
||||
AdjustWindowRectEx(rect,GetWindowStyle(hwnd),TRUE,GetWindowExStyle(hwnd));
|
||||
|
||||
//get height of one menu to subtract off
|
||||
int cymenu = GetSystemMetrics(SM_CYMENU);
|
||||
|
||||
//get the height of the actual menu to add back on
|
||||
MENUBARINFO mbi;
|
||||
ZeroMemory(&mbi, sizeof(mbi));
|
||||
mbi.cbSize = sizeof(mbi);
|
||||
GetMenuBarInfo(hwnd, OBJID_MENU, 0, &mbi);
|
||||
int menuHeight = (mbi.rcBar.bottom - mbi.rcBar.top + 1);
|
||||
|
||||
rect->bottom -= cymenu;
|
||||
rect->bottom += menuHeight;
|
||||
}
|
||||
|
||||
void WINCLASS::sizingMsg(WPARAM wParam, LPARAM lParam, LONG keepRatio)
|
||||
{
|
||||
RECT *rect = (RECT*)lParam;
|
||||
|
||||
int prevRight = rect->right;
|
||||
int prevBottom = rect->bottom;
|
||||
|
||||
int _minWidth, _minHeight;
|
||||
|
||||
int tbheight = 0/*MainWindowToolbar->GetHeight()*/;
|
||||
|
||||
RECT adjr;
|
||||
SetRect(&adjr,0,0,minWidth,minHeight);
|
||||
MyAdjustWindowRectEx(&adjr,hwnd);
|
||||
|
||||
RECT frameInfo;
|
||||
SetRect(&frameInfo,0,0,0,0);
|
||||
MyAdjustWindowRectEx(&frameInfo,hwnd);
|
||||
int frameWidth = frameInfo.right-frameInfo.left;
|
||||
int frameHeight = frameInfo.bottom-frameInfo.top + tbheight;
|
||||
|
||||
// Calculate the minimum size in pixels
|
||||
_minWidth = adjr.right-adjr.left;
|
||||
_minHeight = adjr.bottom-adjr.top + tbheight;
|
||||
|
||||
/* Clamp the size to the minimum size (256x384) */
|
||||
rect->right = (rect->left + std::max(_minWidth, (int)(rect->right - rect->left)));
|
||||
rect->bottom = (rect->top + std::max(_minHeight, (int)(rect->bottom - rect->top)));
|
||||
|
||||
bool horizontalDrag = (wParam == WMSZ_LEFT) || (wParam == WMSZ_RIGHT);
|
||||
bool verticalDrag = (wParam == WMSZ_TOP) || (wParam == WMSZ_BOTTOM);
|
||||
if(verticalDrag && !(keepRatio & KEEPY))
|
||||
{
|
||||
int clientHeight = rect->bottom - rect->top - frameHeight;
|
||||
if(clientHeight < minHeight)
|
||||
rect->bottom += minHeight - clientHeight;
|
||||
}
|
||||
else if(horizontalDrag && !(keepRatio & KEEPX))
|
||||
{
|
||||
int clientWidth = rect->right - rect->left - frameWidth;
|
||||
if(clientWidth < minWidth)
|
||||
rect->right += minWidth - clientWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Apply the ratio stuff
|
||||
|
||||
float ratio1 = ((rect->right - rect->left - frameWidth ) / (float)minWidth);
|
||||
float ratio2 = ((rect->bottom - rect->top - frameHeight) / (float)minHeight);
|
||||
float ratio = std::min(ratio1,ratio2);
|
||||
if(keepRatio & FULLSCREEN)
|
||||
{
|
||||
keepRatio |= WINCLASS::KEEPX | WINCLASS::KEEPY;
|
||||
ratio1 = ratio;
|
||||
ratio2 = ratio;
|
||||
}
|
||||
|
||||
LONG correctedHeight = (LONG)((rect->top + frameHeight + (minHeight * ratio1)));
|
||||
LONG correctedWidth = (LONG)((rect->left + frameWidth + (minWidth * ratio2)));
|
||||
|
||||
if(keepRatio & KEEPX)
|
||||
{
|
||||
if((keepRatio & KEEPY) || (rect->bottom < correctedHeight))
|
||||
{
|
||||
if(verticalDrag)
|
||||
rect->right = correctedWidth;
|
||||
else
|
||||
rect->bottom = correctedHeight;
|
||||
}
|
||||
}
|
||||
//else
|
||||
{
|
||||
if((keepRatio & KEEPY) && (rect->right < correctedWidth) || (keepRatio&FULLSCREEN))
|
||||
{
|
||||
if(horizontalDrag)
|
||||
rect->bottom = correctedHeight;
|
||||
else
|
||||
rect->right = correctedWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prevent "pushing" the window across the screen when resizing from the left or top
|
||||
if(wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT)
|
||||
{
|
||||
rect->left -= rect->right - prevRight;
|
||||
rect->right = prevRight;
|
||||
}
|
||||
if(wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT)
|
||||
{
|
||||
rect->top -= rect->bottom - prevBottom;
|
||||
rect->bottom = prevBottom;
|
||||
}
|
||||
|
||||
// windows screws up the window size if the top of the window goes too high above the top of the screen
|
||||
if(keepRatio & KEEPY)
|
||||
{
|
||||
int titleBarHeight = GetSystemMetrics(SM_CYSIZE);
|
||||
int topExceeded = -(titleBarHeight + rect->top);
|
||||
if(topExceeded > 0)
|
||||
{
|
||||
rect->top += topExceeded;
|
||||
rect->bottom += topExceeded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WINCLASS::setClientSize(int width, int height)
|
||||
{
|
||||
height += 0/*MainWindowToolbar->GetHeight()*/;
|
||||
|
||||
//yep, do it twice, once in case the menu wraps, and once to accomodate that wrap
|
||||
for(int i=0;i<2;i++)
|
||||
{
|
||||
RECT rect;
|
||||
SetRect(&rect,0,0,width,height);
|
||||
MyAdjustWindowRectEx(&rect,hwnd);
|
||||
SetWindowPos(hwnd,0,0,0,rect.right-rect.left,rect.bottom-rect.top,SWP_NOMOVE|SWP_NOZORDER);
|
||||
}
|
||||
}
|
||||
|
||||
//========================================================= Thread class
|
||||
extern DWORD WINAPI ThreadProc(LPVOID lpParameter)
|
||||
{
|
||||
THREADCLASS *tmp = (THREADCLASS *)lpParameter;
|
||||
return tmp->ThreadFunc();
|
||||
}
|
||||
|
||||
THREADCLASS::THREADCLASS()
|
||||
{
|
||||
hThread = NULL;
|
||||
}
|
||||
|
||||
THREADCLASS::~THREADCLASS()
|
||||
{
|
||||
closeThread();
|
||||
}
|
||||
|
||||
void THREADCLASS::closeThread()
|
||||
{
|
||||
if (hThread)
|
||||
{
|
||||
CloseHandle(hThread);
|
||||
hThread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool THREADCLASS::createThread()
|
||||
{
|
||||
if (hThread) return false;
|
||||
|
||||
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, this, 0, &threadID);
|
||||
if (!hThread) return false;
|
||||
//WaitForSingleObject(hThread, INFINITE);
|
||||
return true;
|
||||
}
|
||||
|
||||
//========================================================= Tools class
|
||||
TOOLSCLASS::TOOLSCLASS(HINSTANCE hInst, int IDD, DLGPROC dlgproc)
|
||||
{
|
||||
this->dlgproc = dlgproc;
|
||||
hwnd = NULL;
|
||||
hInstance = hInst;
|
||||
idd=IDD;
|
||||
memset(class_name, 0, sizeof(class_name));
|
||||
memset(class_name2, 0, sizeof(class_name2));
|
||||
}
|
||||
|
||||
TOOLSCLASS::~TOOLSCLASS()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool TOOLSCLASS::open(bool useThread)
|
||||
{
|
||||
if(useThread)
|
||||
{
|
||||
if (!createThread()) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
if(doOpen()) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
bool TOOLSCLASS::close()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD TOOLSCLASS::doOpen()
|
||||
{
|
||||
GetLastError();
|
||||
hwnd = CreateDialogW(hInstance, MAKEINTRESOURCEW(idd), NULL, (DLGPROC) dlgproc);
|
||||
|
||||
if (!hwnd)
|
||||
{
|
||||
return (-2);
|
||||
}
|
||||
|
||||
ShowWindow(hwnd, SW_SHOW);
|
||||
UpdateWindow(hwnd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TOOLSCLASS::doClose()
|
||||
{
|
||||
unregClass();
|
||||
hwnd = NULL;
|
||||
}
|
||||
|
||||
DWORD TOOLSCLASS::ThreadFunc()
|
||||
{
|
||||
DWORD ret = doOpen();
|
||||
if(ret) return ret;
|
||||
|
||||
MSG messages;
|
||||
while (GetMessage (&messages, NULL, 0, 0))
|
||||
{
|
||||
TranslateMessage(&messages);
|
||||
DispatchMessage(&messages);
|
||||
}
|
||||
|
||||
doClose();
|
||||
|
||||
closeThread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TOOLSCLASS::regClass(LPTSTR class_name, WNDPROC wproc, bool SecondReg)
|
||||
{
|
||||
WNDCLASSEX wc;
|
||||
|
||||
wc.cbSize = sizeof(wc);
|
||||
if (SecondReg)
|
||||
lstrcpy(this->class_name2, class_name);
|
||||
else
|
||||
lstrcpy(this->class_name, class_name);
|
||||
|
||||
wc.lpszClassName = class_name;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpfnWndProc = wproc;
|
||||
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||||
wc.hIcon = 0;
|
||||
wc.lpszMenuName = 0;
|
||||
wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE);
|
||||
wc.style = 0;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hIconSm = 0;
|
||||
|
||||
RegisterClassEx(&wc);
|
||||
}
|
||||
|
||||
void TOOLSCLASS::unregClass()
|
||||
{
|
||||
if (class_name[0])
|
||||
{
|
||||
UnregisterClass(class_name, hInstance);
|
||||
}
|
||||
if (class_name2[0])
|
||||
{
|
||||
UnregisterClass(class_name2, hInstance);
|
||||
}
|
||||
memset(class_name, 0, sizeof(class_name));
|
||||
memset(class_name2, 0, sizeof(class_name2));
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
//MemView dialog was copied and adapted from DeSmuME: http://sourceforge.net/projects/desmume/
|
||||
//Authors: DeSmuME team
|
||||
|
||||
// gocha:
|
||||
// 1. According to Normmatt, YopYop had released the final version of original desmume as public domain.
|
||||
// 2. I asked DeSmuME team about the problem between GPL and Snes9x license, but no one raised any objections.
|
||||
// Therefore, I decided to include this code into snes9x-rr project.
|
||||
// Dear DeSmuME coders: if it is not allowed, please tell me.
|
||||
|
||||
/* Copyright (C) 2006 yopyop
|
||||
Copyright (C) 2006-2009 DeSmuME team
|
||||
|
||||
This file is part of DeSmuME
|
||||
|
||||
DeSmuME is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DeSmuME is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DeSmuME; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef CWINDOW_H
|
||||
#define CWINDOW_H
|
||||
|
||||
#include <commctrl.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../port.h"
|
||||
|
||||
namespace std {
|
||||
#ifndef tstring
|
||||
#ifdef UNICODE
|
||||
typedef wstring tstring;
|
||||
#else
|
||||
typedef string tstring;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
extern CRITICAL_SECTION win_execute_sync;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The Toolkit - RECT wrapper
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CRect
|
||||
{
|
||||
public:
|
||||
CRect(int x, int y, int width, int height)
|
||||
{
|
||||
rcRect.left = x; rcRect.top = y;
|
||||
rcRect.right = x + width;
|
||||
rcRect.bottom = y + height;
|
||||
}
|
||||
CRect(RECT rc)
|
||||
{
|
||||
memcpy(&rcRect, &rc, sizeof(RECT));
|
||||
//rcRect = rc;
|
||||
}
|
||||
|
||||
~CRect() {}
|
||||
|
||||
RECT ToMSRect() { return rcRect; }
|
||||
|
||||
private:
|
||||
RECT rcRect;
|
||||
};
|
||||
|
||||
// GetFontQuality()
|
||||
// Returns a font quality value that can be passed to
|
||||
// CreateFont(). The value depends on whether font
|
||||
// antialiasing is enabled or not.
|
||||
DWORD GetFontQuality();
|
||||
|
||||
int DrawText(HDC hDC, TCHAR* text, int X, int Y, int Width, int Height, UINT format);
|
||||
void GetFontSize(HWND hWnd, HFONT hFont, LPSIZE size);
|
||||
|
||||
// MakeBitmapPseudoTransparent(HBITMAP hBmp, COLORREF cKeyColor, COLORREF cNewKeyColor)
|
||||
// Replaces the RGB color cKeyColor with cNewKeyColor in the bitmap hBmp.
|
||||
// For use with toolbars and such. Replace a key color (like magenta) with the right
|
||||
// system color to make the bitmap pseudo-transparent.
|
||||
void MakeBitmapPseudoTransparent(HBITMAP hBmp, COLORREF cKeyColor, COLORREF cNewKeyColor);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Window class handling
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// RegWndClass()
|
||||
// Registers a window class.
|
||||
// Incase the class was already registered, the function
|
||||
// just does nothing and returns true.
|
||||
// Returns false if registration failed.
|
||||
bool RegWndClass(std::tstring name, WNDPROC wndProc, UINT style, int extraSize = 0);
|
||||
bool RegWndClass(std::tstring name, WNDPROC wndProc, UINT style, HICON icon, int extraSize = 0);
|
||||
|
||||
// UnregWndClass()
|
||||
// Unregisters a previously registered window class.
|
||||
// This function will silently fail if one or more windows
|
||||
// using the class still exist.
|
||||
void UnregWndClass(std::tstring name);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Base toolwindow class
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CToolWindow
|
||||
{
|
||||
public:
|
||||
// CToolWindow constructor #1
|
||||
// Creates a window using CreateWindow().
|
||||
// If the window creation failed for whatever reason,
|
||||
// hWnd will be NULL.
|
||||
CToolWindow(TCHAR* className, WNDPROC proc, TCHAR* title, int width, int height);
|
||||
|
||||
// CToolWindow constructor #2
|
||||
// Creates a window from a dialog template resource.
|
||||
// If the window creation failed for whatever reason,
|
||||
// hWnd will be NULL.
|
||||
CToolWindow(int ID, DLGPROC proc, TCHAR* title);
|
||||
|
||||
// CToolWindow destructor
|
||||
// Dummy destructor. The derivated toolwindow classes must
|
||||
// destroy the window in their own destructors. Thus, they
|
||||
// can unregister any window classes they use.
|
||||
virtual ~CToolWindow();
|
||||
|
||||
// this must be called by the derived class constructor. sigh.
|
||||
void PostInitialize();
|
||||
|
||||
// Show(), Hide()
|
||||
// These ones are quite self-explanatory, I guess.
|
||||
void Show() { ShowWindow(hWnd, SW_SHOW); }
|
||||
void Hide() { ShowWindow(hWnd, SW_HIDE); }
|
||||
|
||||
// SetTitle()
|
||||
// Changes the title of the window.
|
||||
void SetTitle(TCHAR* title) { SetWindowText(hWnd, title); }
|
||||
|
||||
// Refresh()
|
||||
// Refreshes the window. Called by RefreshAllToolWindows().
|
||||
void Refresh() { InvalidateRect(hWnd, NULL, FALSE); }
|
||||
|
||||
// Double-linked toolwindow list.
|
||||
CToolWindow* prev;
|
||||
CToolWindow* next;
|
||||
|
||||
// Handle to the window.
|
||||
HWND hWnd;
|
||||
|
||||
private:
|
||||
int ID;
|
||||
DLGPROC proc;
|
||||
std::tstring title;
|
||||
TCHAR* className;
|
||||
int width, height;
|
||||
int whichInit;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Toolwindow handling
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// OpenToolWindow()
|
||||
// Adds the CToolWindow instance to the toolwindow list.
|
||||
// The instance will be deleted if its hWnd member is NULL.
|
||||
bool OpenToolWindow(CToolWindow* wnd);
|
||||
|
||||
// CloseToolWindow()
|
||||
// Removes the CToolWindow instance from the toolwindow list
|
||||
// and deletes it.
|
||||
void CloseToolWindow(CToolWindow* wnd);
|
||||
|
||||
// CloseAllToolWindows()
|
||||
// Deletes all the toolwindows in the list and flushes the list.
|
||||
void CloseAllToolWindows();
|
||||
|
||||
// RefreshAllToolWindows()
|
||||
// Refreshes all the toolwindows in the list.
|
||||
// Called once per frame when the emu is running.
|
||||
void RefreshAllToolWindows();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The Toolkit - Toolbar API wrapper
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CToolBar
|
||||
{
|
||||
public:
|
||||
CToolBar(HWND hParent);
|
||||
~CToolBar();
|
||||
|
||||
HWND GetHWnd() { return hWnd; }
|
||||
|
||||
void Show(bool bShow);
|
||||
bool Visible() { return !hidden; }
|
||||
|
||||
void OnSize();
|
||||
|
||||
void AppendButton(int uID, int uBitmapID, DWORD dwState, bool bDropdown);
|
||||
void AppendSeparator();
|
||||
|
||||
void EnableButton(int uID, bool bEnable) {
|
||||
SendMessage(hWnd, TB_ENABLEBUTTON, uID, bEnable ? TRUE:FALSE); }
|
||||
void CheckButton(int uID, bool bCheck) {
|
||||
SendMessage(hWnd, TB_CHECKBUTTON, uID, bCheck ? TRUE:FALSE); }
|
||||
|
||||
void ChangeButtonBitmap(int uID, int uBitmapID);
|
||||
void EnableButtonDropdown(int uID, bool bDropdown);
|
||||
void ChangeButtonID(int uIndex, int uNewID) {
|
||||
SendMessage(hWnd, TB_SETCMDID, uIndex, MAKELPARAM(uNewID, 0)); }
|
||||
|
||||
int GetHeight();
|
||||
|
||||
private:
|
||||
HWND hWnd;
|
||||
// We have to keep the bitmaps here because destroying them
|
||||
// directly after use would also destroy the toolbar.
|
||||
// They'll be destroyed when the CToolBar destructor is called.
|
||||
typedef std::pair<int, HBITMAP> TBitmapPair;
|
||||
typedef std::map<int, TBitmapPair> TBitmapList;
|
||||
TBitmapList hBitmaps;
|
||||
|
||||
bool hidden;
|
||||
};
|
||||
|
||||
|
||||
class WINCLASS
|
||||
{
|
||||
private:
|
||||
HWND hwnd;
|
||||
HMENU hmenu;
|
||||
HINSTANCE hInstance;
|
||||
TCHAR regclass[256];
|
||||
int minWidth, minHeight;
|
||||
public:
|
||||
WINCLASS(LPTSTR rclass, HINSTANCE hInst);
|
||||
~WINCLASS();
|
||||
|
||||
bool create(LPTSTR caption, int x, int y, int width, int height, int style,
|
||||
HMENU menu);
|
||||
bool createEx(LPTSTR caption, int x, int y, int width, int height, int style, int styleEx,
|
||||
HMENU menu);
|
||||
|
||||
bool setMenu(HMENU menu);
|
||||
bool addMenuItem(uint32 item, bool byPos, LPCMENUITEMINFO info);
|
||||
DWORD checkMenu(UINT idd, bool check);
|
||||
|
||||
void Show(int mode);
|
||||
void Hide();
|
||||
|
||||
HWND getHWnd();
|
||||
|
||||
CRect GetRect()
|
||||
{
|
||||
RECT rc; GetWindowRect(hwnd, &rc);
|
||||
return CRect(rc);
|
||||
}
|
||||
|
||||
void setMinSize(int width, int height);
|
||||
|
||||
enum // keepRatio flags
|
||||
{
|
||||
NOKEEP = 0x0,
|
||||
KEEPX = 0x1,
|
||||
KEEPY = 0x2,
|
||||
FULLSCREEN = 0x4,
|
||||
};
|
||||
|
||||
void sizingMsg(WPARAM wParam, LPARAM lParam, LONG keepRatio = NOKEEP);
|
||||
void setClientSize(int width, int height);
|
||||
};
|
||||
|
||||
class THREADCLASS
|
||||
{
|
||||
friend DWORD WINAPI ThreadProc(LPVOID lpParameter);
|
||||
HANDLE hThread;
|
||||
|
||||
public:
|
||||
THREADCLASS();
|
||||
virtual ~THREADCLASS();
|
||||
bool createThread();
|
||||
void closeThread();
|
||||
|
||||
protected:
|
||||
DWORD threadID;
|
||||
virtual DWORD ThreadFunc()=NULL;
|
||||
};
|
||||
|
||||
class TOOLSCLASS : public THREADCLASS
|
||||
{
|
||||
private:
|
||||
HWND hwnd;
|
||||
HINSTANCE hInstance;
|
||||
DLGPROC dlgproc;
|
||||
int idd;
|
||||
TCHAR class_name[256];
|
||||
TCHAR class_name2[256];
|
||||
|
||||
DWORD doOpen();
|
||||
void doClose();
|
||||
|
||||
protected:
|
||||
DWORD ThreadFunc();
|
||||
|
||||
public:
|
||||
TOOLSCLASS(HINSTANCE hInst, int IDD, DLGPROC wndproc);
|
||||
virtual ~TOOLSCLASS();
|
||||
bool open(bool useThread=true);
|
||||
bool close();
|
||||
void regClass(LPTSTR class_name, WNDPROC wproc, bool SecondReg = false);
|
||||
void unregClass();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,949 @@
|
|||
//MemView dialog was copied and adapted from DeSmuME: http://sourceforge.net/projects/desmume/
|
||||
//Authors: DeSmuME team
|
||||
|
||||
// gocha:
|
||||
// 1. According to Normmatt, YopYop had released the final version of original desmume as public domain.
|
||||
// 2. I asked DeSmuME team about the problem between GPL and Snes9x license, but no one raised any objections.
|
||||
// Therefore, I decided to include this code into snes9x-rr project.
|
||||
// Dear DeSmuME coders: if it is not allowed, please tell me.
|
||||
|
||||
/* Copyright (C) 2006 yopyop
|
||||
yopyop156@ifrance.com
|
||||
yopyop156.ifrance.com
|
||||
|
||||
This file is part of DeSmuME
|
||||
|
||||
DeSmuME is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DeSmuME is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DeSmuME; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <commctrl.h>
|
||||
#include <tchar.h>
|
||||
#include "../port.h"
|
||||
#include "../snes9x.h"
|
||||
#include "../memmap.h"
|
||||
#include "CWindow.h"
|
||||
#include "rsrc/resource.h"
|
||||
#include "wsnes9x.h"
|
||||
#include "memView.h"
|
||||
|
||||
#include "../apu/bapu/snes/snes.hpp"
|
||||
#if defined(DEBUGGER)
|
||||
extern SNES::SMPDebugger SNES::smp;
|
||||
#else
|
||||
extern SNES::SMP SNES::smp;
|
||||
#endif
|
||||
#define APURAM SNES::smp.apuram
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef uint32_t HWAddressType;
|
||||
|
||||
enum RegionType {
|
||||
MEMVIEW_RAM = 0,
|
||||
MEMVIEW_SRAM,
|
||||
MEMVIEW_FILLRAM,
|
||||
MEMVIEW_ARAM
|
||||
};
|
||||
|
||||
struct MemViewRegion
|
||||
{
|
||||
TCHAR name[16]; // name of this region (ex. SRAM)
|
||||
HWAddressType hardwareAddress; // hardware address of the start of this region
|
||||
unsigned int size; // number of bytes to the end of this region
|
||||
};
|
||||
|
||||
static const MemViewRegion s_ramRegion = { TEXT("RAM"), 0x7e0000, 0x20000 };
|
||||
static const MemViewRegion s_sramRegion = { TEXT("SRAM"), 0x000000, 0x20000 };
|
||||
static const MemViewRegion s_fillRAMRegion = { TEXT("FillRAM"), 0x000000, 0x8000 };
|
||||
static const MemViewRegion s_aramRegion = { TEXT("ARAM"), 0x000000, 0x10000 };
|
||||
|
||||
typedef std::vector<MemViewRegion> MemoryList;
|
||||
static MemoryList s_memoryRegions;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint8_t memRead8 (RegionType regionType, HWAddressType address)
|
||||
{
|
||||
MemViewRegion& region = s_memoryRegions[regionType];
|
||||
if (address < region.hardwareAddress || address >= (region.hardwareAddress + region.size))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (regionType)
|
||||
{
|
||||
case MEMVIEW_RAM:
|
||||
return Memory.RAM[address - 0x7e0000];
|
||||
case MEMVIEW_SRAM:
|
||||
return Memory.SRAM[address];
|
||||
case MEMVIEW_FILLRAM:
|
||||
return Memory.FillRAM[address];
|
||||
case MEMVIEW_ARAM:
|
||||
return APURAM[address];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t memRead16 (RegionType regionType, HWAddressType address)
|
||||
{
|
||||
MemViewRegion& region = s_memoryRegions[regionType];
|
||||
if (address < region.hardwareAddress || (address + 1) >= (region.hardwareAddress + region.size))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (regionType)
|
||||
{
|
||||
case MEMVIEW_RAM:
|
||||
return *(uint16_t*)(&Memory.RAM[address - 0x7e0000]);
|
||||
case MEMVIEW_SRAM:
|
||||
return *(uint16_t*)(&Memory.SRAM[address]);
|
||||
case MEMVIEW_FILLRAM:
|
||||
return *(uint16_t*)(&Memory.FillRAM[address]);
|
||||
case MEMVIEW_ARAM:
|
||||
return *(uint16_t*)(&APURAM[address]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t memRead32 (RegionType regionType, HWAddressType address)
|
||||
{
|
||||
MemViewRegion& region = s_memoryRegions[regionType];
|
||||
if (address < region.hardwareAddress || (address + 3) >= (region.hardwareAddress + region.size))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t value = memRead16(regionType, address);
|
||||
value |= (memRead16(regionType, address + 2) << 16);
|
||||
return value;
|
||||
}
|
||||
|
||||
void memRead(uint8_t* buffer, RegionType regionType, HWAddressType address, size_t size)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
buffer[i] = memRead8(regionType, address + i);
|
||||
}
|
||||
}
|
||||
|
||||
void memWrite8 (RegionType regionType, HWAddressType address, uint8_t value)
|
||||
{
|
||||
switch (regionType)
|
||||
{
|
||||
case MEMVIEW_RAM:
|
||||
Memory.RAM[address - 0x7e0000] = value;
|
||||
break;
|
||||
case MEMVIEW_SRAM:
|
||||
Memory.SRAM[address] = value;
|
||||
break;
|
||||
case MEMVIEW_FILLRAM:
|
||||
Memory.FillRAM[address] = value;
|
||||
break;
|
||||
case MEMVIEW_ARAM:
|
||||
APURAM[address] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void memWrite16 (RegionType regionType, HWAddressType address, uint16_t value)
|
||||
{
|
||||
switch (regionType)
|
||||
{
|
||||
case MEMVIEW_RAM:
|
||||
*(uint16_t*)(&Memory.RAM[address - 0x7e0000]) = value;
|
||||
break;
|
||||
case MEMVIEW_SRAM:
|
||||
*(uint16_t*)(&Memory.SRAM[address]) = value;
|
||||
break;
|
||||
case MEMVIEW_FILLRAM:
|
||||
*(uint16_t*)(&Memory.FillRAM[address]) = value;
|
||||
break;
|
||||
case MEMVIEW_ARAM:
|
||||
*(uint16_t*)(&APURAM[address]) = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void memWrite32 (RegionType regionType, HWAddressType address, uint32_t value)
|
||||
{
|
||||
memWrite16(regionType, address, value & 0xffff);
|
||||
memWrite16(regionType, address + 2, (value >> 16) & 0xffff);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CMemView::CMemView()
|
||||
: CToolWindow(IDD_MEM_VIEW, MemView_DlgProc, TEXT("Memory View"))
|
||||
, region(MEMVIEW_RAM)
|
||||
, viewMode(0)
|
||||
, sel(FALSE)
|
||||
, selPart(0)
|
||||
, selAddress(0x00000000)
|
||||
, selNewVal(0x00000000)
|
||||
{
|
||||
// initialize memory regions
|
||||
if (s_memoryRegions.empty())
|
||||
{
|
||||
s_memoryRegions.push_back(s_ramRegion);
|
||||
s_memoryRegions.push_back(s_sramRegion);
|
||||
s_memoryRegions.push_back(s_fillRAMRegion);
|
||||
s_memoryRegions.push_back(s_aramRegion);
|
||||
}
|
||||
address = s_memoryRegions.front().hardwareAddress;
|
||||
|
||||
PostInitialize();
|
||||
}
|
||||
|
||||
CMemView::~CMemView()
|
||||
{
|
||||
DestroyWindow(hWnd);
|
||||
hWnd = NULL;
|
||||
|
||||
UnregWndClass(TEXT("MemView_ViewBox"));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
INT_PTR CALLBACK MemView_DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CMemView* wnd = (CMemView*)GetWindowLongPtr(hDlg, DWLP_USER);
|
||||
if((wnd == NULL) && (uMsg != WM_INITDIALOG))
|
||||
return 0;
|
||||
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
HWND cur;
|
||||
|
||||
wnd = (CMemView*)lParam;
|
||||
SetWindowLongPtr(hDlg, DWLP_USER, (LONG)wnd);
|
||||
SetWindowLongPtr(GetDlgItem(hDlg, IDC_MEMVIEWBOX), DWLP_USER, (LONG)wnd);
|
||||
|
||||
wnd->font = CreateFont(16, 0, 0, 0, FW_MEDIUM, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
|
||||
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, GetFontQuality(), FIXED_PITCH, TEXT("Courier New"));
|
||||
|
||||
MemViewRegion& region = s_memoryRegions[wnd->region];
|
||||
|
||||
cur = GetDlgItem(hDlg, IDC_REGION);
|
||||
for(MemoryList::iterator iter = s_memoryRegions.begin(); iter != s_memoryRegions.end(); ++iter)
|
||||
{
|
||||
SendMessage(cur, CB_ADDSTRING, 0, (LPARAM)iter->name);
|
||||
}
|
||||
SendMessage(cur, CB_SETCURSEL, 0, 0);
|
||||
|
||||
cur = GetDlgItem(hDlg, IDC_VIEWMODE);
|
||||
SendMessage(cur, CB_ADDSTRING, 0, (LPARAM)TEXT("Bytes"));
|
||||
SendMessage(cur, CB_ADDSTRING, 0, (LPARAM)TEXT("Halfwords"));
|
||||
SendMessage(cur, CB_ADDSTRING, 0, (LPARAM)TEXT("Words"));
|
||||
SendMessage(cur, CB_SETCURSEL, 0, 0);
|
||||
|
||||
cur = GetDlgItem(hDlg, IDC_ADDRESS);
|
||||
SendMessage(cur, EM_SETLIMITTEXT, 8, 0);
|
||||
TCHAR addressText[9];
|
||||
wsprintf(addressText, TEXT("%06X"), wnd->address);
|
||||
SetWindowText(cur, addressText);
|
||||
|
||||
SetScrollRange(GetDlgItem(hDlg, IDC_MEMVIEWBOX), SB_VERT, 0x00000000, (region.size - 1) >> 4, TRUE);
|
||||
SetScrollPos(GetDlgItem(hDlg, IDC_MEMVIEWBOX), SB_VERT, 0x00000000, TRUE);
|
||||
|
||||
wnd->Refresh();
|
||||
}
|
||||
return 1;
|
||||
|
||||
case WM_CLOSE:
|
||||
CloseToolWindow(wnd);
|
||||
return 1;
|
||||
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
case IDCANCEL:
|
||||
CloseToolWindow(wnd);
|
||||
return 1;
|
||||
|
||||
case IDC_REGION:
|
||||
if ((HIWORD(wParam) == CBN_SELCHANGE) || (HIWORD(wParam) == CBN_CLOSEUP))
|
||||
{
|
||||
wnd->region = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0);
|
||||
|
||||
MemViewRegion& region = s_memoryRegions[wnd->region];
|
||||
wnd->address = region.hardwareAddress;
|
||||
SetScrollRange(GetDlgItem(hDlg, IDC_MEMVIEWBOX), SB_VERT, 0x00000000, (region.size - 1) >> 4, TRUE);
|
||||
SetScrollPos(GetDlgItem(hDlg, IDC_MEMVIEWBOX), SB_VERT, 0x00000000, TRUE);
|
||||
|
||||
wnd->sel = FALSE;
|
||||
wnd->selAddress = 0x00000000;
|
||||
wnd->selPart = 0;
|
||||
wnd->selNewVal = 0x00000000;
|
||||
|
||||
wnd->Refresh();
|
||||
}
|
||||
return 1;
|
||||
|
||||
case IDC_VIEWMODE:
|
||||
if ((HIWORD(wParam) == CBN_SELCHANGE) || (HIWORD(wParam) == CBN_CLOSEUP))
|
||||
{
|
||||
wnd->viewMode = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0);
|
||||
|
||||
wnd->sel = FALSE;
|
||||
wnd->selAddress = 0x00000000;
|
||||
wnd->selPart = 0;
|
||||
wnd->selNewVal = 0x00000000;
|
||||
|
||||
wnd->Refresh();
|
||||
}
|
||||
return 1;
|
||||
|
||||
case IDC_GO:
|
||||
{
|
||||
TCHAR addrstr[9];
|
||||
int len;
|
||||
int i;
|
||||
int shift;
|
||||
BOOL error = FALSE;
|
||||
uint32 address = 0x00000000;
|
||||
MemViewRegion& region = s_memoryRegions[wnd->region];
|
||||
HWAddressType addrMin = (region.hardwareAddress) & 0xFFFFFF00;
|
||||
HWAddressType addrMax = max(addrMin, (region.hardwareAddress + region.size - 0x100 - 1) & 0xFFFFFF00);
|
||||
|
||||
len = GetWindowText(GetDlgItem(hDlg, IDC_ADDRESS), addrstr, 9);
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
TCHAR ch = addrstr[i];
|
||||
|
||||
if((ch >= TEXT('0')) && (ch <= TEXT('9')))
|
||||
continue;
|
||||
|
||||
if((ch >= TEXT('A')) && (ch <= TEXT('F')))
|
||||
continue;
|
||||
|
||||
if((ch >= TEXT('a')) && (ch <= TEXT('f')))
|
||||
continue;
|
||||
|
||||
if(ch == '\0')
|
||||
break;
|
||||
|
||||
error = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if(error)
|
||||
{
|
||||
MessageBox(hDlg, TEXT("Error:\nInvalid address specified.\nThe address must be an hexadecimal value."), TEXT("Error"), (MB_OK | MB_ICONERROR));
|
||||
SetWindowText(GetDlgItem(hDlg, IDC_ADDRESS), TEXT(""));
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(i = (len-1), shift = 0; i >= 0; i--, shift += 4)
|
||||
{
|
||||
TCHAR ch = addrstr[i];
|
||||
|
||||
if((ch >= TEXT('0')) && (ch <= TEXT('9')))
|
||||
address |= ((ch - TEXT('0')) << shift);
|
||||
else if((ch >= TEXT('A')) && (ch <= TEXT('F')))
|
||||
address |= ((ch - TEXT('A') + 0xA) << shift);
|
||||
else if((ch >= TEXT('a')) && (ch <= TEXT('f')))
|
||||
address |= ((ch - TEXT('a') + 0xA) << shift);
|
||||
}
|
||||
|
||||
wnd->address = max((uint32)addrMin, min((uint32)addrMax, (address & 0xFFFFFFF0)));
|
||||
|
||||
wnd->sel = FALSE;
|
||||
wnd->selAddress = 0x00000000;
|
||||
wnd->selPart = 0;
|
||||
wnd->selNewVal = 0x00000000;
|
||||
|
||||
SetScrollPos(GetDlgItem(hDlg, IDC_MEMVIEWBOX), SB_VERT, (((wnd->address - region.hardwareAddress) >> 4) & 0x000FFFFF), TRUE);
|
||||
wnd->Refresh();
|
||||
}
|
||||
return 1;
|
||||
|
||||
case IDC_TEXTDUMP:
|
||||
{
|
||||
TCHAR fileName[256] = TEXT("");
|
||||
OPENFILENAME ofn;
|
||||
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = hDlg;
|
||||
ofn.lpstrFilter = TEXT("Text file (*.txt)\0*.txt\0Any file (*.*)\0*.*\0\0");
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFile = fileName;
|
||||
ofn.nMaxFile = 256;
|
||||
ofn.lpstrDefExt = TEXT("txt");
|
||||
ofn.Flags = OFN_NOCHANGEDIR | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
|
||||
|
||||
if(GetSaveFileName(&ofn))
|
||||
{
|
||||
FILE *f;
|
||||
uint8 memory[0x100];
|
||||
int line;
|
||||
|
||||
memRead(memory, (RegionType)wnd->region, wnd->address, 0x100);
|
||||
|
||||
f = _tfopen(fileName, TEXT("a"));
|
||||
|
||||
for(line = 0; line < 16; line++)
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf(f, "%08X\t\t", (wnd->address + (line << 4)));
|
||||
|
||||
switch(wnd->viewMode)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
fprintf(f, "%02X ", memory[(line << 4) + i]);
|
||||
}
|
||||
fprintf(f, "\t");
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
for(i = 0; i < 16; i += 2)
|
||||
{
|
||||
fprintf(f, "%04X ", *(uint16_t*)(&memory[(line << 4) + i]));
|
||||
}
|
||||
fprintf(f, "\t\t");
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
for(i = 0; i < 16; i += 4)
|
||||
{
|
||||
fprintf(f, "%08X ", *(uint32_t*)(&memory[(line << 4) + i]));
|
||||
}
|
||||
fprintf(f, "\t\t\t");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
uint8 val = memory[(line << 4) + i];
|
||||
|
||||
if((val >= 32) && (val <= 127))
|
||||
fprintf(f, "%c", (TCHAR)val);
|
||||
else
|
||||
fprintf(f, ".");
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
case IDC_DUMPALL:
|
||||
case IDC_RAWDUMP:
|
||||
{
|
||||
TCHAR fileName[256] = TEXT("");
|
||||
OPENFILENAME ofn;
|
||||
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = hDlg;
|
||||
ofn.lpstrFilter = TEXT("Binary file (*.bin)\0*.bin\0Any file (*.*)\0*.*\0\0");
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFile = fileName;
|
||||
ofn.nMaxFile = 256;
|
||||
ofn.lpstrDefExt = TEXT("bin");
|
||||
ofn.Flags = OFN_NOCHANGEDIR | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
|
||||
|
||||
if(GetSaveFileName(&ofn))
|
||||
{
|
||||
if(LOWORD(wParam) == IDC_RAWDUMP)
|
||||
{
|
||||
FILE *f = _tfopen(fileName, TEXT("ab"));
|
||||
if (f)
|
||||
{
|
||||
uint8 memory[0x100];
|
||||
memRead(memory, (RegionType)wnd->region, wnd->address, 0x100);
|
||||
fwrite(memory, 0x100, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const size_t blocksize = 0x100;
|
||||
byte* memory = new byte[blocksize];
|
||||
if (memory)
|
||||
{
|
||||
FILE *f = _tfopen(fileName, TEXT("wb"));
|
||||
if (f)
|
||||
{
|
||||
MemViewRegion& region = s_memoryRegions[wnd->region];
|
||||
for (HWAddressType address = region.hardwareAddress;
|
||||
address < region.hardwareAddress + region.size; address += blocksize)
|
||||
{
|
||||
size_t size = blocksize;
|
||||
if (address + size > region.hardwareAddress + region.size)
|
||||
{
|
||||
size = region.size - (address - region.hardwareAddress);
|
||||
}
|
||||
memRead(memory, (RegionType)wnd->region, address, size);
|
||||
fwrite(memory, size, 1, f);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
delete [] memory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LRESULT MemView_ViewBoxPaint(CMemView* wnd, HWND hCtl, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HDC hdc;
|
||||
PAINTSTRUCT ps;
|
||||
RECT rc;
|
||||
int w, h;
|
||||
SIZE fontsize;
|
||||
HDC mem_hdc;
|
||||
HBITMAP mem_bmp;
|
||||
uint32 addr = wnd->address;
|
||||
uint8 memory[0x100];
|
||||
TCHAR text[80];
|
||||
int startx;
|
||||
int curx, cury;
|
||||
int line;
|
||||
|
||||
GetClientRect(hCtl, &rc);
|
||||
w = (rc.right - rc.left);
|
||||
h = (rc.bottom - rc.top);
|
||||
|
||||
hdc = BeginPaint(hCtl, &ps);
|
||||
|
||||
mem_hdc = CreateCompatibleDC(hdc);
|
||||
mem_bmp = CreateCompatibleBitmap(hdc, w, h);
|
||||
SelectObject(mem_hdc, mem_bmp);
|
||||
|
||||
SelectObject(mem_hdc, wnd->font);
|
||||
|
||||
SetBkMode(mem_hdc, OPAQUE);
|
||||
SetBkColor(mem_hdc, RGB(255, 255, 255));
|
||||
SetTextColor(mem_hdc, RGB(0, 0, 0));
|
||||
|
||||
FillRect(mem_hdc, &rc, (HBRUSH)GetStockObject(WHITE_BRUSH));
|
||||
|
||||
GetTextExtentPoint32(mem_hdc, TEXT(" "), 1, &fontsize);
|
||||
startx = ((fontsize.cx * 8) + 5);
|
||||
curx = 0;
|
||||
cury = (fontsize.cy + 3);
|
||||
|
||||
MoveToEx(mem_hdc, ((fontsize.cx * 8) + 2), 0, NULL);
|
||||
LineTo(mem_hdc, ((fontsize.cx * 8) + 2), h);
|
||||
|
||||
MoveToEx(mem_hdc, 0, (fontsize.cy + 1), NULL);
|
||||
LineTo(mem_hdc, w, (fontsize.cy + 1));
|
||||
|
||||
switch(wnd->viewMode)
|
||||
{
|
||||
case 0: _stprintf(text, TEXT(" 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF")); break;
|
||||
case 1: _stprintf(text, TEXT(" 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF")); break;
|
||||
case 2: _stprintf(text, TEXT(" 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF")); break;
|
||||
}
|
||||
TextOut(mem_hdc, startx, 0, text, lstrlen(text));
|
||||
|
||||
memRead(memory, (RegionType)wnd->region, wnd->address, 0x100);
|
||||
|
||||
for(line = 0; line < 16; line++, addr += 0x10)
|
||||
{
|
||||
int i;
|
||||
|
||||
_stprintf(text, TEXT("%08X"), addr);
|
||||
TextOut(mem_hdc, 0, cury, text, lstrlen(text));
|
||||
|
||||
curx = startx;
|
||||
|
||||
switch(wnd->viewMode)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
curx += (fontsize.cx * 2);
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
uint8 val = memory[(line << 4) + i];
|
||||
if(wnd->sel && (wnd->selAddress == (addr + i)))
|
||||
{
|
||||
SetBkColor(mem_hdc, GetSysColor(COLOR_HIGHLIGHT));
|
||||
SetTextColor(mem_hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
|
||||
switch(wnd->selPart)
|
||||
{
|
||||
case 0: _stprintf(text, TEXT("%02X"), val); break;
|
||||
case 1: _stprintf(text, TEXT("%01X."), wnd->selNewVal); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBkColor(mem_hdc, RGB(255, 255, 255));
|
||||
SetTextColor(mem_hdc, RGB(0, 0, 0));
|
||||
|
||||
_stprintf(text, TEXT("%02X"), val);
|
||||
}
|
||||
|
||||
TextOut(mem_hdc, curx, cury, text, lstrlen(text));
|
||||
curx += (fontsize.cx * (2+1));
|
||||
}
|
||||
curx += (fontsize.cx * 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
curx += (fontsize.cx * 6);
|
||||
for(i = 0; i < 16; i += 2)
|
||||
{
|
||||
uint16 val = *(uint16_t*)(&memory[(line << 4) + i]);
|
||||
if(wnd->sel && (wnd->selAddress == (addr + i)))
|
||||
{
|
||||
SetBkColor(mem_hdc, GetSysColor(COLOR_HIGHLIGHT));
|
||||
SetTextColor(mem_hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
|
||||
switch(wnd->selPart)
|
||||
{
|
||||
case 0: _stprintf(text, TEXT("%04X"), val); break;
|
||||
case 1: _stprintf(text, TEXT("%01X..."), wnd->selNewVal); break;
|
||||
case 2: _stprintf(text, TEXT("%02X.."), wnd->selNewVal); break;
|
||||
case 3: _stprintf(text, TEXT("%03X."), wnd->selNewVal); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBkColor(mem_hdc, RGB(255, 255, 255));
|
||||
SetTextColor(mem_hdc, RGB(0, 0, 0));
|
||||
|
||||
_stprintf(text, TEXT("%04X"), val);
|
||||
}
|
||||
|
||||
TextOut(mem_hdc, curx, cury, text, lstrlen(text));
|
||||
curx += (fontsize.cx * (4+1));
|
||||
}
|
||||
curx += (fontsize.cx * 6);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
curx += (fontsize.cx * 8);
|
||||
for(i = 0; i < 16; i += 4)
|
||||
{
|
||||
uint32 val = *(uint32_t*)(&memory[(line << 4) + i]);
|
||||
if(wnd->sel && (wnd->selAddress == (addr + i)))
|
||||
{
|
||||
SetBkColor(mem_hdc, GetSysColor(COLOR_HIGHLIGHT));
|
||||
SetTextColor(mem_hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
|
||||
|
||||
switch(wnd->selPart)
|
||||
{
|
||||
case 0: _stprintf(text, TEXT("%08X"), val); break;
|
||||
case 1: _stprintf(text, TEXT("%01X......."), wnd->selNewVal); break;
|
||||
case 2: _stprintf(text, TEXT("%02X......"), wnd->selNewVal); break;
|
||||
case 3: _stprintf(text, TEXT("%03X....."), wnd->selNewVal); break;
|
||||
case 4: _stprintf(text, TEXT("%04X...."), wnd->selNewVal); break;
|
||||
case 5: _stprintf(text, TEXT("%05X..."), wnd->selNewVal); break;
|
||||
case 6: _stprintf(text, TEXT("%06X.."), wnd->selNewVal); break;
|
||||
case 7: _stprintf(text, TEXT("%07X."), wnd->selNewVal); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetBkColor(mem_hdc, RGB(255, 255, 255));
|
||||
SetTextColor(mem_hdc, RGB(0, 0, 0));
|
||||
|
||||
_stprintf(text, TEXT("%08X"), val);
|
||||
}
|
||||
|
||||
TextOut(mem_hdc, curx, cury, text, lstrlen(text));
|
||||
curx += (fontsize.cx * (8+1));
|
||||
}
|
||||
curx += (fontsize.cx * 8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SetBkColor(mem_hdc, RGB(255, 255, 255));
|
||||
SetTextColor(mem_hdc, RGB(0, 0, 0));
|
||||
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
uint8 val = memory[(line << 4) + i];
|
||||
|
||||
if((val >= 32) && (val <= 127))
|
||||
text[i] = (TCHAR)val;
|
||||
else
|
||||
text[i] = TEXT('.');
|
||||
}
|
||||
text[16] = '\0';
|
||||
TextOut(mem_hdc, curx, cury, text, lstrlen(text));
|
||||
|
||||
cury += fontsize.cy;
|
||||
}
|
||||
|
||||
BitBlt(hdc, 0, 0, w, h, mem_hdc, 0, 0, SRCCOPY);
|
||||
|
||||
DeleteDC(mem_hdc);
|
||||
DeleteObject(mem_bmp);
|
||||
|
||||
EndPaint(hCtl, &ps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK MemView_ViewBoxProc(HWND hCtl, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CMemView* wnd = (CMemView*)GetWindowLongPtr(hCtl, DWLP_USER);
|
||||
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_NCCREATE:
|
||||
SetScrollRange(hCtl, SB_VERT, 0x00000000, 0x000FFFF0, TRUE);
|
||||
SetScrollPos(hCtl, SB_VERT, 0x00000000, TRUE);
|
||||
return 1;
|
||||
|
||||
case WM_NCDESTROY:
|
||||
return 1;
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
return 1;
|
||||
|
||||
case WM_PAINT:
|
||||
MemView_ViewBoxPaint(wnd, hCtl, wParam, lParam);
|
||||
return 1;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
HDC hdc;
|
||||
HFONT font;
|
||||
SIZE fontsize;
|
||||
int x, y;
|
||||
|
||||
wnd->sel = FALSE;
|
||||
wnd->selAddress = 0x00000000;
|
||||
wnd->selPart = 0;
|
||||
wnd->selNewVal = 0x00000000;
|
||||
|
||||
hdc = GetDC(hCtl);
|
||||
font = (HFONT)SelectObject(hdc, wnd->font);
|
||||
GetTextExtentPoint32(hdc, TEXT(" "), 1, &fontsize);
|
||||
|
||||
x = LOWORD(lParam);
|
||||
y = HIWORD(lParam);
|
||||
|
||||
if((x >= ((fontsize.cx * 8) + 5)) && (y >= (fontsize.cy + 3)))
|
||||
{
|
||||
int line, col;
|
||||
|
||||
x -= ((fontsize.cx * 8) + 5);
|
||||
y -= (fontsize.cy + 3);
|
||||
|
||||
line = (y / fontsize.cy);
|
||||
|
||||
switch(wnd->viewMode)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if((x < (fontsize.cx * 2)) || (x >= (fontsize.cx * (2 + ((2+1) * 16)))))
|
||||
break;
|
||||
|
||||
col = ((x - (fontsize.cx * 2)) / (fontsize.cx * (2+1)));
|
||||
|
||||
wnd->sel = TRUE;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
if((x < (fontsize.cx * 6)) || (x >= (fontsize.cx * (6 + ((4+1) * 8)))))
|
||||
break;
|
||||
|
||||
col = ((x - (fontsize.cx * 6)) / (fontsize.cx * (4+1)) * 2);
|
||||
|
||||
wnd->sel = TRUE;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
if((x < (fontsize.cx * 8)) || (x >= (fontsize.cx * (8 + ((8+1) * 4)))))
|
||||
break;
|
||||
|
||||
col = ((x - (fontsize.cx * 8)) / (fontsize.cx * (8+1)) * 4);
|
||||
|
||||
wnd->sel = TRUE;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
wnd->selAddress = (wnd->address + (line << 4) + col);
|
||||
wnd->selPart = 0;
|
||||
wnd->selNewVal = 0x00000000;
|
||||
}
|
||||
|
||||
SelectObject(hdc, font);
|
||||
ReleaseDC(hCtl, hdc);
|
||||
|
||||
SetFocus(hCtl); /* Required to receive keyboard messages */
|
||||
wnd->Refresh();
|
||||
}
|
||||
return 1;
|
||||
|
||||
case WM_CHAR:
|
||||
{
|
||||
TCHAR ch = (TCHAR)wParam;
|
||||
|
||||
if(((ch >= TEXT('0')) && (ch <= TEXT('9'))) || ((ch >= TEXT('A')) && (ch <= TEXT('F'))) || ((ch >= TEXT('a')) && (ch <= TEXT('f'))))
|
||||
{
|
||||
//if ((wnd->region == ARMCPU_ARM7) && ((wnd->selAddress & 0xFFFF0000) == 0x04800000))
|
||||
// return DefWindowProc(hCtl, uMsg, wParam, lParam);
|
||||
|
||||
uint8 maxSelPart[3] = {2, 4, 8};
|
||||
|
||||
wnd->selNewVal <<= 4;
|
||||
wnd->selPart++;
|
||||
|
||||
if((ch >= TEXT('0')) && (ch <= TEXT('9')))
|
||||
wnd->selNewVal |= (ch - TEXT('0'));
|
||||
else if((ch >= TEXT('A')) && (ch <= TEXT('F')))
|
||||
wnd->selNewVal |= (ch - TEXT('A') + 0xA);
|
||||
else if((ch >= TEXT('a')) && (ch <= TEXT('f')))
|
||||
wnd->selNewVal |= (ch - TEXT('a') + 0xA);
|
||||
|
||||
if(wnd->selPart >= maxSelPart[wnd->viewMode])
|
||||
{
|
||||
switch(wnd->viewMode)
|
||||
{
|
||||
case 0: memWrite8((RegionType)wnd->region, wnd->selAddress, (uint8)wnd->selNewVal); wnd->selAddress++; break;
|
||||
case 1: memWrite16((RegionType)wnd->region, wnd->selAddress, (uint16)wnd->selNewVal); wnd->selAddress += 2; break;
|
||||
case 2: memWrite32((RegionType)wnd->region, wnd->selAddress, wnd->selNewVal); wnd->selAddress += 4; break;
|
||||
}
|
||||
wnd->selPart = 0;
|
||||
wnd->selNewVal = 0x00000000;
|
||||
|
||||
if(wnd->selAddress == 0x00000000)
|
||||
{
|
||||
wnd->sel = FALSE;
|
||||
}
|
||||
else if(wnd->selAddress >= (wnd->address + 0x100))
|
||||
{
|
||||
MemViewRegion& region = s_memoryRegions[wnd->region];
|
||||
HWAddressType addrMin = (region.hardwareAddress) & 0xFFFFFF00;
|
||||
HWAddressType addrMax = max(addrMin, (region.hardwareAddress + region.size - 0x100 - 1) & 0xFFFFFF00);
|
||||
if (wnd->address + 0x10 <= addrMax)
|
||||
{
|
||||
wnd->address += 0x10;
|
||||
SetScrollPos(hCtl, SB_VERT, (((wnd->address - region.hardwareAddress) >> 4) & 0x000FFFFF), TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(wnd->viewMode)
|
||||
{
|
||||
case 0: wnd->selAddress--; break;
|
||||
case 1: wnd->selAddress -= 2; break;
|
||||
case 2: wnd->selAddress -= 4; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wnd->Refresh();
|
||||
}
|
||||
return 1;
|
||||
|
||||
case WM_VSCROLL:
|
||||
{
|
||||
int firstpos = GetScrollPos(hCtl, SB_VERT);
|
||||
MemViewRegion& region = s_memoryRegions[wnd->region];
|
||||
HWAddressType addrMin = (region.hardwareAddress) & 0xFFFFFF00;
|
||||
HWAddressType addrMax = (region.hardwareAddress + region.size - 1) & 0xFFFFFF00;
|
||||
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
case SB_LINEUP:
|
||||
wnd->address = (uint32)max((int)addrMin, ((int)wnd->address - 0x10));
|
||||
break;
|
||||
|
||||
case SB_LINEDOWN:
|
||||
wnd->address = min((uint32)addrMax, (wnd->address + 0x10));
|
||||
break;
|
||||
|
||||
case SB_PAGEUP:
|
||||
wnd->address = (uint32)max((int)addrMin, ((int)wnd->address - 0x100));
|
||||
break;
|
||||
|
||||
case SB_PAGEDOWN:
|
||||
wnd->address = min((uint32)addrMax, (wnd->address + 0x100));
|
||||
break;
|
||||
|
||||
case SB_THUMBTRACK:
|
||||
case SB_THUMBPOSITION:
|
||||
{
|
||||
SCROLLINFO si;
|
||||
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cbSize = sizeof(si);
|
||||
si.fMask = SIF_TRACKPOS;
|
||||
|
||||
GetScrollInfo(hCtl, SB_VERT, &si);
|
||||
|
||||
wnd->address = min((uint32)addrMax, (wnd->address + ((si.nTrackPos - firstpos) * 16)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if((wnd->selAddress < wnd->address) || (wnd->selAddress >= (wnd->address + 0x100)))
|
||||
{
|
||||
wnd->sel = FALSE;
|
||||
wnd->selAddress = 0x00000000;
|
||||
wnd->selPart = 0;
|
||||
wnd->selNewVal = 0x00000000;
|
||||
}
|
||||
|
||||
SetScrollPos(hCtl, SB_VERT, (((wnd->address - region.hardwareAddress) >> 4) & 0x000FFFFF), TRUE);
|
||||
wnd->Refresh();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return DefWindowProc(hCtl, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,58 @@
|
|||
//MemView dialog was copied and adapted from DeSmuME: http://sourceforge.net/projects/desmume/
|
||||
//Authors: DeSmuME team
|
||||
|
||||
// gocha:
|
||||
// 1. According to Normmatt, YopYop had released the final version of original desmume as public domain.
|
||||
// 2. I asked DeSmuME team about the problem between GPL and Snes9x license, but no one raised any objections.
|
||||
// Therefore, I decided to include this code into snes9x-rr project.
|
||||
// Dear DeSmuME coders: if it is not allowed, please tell me.
|
||||
|
||||
/* Copyright (C) 2006 yopyop
|
||||
yopyop156@ifrance.com
|
||||
yopyop156.ifrance.com
|
||||
|
||||
This file is part of DeSmuME
|
||||
|
||||
DeSmuME is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DeSmuME is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DeSmuME; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef MEM_VIEW_H
|
||||
#define MEM_VIEW_H
|
||||
|
||||
#include <windows.h>
|
||||
#include "../port.h"
|
||||
|
||||
INT_PTR CALLBACK MemView_DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
LRESULT CALLBACK MemView_ViewBoxProc(HWND hCtl, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
class CMemView : public CToolWindow
|
||||
{
|
||||
public:
|
||||
CMemView();
|
||||
~CMemView();
|
||||
|
||||
HFONT font;
|
||||
|
||||
uint32 region;
|
||||
uint32 address;
|
||||
uint32 viewMode;
|
||||
|
||||
BOOL sel;
|
||||
uint32 selPart;
|
||||
uint32 selAddress;
|
||||
uint32 selNewVal;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -42,6 +42,7 @@
|
|||
#define IDD_EDITWATCH 502
|
||||
#define IDD_PROMPT 503
|
||||
#define IDR_RWACCELERATOR 504
|
||||
#define IDD_MEM_VIEW 505
|
||||
#define IDC_DRIVER 1001
|
||||
#define IDC_BUFLEN 1002
|
||||
#define IDC_RATE 1003
|
||||
|
@ -407,6 +408,14 @@
|
|||
#define IDC_PROMPT_TEXT2 5037
|
||||
#define IDC_PROMPT_EDIT 5038
|
||||
#define IDC_WATCHES_GROUP 5039
|
||||
#define IDC_GO 5040
|
||||
#define IDC_TEXTDUMP 5041
|
||||
#define IDC_MEMVIEWBOX 5042
|
||||
//#define IDC_ADDRESS 5043
|
||||
#define IDC_RAWDUMP 5044
|
||||
#define IDC_REGION 5045
|
||||
#define IDC_VIEWMODE 5046
|
||||
#define IDC_DUMPALL 5047
|
||||
#define ID_FILE_EXIT 40001
|
||||
#define ID_WINDOW_HIDEMENUBAR 40004
|
||||
#define ID_FILE_AVI_RECORDING 40005
|
||||
|
@ -552,6 +561,7 @@
|
|||
#define ID_RAM_WATCH 45009
|
||||
#define RW_MENU_FIRST_RECENT_FILE 45010
|
||||
#define RW_MENU_LAST_RECENT_FILE 45011
|
||||
#define IDM_MEMORY 45031
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
|
|
|
@ -697,6 +697,25 @@ BEGIN
|
|||
EDITTEXT IDC_PROMPT_EDIT,10,15,167,14,ES_AUTOHSCROLL
|
||||
END
|
||||
|
||||
IDD_MEM_VIEW DIALOGEX 0, 0, 444, 283
|
||||
STYLE DS_SETFONT | DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
PUSHBUTTON "Close",IDCANCEL,378,262,60,15
|
||||
GROUPBOX "View mode",IDC_STATIC,66,6,72,30
|
||||
GROUPBOX "Address",IDC_STATIC,144,6,108,30
|
||||
PUSHBUTTON "Go",IDC_GO,222,18,25,14
|
||||
PUSHBUTTON "Text dump",IDC_TEXTDUMP,264,18,49,14
|
||||
CONTROL "1",IDC_MEMVIEWBOX,"MemView_ViewBox",WS_VSCROLL | WS_TABSTOP,6,42,432,204
|
||||
EDITTEXT IDC_ADDRESS,150,18,72,14,ES_AUTOHSCROLL,WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "Raw dump",IDC_RAWDUMP,317,18,48,14
|
||||
GROUPBOX "Dump view",IDC_STATIC,258,6,180,30
|
||||
GROUPBOX "Region",IDC_STATIC,6,6,54,30
|
||||
COMBOBOX IDC_REGION,12,18,42,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
COMBOBOX IDC_VIEWMODE,72,18,60,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Dump All",IDC_DUMPALL,369,18,48,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -825,6 +844,12 @@ BEGIN
|
|||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 83
|
||||
END
|
||||
|
||||
IDD_MEM_VIEW, DIALOG
|
||||
BEGIN
|
||||
RIGHTMARGIN, 438
|
||||
BOTTOMMARGIN, 270
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
@ -1077,6 +1102,7 @@ BEGIN
|
|||
MENUITEM SEPARATOR
|
||||
MENUITEM "RAM Watch...", ID_RAM_WATCH, GRAYED
|
||||
MENUITEM "RAM &Search...\tAlt+A", ID_RAM_SEARCH, GRAYED
|
||||
MENUITEM "View &Memory", IDM_MEMORY
|
||||
END
|
||||
POPUP "&Netplay"
|
||||
BEGIN
|
||||
|
|
|
@ -3014,6 +3014,14 @@
|
|||
RelativePath=".\AVIOutput.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CWindow.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\CWindow.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\InputCustom.cpp"
|
||||
>
|
||||
|
@ -3022,6 +3030,14 @@
|
|||
RelativePath=".\InputCustom.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\memView.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\memView.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\ram_search.cpp"
|
||||
>
|
||||
|
|
|
@ -214,6 +214,8 @@
|
|||
#include "../statemanager.h"
|
||||
#include "AVIOutput.h"
|
||||
#include "InputCustom.h"
|
||||
#include "CWindow.h"
|
||||
#include "memView.h"
|
||||
#include "ram_search.h"
|
||||
#include "ramwatch.h"
|
||||
#include <vector>
|
||||
|
@ -2240,6 +2242,12 @@ LRESULT CALLBACK WinProc(
|
|||
else
|
||||
SetForegroundWindow(RamWatchHWnd);
|
||||
break;
|
||||
case IDM_MEMORY:
|
||||
if (!RegWndClass(TEXT("MemView_ViewBox"), MemView_ViewBoxProc, 0, sizeof(CMemView*)))
|
||||
return 0;
|
||||
|
||||
OpenToolWindow(new CMemView());
|
||||
return 0;
|
||||
case ID_CHEAT_APPLY:
|
||||
Settings.ApplyCheats = !Settings.ApplyCheats;
|
||||
if (!Settings.ApplyCheats){
|
||||
|
@ -3488,7 +3496,7 @@ int WINAPI WinMain(
|
|||
}
|
||||
|
||||
S9xMainLoop();
|
||||
Update_RAM_Search(); // Update_RAM_Watch() is also called.
|
||||
UpdateToolWindows();
|
||||
GUI.FrameCount++;
|
||||
}
|
||||
|
||||
|
@ -3513,6 +3521,8 @@ int WINAPI WinMain(
|
|||
|
||||
loop_exit:
|
||||
|
||||
CloseAllToolWindows();
|
||||
|
||||
Settings.StopEmulation = TRUE;
|
||||
|
||||
// stop sound playback
|
||||
|
@ -3561,6 +3571,13 @@ loop_exit:
|
|||
return msg.wParam;
|
||||
}
|
||||
|
||||
void UpdateToolWindows()
|
||||
{
|
||||
Update_RAM_Search(); //Update_RAM_Watch() is also called
|
||||
|
||||
RefreshAllToolWindows();
|
||||
}
|
||||
|
||||
void FreezeUnfreeze (int slot, bool8 freeze)
|
||||
{
|
||||
const char *filename;
|
||||
|
@ -10123,11 +10140,11 @@ INT_PTR CALLBACK DlgCheatSearchAdd(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lP
|
|||
strncpy(new_cheat->name,_tToChar(tempBuf),22);
|
||||
|
||||
new_cheat->enabled=TRUE;
|
||||
for(int byteIndex = 0; byteIndex < new_cheat->size; byteIndex++)
|
||||
{
|
||||
S9xAddCheat(new_cheat->enabled,new_cheat->saved_val,new_cheat->address+byteIndex,(new_cheat->new_val>>(8*byteIndex))&0xFF);
|
||||
strcpy(Cheat.c[Cheat.num_cheats-1].name,new_cheat->name);
|
||||
}
|
||||
for(int byteIndex = 0; byteIndex < new_cheat->size; byteIndex++)
|
||||
{
|
||||
S9xAddCheat(new_cheat->enabled,new_cheat->saved_val,new_cheat->address+byteIndex,(new_cheat->new_val>>(8*byteIndex))&0xFF);
|
||||
strcpy(Cheat.c[Cheat.num_cheats-1].name,new_cheat->name);
|
||||
}
|
||||
ret=0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -612,4 +612,6 @@ bool GetFilterHiResSupport(RenderFilter filterID);
|
|||
const TCHAR * S9xGetDirectoryT (enum s9x_getdirtype);
|
||||
RECT GetWindowMargins(HWND hwnd, UINT width);
|
||||
|
||||
void UpdateToolWindows();
|
||||
|
||||
#endif // !defined(SNES9X_H_INCLUDED)
|
||||
|
|
Loading…
Reference in New Issue