// windows.cpp : Defines the entry point for the application.
//
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <sstream>
#include "resource.h"
#undef NO_ADDRESS
#include "prog.h"
#include "proc.h"
#include "signature.h"
#include "statement.h"
#include "boomerang.h"
#include "log.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND hTopWnd, hStatusBar, hTreeView, hLogView;
HBRUSH yellowBrush, buttonBrush;
HFONT hTabBarFont, hMemoryDumpFont;
static Prog *prog = NULL;
std::map<Proc*,HTREEITEM> procItems;
HTREEITEM treeDragging = NULL;
HMENU clusterMenu = NULL, procMenu = NULL, callersMenu = NULL, callsMenu = NULL;
bool someUnknown = false;
enum { V_CODE, V_RTL, V_MIXED } view_as = V_RTL;
struct my_tab
{
const char *name;
HWND edit;
Cluster *cluster;
};
std::map<std::string, my_tab> tabWithName;
char *selectedTab = NULL;
RECT tabBarRect;
int iCluster, iProc, iDProc, iLProc, iULProc;
class MyLParam
{
public:
Proc *p;
Cluster *c;
int isCluster;
MyLParam(Cluster *c) : c(c)
{
isCluster = 1;
}
MyLParam(Proc *p) : p(p)
{
isCluster = 0;
}
};
HANDLE hDecompilerThread = NULL;
void updateDecompilerMenu()
{
if (hDecompilerThread == NULL)
{
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_SUSPEND, MF_GRAYED);
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_RESUME, MF_GRAYED);
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_TERMINATE, MF_GRAYED);
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_START, MF_ENABLED);
SendMessage(hStatusBar, SB_SETICON, 2, NULL);
}
else
{
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_SUSPEND, MF_ENABLED);
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_TERMINATE, MF_ENABLED);
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_START, MF_GRAYED);
SendMessage(hStatusBar, SB_SETICON, 2, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME)));
}
}
void updateAllTabs()
{
for (std::map<std::string, my_tab>::iterator it = tabWithName.begin(); it != tabWithName.end(); )
if ((*it).first != (*it).second.cluster->getName())
{
struct my_tab t = (*it).second;
if ((*it).first == selectedTab)
selectedTab = strdup(t.cluster->getName());
tabWithName.erase(it);
t.name = strdup(t.cluster->getName());
tabWithName[t.cluster->getName()] = t;
it = tabWithName.begin();
}
else
it++;
InvalidateRect(hTopWnd, &tabBarRect, TRUE);
}
void updateTreeView()
{
HTREEITEM h = TreeView_GetRoot(hTreeView);
while (h)
{
TVITEM i;
i.hItem = h;
i.mask = TVIF_TEXT | TVIF_HANDLE | TVIF_PARAM;
char buf[1024];
i.pszText = buf;
i.cchTextMax = sizeof(buf);
TreeView_GetItem(hTreeView, &i);
if (strcmp(i.pszText, ((MyLParam*)i.lParam)->c->getName()))
{
i.mask = TVIF_TEXT;
strcpy(buf, ((MyLParam*)i.lParam)->c->getName());
TreeView_SetItem(hTreeView, &i);
}
h = TreeView_GetNextSibling(hTreeView, h);
}
for (std::map<Proc*,HTREEITEM>::iterator it = procItems.begin(); it != procItems.end(); it++)
{
TVITEM i;
i.hItem = (*it).second;
i.mask = TVIF_TEXT;
i.pszText = strdup((*it).first->getName());
TreeView_SetItem(hTreeView, &i);
}
}
void suspendDecompiler()
{
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_SUSPEND, MF_GRAYED);
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_RESUME, MF_ENABLED);
SendMessage(hStatusBar, SB_SETICON, 2, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_SUSPEND)));
SuspendThread(hDecompilerThread);
}
void resumeDecompiler()
{
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_SUSPEND, MF_ENABLED);
EnableMenuItem(GetMenu(hTopWnd), ID_DECOMPILER_RESUME, MF_GRAYED);
SendMessage(hStatusBar, SB_SETICON, 2, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME)));
ResumeThread(hDecompilerThread);
}
void generateCodeForCluster(Cluster *c);
void generateCodeForUserProc(UserProc *p);
void updateCodeView()
{
HTREEITEM h = TreeView_GetSelection(hTreeView);
if (h == NULL)
return;
TVITEM i;
i.hItem = h;
i.mask = TVIF_PARAM;
TreeView_GetItem(hTreeView, &i);
MyLParam *lp = (MyLParam*)i.lParam;
if (lp->isCluster)
{
generateCodeForCluster(lp->c);
if (lp->c->getNumChildren() == 0)
{
PROGMAP::const_iterator it;
bool found = false;
for (Proc *proc = prog->getFirstProc(it); proc; proc = prog->getNextProc(it))
if (proc->getCluster() == lp->c)
{
found = true;
break;
}
if (!found)
{
EnableMenuItem(GetMenu(hTopWnd), ID_VIEW_DELETECLUSTER, MF_ENABLED);
if (clusterMenu)
EnableMenuItem(clusterMenu, ID_VIEW_DELETECLUSTER, MF_ENABLED);
}
}
}
else
{
UserProc *u = dynamic_cast<UserProc*>(lp->p);
if (u)
generateCodeForUserProc(u);
}
}
void saveUndoPoint()
{
return; // Possibly Mike broke it
if (prog)
{
prog->takeMemo();
if (prog->canRestore())
EnableMenuItem(GetMenu(hTopWnd), ID_EDIT_UNDO, MF_ENABLED);
else
EnableMenuItem(GetMenu(hTopWnd), ID_EDIT_UNDO, MF_GRAYED);
EnableMenuItem(GetMenu(hTopWnd), ID_EDIT_REDO, MF_GRAYED);
}
}
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK StatusBar(HWND, UINT, WPARAM, LPARAM);
WNDPROC oldStatusBarProc = NULL;
LRESULT CALLBACK TreeView(HWND, UINT, WPARAM, LPARAM);
WNDPROC oldTreeViewProc = NULL;
LRESULT CALLBACK TabEdit(HWND, UINT, WPARAM, LPARAM);
WNDPROC oldTabEditProc = NULL;
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK NewProject(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK DebugOptions(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK DecodeOptions(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK DecompileOptions(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK Decoding(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ProcProperties(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK SymbolTable(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK MemoryDump(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
char filename[MAX_PATH];
GetCurrentDirectory(sizeof(filename), filename);
strcat(filename, "\\");
Boomerang::get()->setProgPath(filename);
strcat(filename, "output");
Boomerang::get()->setOutputPath(filename);
InitCommonControls();
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_BOOMERANG, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_BOOMERANG);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
#define LOG_SIZE 1024*92
char log[LOG_SIZE], *plog = log;
class WindowLogger : public Log
{
public:
WindowLogger() : Log() { }
virtual Log &operator<<(const char *pstr)
{
if (pstr == NULL)
return *this;
char *str = new char[strlen(pstr) + 1024], *p2 = str;
for (const char *p1 = pstr; *p1; p1++)
if (*p1 != '\n')
*p2++ = *p1;
else
{
*p2++ = '\r';
*p2++ = '\n';
}
*p2 = 0;
if (strlen(str) + plog - log < LOG_SIZE)
{
strcpy(plog, str);
plog += strlen(str);
}
else
{
memmove(log, log + 1024, LOG_SIZE - 1024);
plog -= 1024;
if (strlen(str) + plog - log < LOG_SIZE)
{
strcpy(plog, str);
plog += strlen(str);
}
}
SetWindowText(hLogView, log);
SendMessage(hLogView, WM_VSCROLL, SB_BOTTOM, 0);
return *this;
}
virtual ~WindowLogger() {};
};
void OpenProject();
void SaveProject();
void CloseProject();
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_BOOMERANG);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCTSTR)IDC_BOOMERANG;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_BOOMERANG);
return RegisterClassEx(&wcex);
}
void addNewTab(Cluster *cluster);
HFONT MyCreateFont( void )
{
CHOOSEFONT cf;
LOGFONT lf;
HFONT hfont;
// Initialize members of the CHOOSEFONT structure.
cf.lStructSize = sizeof(CHOOSEFONT);
cf.hwndOwner = (HWND)NULL;
cf.hDC = (HDC)NULL;
cf.lpLogFont = &lf;
cf.iPointSize = 0;
cf.Flags = CF_SCREENFONTS;
cf.rgbColors = RGB(0,0,0);
cf.lCustData = 0L;
cf.lpfnHook = (LPCFHOOKPROC)NULL;
cf.lpTemplateName = (LPSTR)NULL;
cf.hInstance = (HINSTANCE) NULL;
cf.lpszStyle = (LPSTR)NULL;
cf.nFontType = SCREEN_FONTTYPE;
cf.nSizeMin = 0;
cf.nSizeMax = 0;
// Display the CHOOSEFONT common-dialog box.
ChooseFont(&cf);
// Create a logical font based on the user's
// selection and return a handle identifying
// that font.
OpenClipboard(hTopWnd);
EmptyClipboard();
HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, 8192);
char *buf = (char*)GlobalLock(hglbCopy);
buf[0] = 0;
for (unsigned i = 0; i < sizeof(lf); i++)
sprintf(buf + strlen(buf), "0x%02X, ", ((unsigned char*)&lf)[i]);
GlobalUnlock(hglbCopy);
SetClipboardData(CF_TEXT, hglbCopy);
CloseClipboard();
hfont = CreateFontIndirect(cf.lpLogFont);
return (hfont);
}
void setupDecompiler();
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
hTopWnd = hWnd;
hStatusBar = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0, hWnd, NULL, hInstance, NULL);
oldStatusBarProc = (WNDPROC)SetWindowLongPtr (hStatusBar, GWLP_WNDPROC, (LONG_PTR)StatusBar);
SetTimer(hStatusBar, 1, 1000, NULL);
RECT r, rsb;
GetClientRect(hWnd, &r);
GetClientRect(hStatusBar, &rsb);
int parts[] = { rsb.right / 2, rsb.right / 2 + 200, rsb.right / 2 + 232, -1 };
SendMessage(hStatusBar, SB_SETPARTS, 4, (LPARAM) parts);
hTreeView = CreateWindowEx(0, WC_TREEVIEW, NULL, WS_CHILD | WS_DLGFRAME | WS_VISIBLE | TVS_EDITLABELS | TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS, r.right - 200, 0, 200, r.bottom - rsb.bottom, hWnd, NULL, hInstance, NULL);
oldTreeViewProc = (WNDPROC)SetWindowLongPtr (hTreeView, GWLP_WNDPROC, (LONG_PTR)TreeView);
HIMAGELIST himglist = ImageList_Create(16, 16, ILC_COLOR4, 5, 1);
iCluster = ImageList_AddIcon(himglist, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CLUSTER)));
iProc = ImageList_AddIcon(himglist, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PROC)));
iDProc = ImageList_AddIcon(himglist, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DPROC)));
iLProc = ImageList_AddIcon(himglist, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LPROC)));
iULProc = ImageList_AddIcon(himglist, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ULPROC)));
TreeView_SetImageList(hTreeView, himglist, TVSIL_NORMAL);
yellowBrush = CreateSolidBrush(RGB(255, 255, 200));
buttonBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
unsigned char lf_bits[] = { 0xF3, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x22, 0x41, 0x72, 0x69, 0x61, 0x6C, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, };
hTabBarFont = CreateFontIndirect((LOGFONT*)lf_bits);
LOGFONT mmfont;
memcpy(&mmfont, lf_bits, sizeof(mmfont));
strcpy(mmfont.lfFaceName, "OEM fixed font");
mmfont.lfPitchAndFamily &= ~3;
mmfont.lfPitchAndFamily |= FIXED_PITCH;
hMemoryDumpFont = CreateFontIndirect(&mmfont);
hLogView = CreateWindowEx(0, WC_EDIT, NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_DLGFRAME
| ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
0, r.bottom - rsb.bottom - 200, r.right - 200, 200, hTopWnd, NULL, hInst, NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
setupDecompiler();
return TRUE;
}
void selectTab(const char *name)
{
if (selectedTab)
{
if (!strcmp(selectedTab, name))
return;
ShowWindowAsync(tabWithName[selectedTab].edit, SW_HIDE);
}
selectedTab = strdup(name);
ShowWindowAsync(tabWithName[selectedTab].edit, SW_SHOW);
InvalidateRect(hTopWnd, &tabBarRect, TRUE);
}
void updateTab(const char *name)
{
Cluster *c = tabWithName[name].cluster;
const char *path = c->getOutPath((view_as == V_CODE || view_as == V_MIXED) ? "c" : "rtl");
std::ifstream in(path, std::ios_base::binary);
if (in.is_open())
{
in.seekg(0, std::ios_base::end);
int n = in.tellg();
in.seekg(0, std::ios_base::beg);
char *buf = new char[n];
in.read(buf, n);
in.close();
SendMessage(tabWithName[c->getName()].edit, WM_SETTEXT, 0, (LPARAM)buf);
}
}
void generateCodeForClusterThread(Cluster *c)
{
char buf[1024];
sprintf(buf, "Generating code for cluster %s", c->getName());
SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)buf);
if (view_as == V_CODE)
prog->generateCode(c);
else if (view_as == V_RTL)
prog->generateRTL(c);
else if (view_as == V_MIXED)
prog->generateCode(c, NULL, true);
selectTab(c->getName());
updateTab(c->getName());
SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)"Done");
ExitThread(0);
}
void generateCodeForCluster(Cluster *c)
{
addNewTab(c);
DWORD id;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)generateCodeForClusterThread, (LPVOID)c, 0, &id);
}
void generateCodeForAllThread(void *n)
{
char buf[1024];
sprintf(buf, "Generating code...");
SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)buf);
prog->generateCode();
if (selectedTab)
updateTab(selectedTab);
SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)"Done");
ExitThread(0);
}
void generateCodeForAll()
{
DWORD id;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)generateCodeForAllThread, 0, 0, &id);
}
void generateCodeForUserProcThread(UserProc *proc)
{
if (prog == NULL)
return;
char buf[1024];
sprintf(buf, "Generating code for proc %s", proc->getName());
SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)buf);
if (view_as == V_CODE)
prog->generateCode(proc->getCluster(), proc);
else if (view_as == V_RTL)
prog->generateRTL(proc->getCluster(), proc);
else if (view_as == V_MIXED)
prog->generateCode(proc->getCluster(), proc, true);
selectTab(proc->getCluster()->getName());
updateTab(proc->getCluster()->getName());
SendMessage(hStatusBar, SB_SETTEXT, 0, (LPARAM)"Done");
ExitThread(0);
}
void generateCodeForUserProc(UserProc *proc)
{
addNewTab(proc->getCluster());
DWORD id;
HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)generateCodeForUserProcThread, (LPVOID)proc, 0, &id);
}
void closeTab(const char *name)
{
for (std::map<std::string, struct my_tab>::iterator it = tabWithName.begin(); it != tabWithName.end(); it++)
if ((*it).first == name)
{
DestroyWindow((*it).second.edit);
if (!strcmp(selectedTab, name))
selectedTab = NULL;
tabWithName.erase(it);
break;
}
InvalidateRect(hTopWnd, &tabBarRect, TRUE);
}
void closeAllTabs()
{
for (std::map<std::string, struct my_tab>::iterator it = tabWithName.begin(); it != tabWithName.end(); it++)
{
DestroyWindow((*it).second.edit);
}
tabWithName.clear();
selectedTab = NULL;
InvalidateRect(hTopWnd, &tabBarRect, TRUE);
}
void addNewTab(Cluster *cluster)
{
const char *name = cluster->getName();
if (tabWithName.find(name) != tabWithName.end())
return;
struct my_tab tab;
tab.name = strdup(name);
tab.cluster = cluster;
RECT r, rsb;
GetClientRect(hTopWnd, &r);
GetClientRect(hStatusBar, &rsb);
tab.edit = CreateWindowEx(0, WC_EDIT, NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_DLGFRAME
| ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, tabBarRect.bottom, r.right - 200, r.bottom - rsb.bottom - tabBarRect.bottom - 200, hTopWnd, NULL, hInst, NULL);
oldTabEditProc = (WNDPROC)SetWindowLongPtr (tab.edit, GWLP_WNDPROC, (LONG_PTR)TabEdit);
tabWithName[name] = tab;
if (selectedTab == NULL)
selectTab(name);
InvalidateRect(hTopWnd, &tabBarRect, TRUE);
}
void drawTabBar(HDC hdc)
{
RECT r = tabBarRect;
FillRect(hdc, &r, yellowBrush);
r.left += 4;
for (std::map<std::string, struct my_tab>::iterator it = tabWithName.begin(); it != tabWithName.end(); it++)
{
const char *name = (*it).second.name;
DrawText(hdc, name, -1, &r, DT_CALCRECT | DT_LEFT | DT_TOP);
r.bottom++;
r.right += 4;
if (selectedTab && !strcmp(name, selectedTab))
{
r.left -= 4;
r.top++;
FillRect(hdc, &r, buttonBrush);
r.left += 4;
r.top--;
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
DrawText(hdc, name, -1, &r, DT_LEFT | DT_TOP);
MoveToEx(hdc, r.right, r.top + 1, NULL);
LineTo(hdc, r.right, r.bottom - 1);
}
else
{
SetBkColor(hdc, RGB(255, 255, 200));
DrawText(hdc, name, -1, &r, DT_LEFT | DT_TOP);
MoveToEx(hdc, r.right, r.top + 2, NULL);
LineTo(hdc, r.right, r.bottom - 3);
}
r.left += r.right - r.left + 4;
r.right = r.left + 10;
}
}
void handleTabBarPress(int xPos)
{
HDC hdc = GetDC(hTopWnd);
RECT r = tabBarRect;
r.left += 4;
for (std::map<std::string, struct my_tab>::iterator it = tabWithName.begin(); it != tabWithName.end(); it++)
{
const char *name = (*it).second.name;
DrawText(hdc, name, -1, &r, DT_CALCRECT | DT_LEFT | DT_TOP);
r.bottom++;
r.right += 4;
if (xPos >= r.left && xPos < r.right)
{
selectTab(name);
break;
}
r.left += r.right - r.left + 4;
r.right = r.left + 10;
}
ReleaseDC(hTopWnd, hdc);
}
Proc *selectedProc()
{
HTREEITEM h = TreeView_GetSelection(hTreeView);
TVITEM it;
it.hItem = h;
it.mask = TVIF_HANDLE;
if (!TreeView_GetItem(hTreeView, &it))
return NULL;
MyLParam *lp = (MyLParam*)it.lParam;
if (lp->isCluster)
return NULL;
return lp->p;
}
LRESULT CALLBACK StatusBar(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
break;
case WM_LBUTTONUP:
{
int parts[5];
SendMessage(hWnd, SB_GETPARTS, 5, (LPARAM)parts);
if (LOWORD(lParam) > parts[1] && LOWORD(lParam) < parts[2])
{
if ((HICON)SendMessage(hWnd, SB_GETICON, 2, 0) == LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME)) ||
(HICON)SendMessage(hWnd, SB_GETICON, 2, 0) == LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME1)))
{
SendMessage(hWnd, SB_SETICON, 2, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_SUSPEND)));
suspendDecompiler();
}
else
{
SendMessage(hWnd, SB_SETICON, 2, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME)));
resumeDecompiler();
}
}
}
break;
case WM_TIMER:
if ((HICON)SendMessage(hWnd, SB_GETICON, 2, 0) == LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME)))
{
SendMessage(hWnd, SB_SETICON, 2, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME1)));
}
else if ((HICON)SendMessage(hWnd, SB_GETICON, 2, 0) == LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME1)))
{
SendMessage(hWnd, SB_SETICON, 2, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_RESUME)));
}
break;
case WM_RBUTTONDOWN:
break;
case WM_MOUSEMOVE:
break;
}
return CallWindowProc(oldStatusBarProc, hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK TreeView(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
RECT r;
TVHITTESTINFO tvhti;
TVITEM tvi;
MyLParam *lp;
switch (uMsg)
{
case WM_LBUTTONUP:
if (treeDragging)
{
TreeView_SetInsertMark(hTreeView, NULL, TRUE);
TVHITTESTINFO tvh;
tvh.pt.x = LOWORD(lParam);
tvh.pt.y = HIWORD(lParam);
TreeView_HitTest(hTreeView, &tvh);
if (tvh.hItem && tvh.hItem != treeDragging)
{
TVINSERTSTRUCT tvi;
tvi.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvi.item.hItem = treeDragging;
char buf[1024];
tvi.item.pszText = buf;
tvi.item.cchTextMax = sizeof(buf);
TreeView_GetItem(hTreeView, &tvi.item);
TVITEM tv;
tv.mask = TVIF_PARAM;
tv.hItem = tvh.hItem;
TreeView_GetItem(hTreeView, &tv);
MyLParam *tp = (MyLParam*)tv.lParam;
if (tp->isCluster)
{
tvi.hParent = tvh.hItem;
tvi.hInsertAfter = TVI_FIRST;
}
else
{
tvi.hParent = TreeView_GetParent(hTreeView, tvh.hItem);
tvi.hInsertAfter = tvh.hItem;
}
MyLParam *p = (MyLParam*)tvi.item.lParam;
if (!p->isCluster || tp->isCluster)
{
HTREEITEM h = TreeView_InsertItem(hTreeView, &tvi);
TreeView_DeleteItem(hTreeView, treeDragging);
if (p->isCluster)
{
p->c->getParent()->removeChild(p->c);
tp->c->addChild(p->c);
}
else
{
procItems[p->p] = h;
if (tp->isCluster)
{
p->p->setCluster(tp->c);
}
else
{
p->p->setCluster(tp->p->getCluster());
}
}
}
}
treeDragging = NULL;
}
break;
case WM_RBUTTONDOWN:
tvhti.pt.x = LOWORD(lParam);
tvhti.pt.y = HIWORD(lParam);
TreeView_HitTest(hTreeView, &tvhti);
tvi.hItem = tvhti.hItem;
tvi.mask = TVIF_PARAM;
TreeView_GetItem(hTreeView, &tvi);
GetWindowRect(hWnd, &r);
lp = (MyLParam*)tvi.lParam;
if (lp->isCluster)
{
if (clusterMenu == NULL)
{
clusterMenu = CreatePopupMenu();
AppendMenu(clusterMenu, MF_STRING, ID_VIEW_RENAME, "&Rename");
AppendMenu(clusterMenu, MF_STRING, ID_VIEW_NEWCLUSTER, "&New Cluster");
AppendMenu(clusterMenu, MF_STRING | MF_GRAYED, ID_VIEW_DELETECLUSTER, "&Delete Cluster");
}
TreeView_SelectItem(hTreeView, tvhti.hItem);
TrackPopupMenu(clusterMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, r.left + LOWORD(lParam), r.top + HIWORD(lParam), 0, hTopWnd, NULL);
}
else
{
UserProc *u = dynamic_cast<UserProc*>(lp->p);
if (procMenu != NULL)
{
DestroyMenu(procMenu);
}
callersMenu = CreatePopupMenu();
callsMenu = CreatePopupMenu();
procMenu = CreatePopupMenu();
AppendMenu(procMenu, MF_STRING, ID_VIEW_RENAME, "&Rename");
AppendMenu(procMenu, MF_SEPARATOR, 0, 0);
AppendMenu(procMenu, MF_STRING | MF_POPUP, (UINT_PTR)callersMenu, "&Callers");
AppendMenu(procMenu, MF_STRING | MF_POPUP, (UINT_PTR)callsMenu, "C&alls");
AppendMenu(procMenu, MF_STRING, ID_VIEW_PROPERTIES, "&Properties");
while (DeleteMenu(callersMenu, 0, MF_BYPOSITION))
;
std::set<CallStatement*> &callers = lp->p->getCallers();
int n = 33001;
for (std::set<CallStatement*>::iterator it = callers.begin(); it != callers.end(); it++, n++)
AppendMenu(callersMenu, MF_STRING, n, (*it)->getProc()->getName());
while (DeleteMenu(callsMenu, 0, MF_BYPOSITION))
;
if (u)
{
std::list<Proc*> &calls = u->getCallees();
n = 34001;
for (std::list<Proc*>::iterator it = calls.begin(); it != calls.end(); it++, n++)
AppendMenu(callsMenu, MF_STRING, n, (*it)->getName());
}
TreeView_Select(hTreeView, tvhti.hItem, TVGN_CARET);
TrackPopupMenu(procMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, r.left + LOWORD(lParam), r.top + HIWORD(lParam), 0, hTopWnd, NULL);
}
break;
case WM_MOUSEMOVE:
if (treeDragging)
{
TVHITTESTINFO tvh;
tvh.pt.x = LOWORD(lParam);
tvh.pt.y = HIWORD(lParam);
TreeView_HitTest(hTreeView, &tvh);
if (tvh.hItem)
TreeView_SetInsertMark(hTreeView, tvh.hItem, TRUE);
else
TreeView_SetInsertMark(hTreeView, NULL, TRUE);
}
break;
default:
return CallWindowProc(oldTreeViewProc, hWnd, uMsg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK TabEdit(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static Statement *stmt;
static Exp *exp;
//std::map<std::string, my_tab>::iterator it;
//for (it = tabWithName.begin(); it != tabWithName.end(); it++)
// if ((*it).second.edit == hWnd)
// break;
switch (uMsg)
{
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_STMT_PROPAGATE_TO:
stmt->propagateTo(-1);
stmt->getProc()->updateBlockVars();
updateCodeView();
break;
}
break;
case WM_LBUTTONUP:
break;
case WM_RBUTTONDOWN:
{
DWORD d = SendMessage(hWnd, EM_CHARFROMPOS, 0, lParam);
int ch = LOWORD(d);
int line = HIWORD(d);
Proc *p = selectedProc();
if (p == NULL)
break; // don't currently support right click in cluster view
UserProc *u = dynamic_cast<UserProc*>(p);
if (u == NULL)
break;
stmt = u->getStmtAtLex(ch, -1);
if (stmt == NULL)
break;
exp = stmt->getExpAtLex(ch, -1);
HMENU editMenu = CreatePopupMenu();
AppendMenu(editMenu, MF_STRING, ID_STMT_PROPAGATE_TO, "&Propagate to this statement");
RECT r;
GetWindowRect(hWnd, &r);
TrackPopupMenu(editMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON, r.left + LOWORD(lParam), r.top + HIWORD(lParam), 0, hWnd, NULL);
DestroyMenu(editMenu);
}
break;
case WM_MOUSEMOVE:
break;
}
return CallWindowProc(oldTabEditProc, hWnd, uMsg, wParam, lParam);
}
//
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
TEXTMETRIC tm;
LPNMTREEVIEW pnmtv;
LPNMTVDISPINFO ptvdi;
switch (message)
{
case WM_SIZE:
{
RECT r;
RECT rsb;
GetClientRect(hTopWnd, &r);
GetClientRect(hStatusBar, &rsb);
SetWindowPos(hTreeView, 0, r.right - 200, 0, 200, r.bottom - rsb.bottom, SWP_NOZORDER);
SetWindowPos(hStatusBar, 0, 0, r.bottom - rsb.bottom, r.right, rsb.bottom, SWP_NOZORDER);
SetWindowPos(hLogView, 0, 0, r.bottom - rsb.bottom - 200, r.right - 200, 200, SWP_NOZORDER);
for (std::map<std::string, my_tab>::iterator it = tabWithName.begin(); it != tabWithName.end(); it++)
{
SetWindowPos((*it).second.edit, 0, 0, tabBarRect.bottom, r.right - 200, r.bottom - rsb.bottom - tabBarRect.bottom - 200, SWP_NOZORDER);
}
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
if (selectedTab && wmEvent == EN_CHANGE && (HWND)lParam == tabWithName[selectedTab].edit)
{
updateTab(selectedTab);
}
if (wmId > 33000)
{
char buf[1024];
MENUITEMINFO mi;
mi.cbSize = sizeof(mi);
mi.fMask = MIIM_STRING;
mi.cch = sizeof(buf);
mi.dwTypeData = buf;
if (GetMenuItemInfo(procMenu, wmId, FALSE, &mi))
{
Proc *p = prog->findProc(buf);
if (p && procItems.find(p) != procItems.end())
TreeView_SelectItem(hTreeView, procItems[p]);
}
}
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case ID_NEW_PROJECT:
if (DialogBox(hInst, (LPCTSTR)IDD_NEWPROJECT, hWnd, (DLGPROC)NewProject) == IDOK)
if (DialogBox(hInst, (LPCTSTR)IDD_DECODING, hWnd, (DLGPROC)Decoding) == IDOK)
;
break;
case ID_DECODER_SHOWCOVERAGE:
DialogBox(hInst, (LPCTSTR)IDD_DECODING, hWnd, (DLGPROC)Decoding);
break;
case ID_OPEN_PROJECT:
OpenProject();
break;
case ID_FILE_SAVE:
SaveProject();
break;
case ID_FILE_CLOSE:
CloseProject();
break;
case ID_HELP_BOOMERANGWEBSITE:
ShellExecute(NULL, "open", "[url]http://boomerang.sourceforge.net/[/url]", NULL, NULL, SW_SHOW);
break;
case ID_HELP_BOOMERANGFAQ:
ShellExecute(NULL, "open", "[url]http://boomerang.sourceforge.net/FAQ.html[/url]", NULL, NULL, SW_SHOW);
break;
case ID_LOADER_SYMBOLTABLE:
DialogBox(hInst, (LPCTSTR)IDD_SYMBOLTABLE, hWnd, (DLGPROC)SymbolTable);
break;
case ID_LOADER_MEMORYDUMP:
DialogBox(hInst, (LPCTSTR)IDD_MEMORYDUMP, hWnd, (DLGPROC)MemoryDump);
break;
case ID_DECOMPILER_START:
if (hDecompilerThread == NULL)
{
saveUndoPoint();
prog->decompile();
}
break;
case ID_DECOMPILER_SUSPEND:
if (hDecompilerThread)
{
suspendDecompiler();
}
break;
case ID_DECOMPILER_RESUME:
if (hDecompilerThread)
{
resumeDecompiler();
}
break;
case ID_DECOMPILER_TERMINATE:
if (hDecompilerThread)
{
TerminateThread(hDecompilerThread, 0);
hDecompilerThread = NULL;
updateDecompilerMenu();
}
break;
case ID_SETOUTPUTPATH:
{
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
char buf[MAX_PATH];
buf[0] = 0;
ofn.lpstrFile = buf;
ofn.nMaxFile = MAX_PATH;
if (GetOpenFileName(&ofn))
{
Boomerang::get()->setOutputDirectory(buf);
}
}
break;
case ID_VIEW_CODE:
if (view_as != V_CODE)
{
view_as = V_CODE;
updateCodeView();
}
break;
case ID_VIEW_RTL:
if (view_as != V_RTL)
{
view_as = V_RTL;
updateCodeView();
}
break;
case ID_VIEW_MIXED:
if (view_as != V_MIXED)
{
view_as = V_MIXED;
updateCodeView();
}
break;
case ID_VIEW_RENAME:
TreeView_EditLabel(hTreeView, TreeView_GetSelection(hTreeView));
break;
case ID_TO_SSA:
{
UserProc *u = dynamic_cast<UserProc*>(selectedProc());
if (u == NULL)
break;
Boomerang::get()->noDecompile = true;
u->decompile(new CycleList);
Boomerang::get()->noDecompile = false;
updateCodeView();
}
break;
case ID_FROM_SSA:
{
UserProc *u = dynamic_cast<UserProc*>(selectedProc());
if (u == NULL)
break;
u->fromSSAform();
updateCodeView();
}
break;
case ID_PROP_REGS:
{
UserProc *u = dynamic_cast<UserProc*>(selectedProc());
if (u == NULL)
break;
u->propagateAtDepth(0);
updateCodeView();
}
break;
case ID_VIEW_NEWCLUSTER:
{
TVINSERTSTRUCT tvi;
tvi.hParent = TreeView_GetRoot(hTreeView);
tvi.hInsertAfter = TVI_LAST;
tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvi.item.state = tvi.item.stateMask = TVIS_EXPANDED;
tvi.item.pszText = "New Cluster";
tvi.item.iImage = tvi.item.iSelectedImage = iCluster;
MyLParam *p = new MyLParam(new Cluster());
tvi.item.lParam = (LPARAM)p;
prog->getRootCluster()->addChild(p->c);
HTREEITEM h = TreeView_InsertItem(hTreeView, &tvi);
TreeView_EditLabel(hTreeView, h);
}
break;
case ID_VIEW_DELETECLUSTER:
{
TVITEM tvi;
tvi.hItem = TreeView_GetSelection(hTreeView);
tvi.mask = TVIF_PARAM;
TreeView_GetItem(hTreeView, &tvi);
MyLParam *p = (MyLParam*)tvi.lParam;
if (p->isCluster && p->c != prog->getRootCluster())
{
p->c->getParent()->removeChild(p->c);
TreeView_DeleteItem(hTreeView, tvi.hItem);
closeTab(p->c->getName());
}
}
break;
case ID_VIEW_PROPERTIES:
{
Proc *p = selectedProc();
if (p)
if (p->isLib())
DialogBox(hInst, (LPCTSTR)IDD_LPROCPROPERTIES, hWnd, (DLGPROC)ProcProperties);
else
DialogBox(hInst, (LPCTSTR)IDD_PROCPROPERTIES, hWnd, (DLGPROC)ProcProperties);
}
break;
case ID_DECODER_OPTIONS:
DialogBox(hInst, (LPCTSTR)IDD_DECODEOPTIONS, hWnd, (DLGPROC)DecodeOptions);
break;
case ID_DECOMPILER_OPTIONS:
DialogBox(hInst, (LPCTSTR)IDD_DECOMPILEOPTIONS, hWnd, (DLGPROC)DecompileOptions);
break;
case ID_CODEGENERATOR_REGENERATEALL:
generateCodeForAll();
break;
case ID_EDIT_UNDO:
prog->restoreMemo();
if (!prog->canRestore())
EnableMenuItem(GetMenu(hTopWnd), ID_EDIT_UNDO, MF_GRAYED);
EnableMenuItem(GetMenu(hTopWnd), ID_EDIT_REDO, MF_ENABLED);
updateAllTabs();
updateTreeView();
updateCodeView();
break;
case ID_EDIT_REDO:
prog->restoreMemo(true);
if (!prog->canRestore(true))
EnableMenuItem(GetMenu(hTopWnd), ID_EDIT_REDO, MF_GRAYED);
EnableMenuItem(GetMenu(hTopWnd), ID_EDIT_UNDO, MF_ENABLED);
updateAllTabs();
updateTreeView();
updateCodeView();
break;
case ID_EDIT_COPY:
if (selectedTab)
SendMessage(tabWithName[selectedTab].edit, WM_COPY, 0, 0);
break;
case ID_EDIT_PASTE:
if (selectedTab)
SendMessage(tabWithName[selectedTab].edit, WM_PASTE, 0, 0);
break;
case ID_EDIT_SELECTALL:
if (selectedTab)
SendMessage(tabWithName[selectedTab].edit, EM_SETSEL, 0, -1);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
SelectObject(hdc, hTabBarFont);
GetTextMetrics(hdc, &tm);
GetClientRect(hWnd, &tabBarRect);
tabBarRect.right -= 200;
tabBarRect.bottom = tm.tmHeight;
drawTabBar(hdc);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_LBUTTONDOWN:
if (GET_Y_LPARAM(lParam) <= tabBarRect.bottom)
handleTabBarPress(GET_X_LPARAM(lParam));