Source file: /~heha/hs/borg.zip/DASM.CPP

/************************************************************************
*		   Dasm.cpp						*
*									*
*	       Borg Disassembler					*
*		     v2.24						*
*		  by Cronos						*
*									*
* Contributors:								*
* Thanks to Mark Ogden for many bugfixes and mods for assembly under	*
* VC++, in its early stages (v2 beta builds). Also changes from		*
* wvsprintf to wsprintf to allow compilation under VC++.		*
* Thanks to Eugen Polukhin for some interesting alternate code and	*
* ideas around v2.11 and feedback on fonts, etc.			*
* Thanks to Pawe3 Kunio for a lot of coding ideas and advice re C++	*
* usage around v2.22							*
* Thanks to Howard Chu for some coding additions on default names, and	*
* more block functions							*
************************************************************************/

/************************************************************************
* dasm.cpp								*
* - this whole file is a declaration and global routine dumping area	*
* - it includes winmain and the main message callback routine, along	*
*   with initialisation code and the registry read/write code, odd	*
*   dialog boxes and helper functions for the main routines. The whole	*
*   file is a bit of a mish-mash of stuff which hasnt found its way	*
*   elsewhere.								*
* - a lot of the code in here has grown, and i mean grown from the	*
*   ground up, and at some point it will require reorganisation, or	*
*   maybe that point was long ago....					*
************************************************************************/
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>

//#include "menuids.rh"
#include "resource.h"
#include "exeload.h"
#include "data.h"
#include "schedule.h"
#include "proctab.h"
#include "disasm.h"
#include "dasm.h"
#include "gname.h"
#include "xref.h"
#include "relocs.h"
#include "srch.h"
#include "disio.h"
#include "range.h"
#include "decrypt.h"
#include "registry.h"
#include "help.h"
#include "database.h"
#include "user_fn.h"
#include "debug.h"	// for ShowLastError()

//#define _CRTDBG_MAP_ALLOC 
//#include <crtdbg.h>

/************************************************************************
* decaration dumping ground........					*
************************************************************************/
//CRITICAL_SECTION cs;
//volatile bool KillThread;
//volatile bool InThread;
globaloptions options;
LOGFONT UserFont;

fileloader floader;
dataseg *dta;		// Segmente
schedule scheduler;
disasm *dsm;
//disio dio;
xref *xrefs;
gname *import;
gname *expt;
gname *name;		// all other names
relocs *reloc;
range blk;
decrypt decrypter;

char winname[300];
HINSTANCE hInst;
//HANDLE ThreadHandle;
//DWORD ThreadId;
HWND Toolbar;		// comctl32.dll's toolbar, most handled like TOOLSTAT.PAS
HWND Status;		// comctl32.dll's status bar
HWND MainWnd;		// main (frame) window containing Toolbar and Status too
HWND View[2];		// up to two viewer windows on client area of MainWnd
HWND KBHand;		// handle of focused modeless dialog box (keyboard handler)
HACCEL Accel;		// Accelerator Table

//POINT mainwndsize;
HFONT Font;		// disassembly font
bool StockFont;		// whether to free the font
POINT CharBox;		// font size, for hit testing
HMENU rmenu;		// right-click (and Shift+F10) context menu
//bool charinputenabled=false;

char szWinName[]="Dasm";
char program_name[]="Borg Disassembler";
TCHAR current_exe_name[MAX_PATH];


void CalcClientRect(RECT &R) {
// Calculates the client rectangle of MainWnd,
// removing a tool bar and the status line from height
 RECT R2;
 GetClientRect(MainWnd,&R);
 if (Toolbar) {
  GetWindowRect(Toolbar,&R2);
  ScreenToClient(MainWnd,(LPPOINT)(&R2.right));	// convert the "bottom" member
  R.top=R2.bottom;
 }
 if (Status) {
  GetWindowRect(Status,&R2);
  ScreenToClient(MainWnd,(LPPOINT)(&R2.left));	// convert the "top" member
  R.bottom=R2.top;
 }
}

void InitStruct(LPVOID mem, DWORD size) {	// initialize most Windows structures
 ZeroMemory(mem,size);
 *(LPDWORD)mem=size;
}

/************************************************************************
* savefile_text								*
* - this is the savefile as text dialog which asks the user to select	*
*   a file for the save. The filedump is then controlled by disio	*
* - this is for text or asm saves					*
************************************************************************/
bool savefile_text(HWND,bool printaddrs,bool block) {
 TCHAR savefname[MAX_PATH];
 UINT FilterIndex;
 if (scheduler.sizelist()) {
  MessageBox(MainWnd,"There are still items to process yet","Borg Warning",
    MB_OK|MB_ICONEXCLAMATION);
  return false;
 }
 savefname[0]=0;
 if (!getfiletosave(savefname,elemof(savefname),IDS_FILTERTEXT,FilterIndex))
   return false;
 StatusMessage("Saving...");
 if (block) cvd->dumpblocktofile(savefname,printaddrs);
 else       cvd->dumptofile(savefname,printaddrs);
 StatusMessage("Saved.");
 return true;
}

/************************************************************************/
/* Calculates the (global) size of display font, for easier hit-testing */
/************************************************************************/
void SetCharBox(HDC dc) {
 TEXTMETRIC tm;
 GetTextMetrics(dc,&tm);
 CharBox.x=tm.tmAveCharWidth;
 CharBox.y=tm.tmHeight+tm.tmExternalLeading;
}

void SetFont(HFONT NewFont, bool NewStockFont) {
 if (!NewFont) return;		// don't accept non-existing fonts
 if (!StockFont && Font) DeleteObject(Font);
 Font=NewFont;
 StockFont=NewStockFont;
}

/************************************************************************
* setupfont								*
* - handles the setting up of a font (like selecting the object for	*
*   window painting and setting checkmarks on the menu, etc)		*
************************************************************************/
void setupfont(byte fontindex) {
 static UINT MenuIDs[6]={font_ansi,font_system,font_courier,font_courier10,
   font_courier12,font_user};
 int i;
 HDC hdc;
 HFONT ofont;
 HMENU hMenu;
 LOGFONT lf;

 options.font=fontindex;
 hdc=GetDC(MainWnd);
 hMenu=GetMenu(MainWnd);
 ZeroMemory(&lf,sizeof(lf));
 lstrcpy(lf.lfFaceName,T("Courier New"));
 lf.lfWeight=FW_LIGHT;
 for (i=0; i<6; i++) CheckMenuItem(hMenu,MenuIDs[i],
   options.font-ansifont==i ? MF_CHECKED : MF_UNCHECKED);
 switch (options.font) {
  case systemfont: SetFont((HFONT)GetStockObject(SYSTEM_FIXED_FONT),true); break;
  case courierfont: {
   lf.lfHeight=-MulDiv(8, GetDeviceCaps(hdc,LOGPIXELSY),72);
   SetFont(CreateFontIndirect(&lf),false);
  }break;
  case courierfont10: {
   lf.lfHeight=-MulDiv(10, GetDeviceCaps(hdc,LOGPIXELSY),72);
   SetFont(CreateFontIndirect(&lf),false);
  }break;
  case courierfont12: {
   lf.lfHeight=-MulDiv(12, GetDeviceCaps(hdc,LOGPIXELSY),72);
   SetFont(CreateFontIndirect(&lf),false);
  }break;
  case userfont: SetFont(CreateFontIndirect(&UserFont),false); break;
  default: SetFont((HFONT)GetStockObject(ANSI_FIXED_FONT),true);
 }
 ofont=(HFONT)SelectObject(hdc,Font);
 SetCharBox(hdc);
 SelectObject(hdc,ofont);
 ReleaseDC(MainWnd,hdc);
 if (View[0]) {
  SendMessage(View[0],WM_SETFONT,(WPARAM)Font,TRUE);	// let the View do the rest
  scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
 }
}

void FontSel(void) {
 CHOOSEFONT cf;
 InitStruct(&cf,sizeof(cf));
 cf.hwndOwner=MainWnd;
 cf.lpLogFont=&UserFont;
 cf.Flags=CF_INITTOLOGFONTSTRUCT|CF_FIXEDPITCHONLY|CF_FORCEFONTEXIST
   |CF_SCREENFONTS;
 if (!ChooseFont(&cf)) return;
 setupfont(userfont);
}

/************************************************************************
* changemenus								*
* erm..... everytime I added a menu function I just added another line	*
* in here :)								*
************************************************************************/
void changemenus(bool HaveProject) {
 static UINT IDmenu[]={file_save,save_asm,
   Seg_Viewer,Names_Viewer,Xrefs_Viewer,Imports_Viewer,Exports_Viewer,
   make_code,undefine_line,undefine_lines,undefine_lines_long,
   line_jumpto,line_jumptoarg2,
   make_dword,make_word,make_string,pascal_string,uc_string,up_string,dos_string,general_string,
   Name_Location,Jump_Back,argover_dec,argover_hex,argover_char,argnegate,offset_dseg,
   main_search,save_database,get_comment,
   block_top,block_bottom,block_view,block_saveasm,block_savetext,block_undefine,
   float_single,float_double,float_longdouble,arg_single,
   search_again,cm_decrypt,IDM_Close};
 static UINT IDrmenu[]={cm_decrypt,
   arg_single,float_single,float_double,float_longdouble,block_top,
   block_bottom,make_code,get_comment,
   undefine_line,undefine_lines,undefine_lines_long,line_jumpto,line_jumptoarg2,
   make_dword,make_word,make_string,pascal_string,uc_string,up_string,dos_string,general_string,
   Name_Location,Xrefs_Viewer,argover_dec,argover_hex,argover_char,argnegate,offset_dseg};
 HMENU hMenu;
 int i;

 hMenu=GetMenu(MainWnd);
 EnableMenuItem(hMenu,file_open,HaveProject?MF_GRAYED:MF_ENABLED);
 EnableMenuItem(hMenu,load_database,HaveProject?MF_GRAYED:MF_ENABLED);
 for (i=0; i<sizeof(IDmenu)/sizeof(UINT); i++) {
  EnableMenuItem(hMenu,IDmenu[i],HaveProject?MF_ENABLED:MF_GRAYED);
 }
 for (i=0; i<sizeof(IDrmenu)/sizeof(UINT); i++) {
  EnableMenuItem(rmenu,IDrmenu[i],HaveProject?MF_ENABLED:MF_GRAYED);
// eigentlich Unsinn, ist Bestandteil des View-Fensters
 }
// charinputenabled=HaveProject;
 if (View[0]) DestroyWindow(View[0]); View[0]=0;
 if (dsm) {
  delete dsm; dsm=NULL;	// Zeiger für offenes Projekt
  delete import;
  delete expt;
  delete name;
  delete dta;
  delete reloc;
  delete xrefs;
 }
 if (HaveProject) {
  RECT R;
  dsm=new disasm;
  import=new gname;
  expt=new gname;
  name=new gname;
  dta=new dataseg;
  reloc=new relocs;
  xrefs=new xref;

  CalcClientRect(R);
  View[0]=CreateWindow("BorgView",NULL,WS_CHILD|WS_VISIBLE|WS_VSCROLL,
    R.left,R.top,R.right-R.left,R.bottom-R.top,
    MainWnd,0,hInst,NULL);
  SetFocus(View[0]);
 }
}

/************************************************************************
* Thread								*
* - this is the secondary thread interface. It just keeps calling the	*
*   scheduler to process any items in the queue, until such time as the *
*   main thread wants to quit.						*
************************************************************************/
/*
void Thread(PVOID) {
 // needs to setup initial schedule list
 // continually monitor schedule list for jobs
 do {
  if (scheduler.process() && !KillThread)
    StatusMessage("Processing Completed");
  Sleep(1);
 }while (!KillThread);
 InThread=false;
 ExitThread(0);
}
*/
/************************************************************************
* StatusMessage								*
* - output a simple message to the status bar				*
************************************************************************/
void StatusMessage(char *msg) {
 /*EnterCriticalSection(&cs);*/     // was causing locks (possibly)
 Status_SetText(Status,0,0,msg);
 /*LeaveCriticalSection(&cs);	  */
}

/************************************************************************
* StatusMessageNItems							*
* - shows how many items there are left to process			*
************************************************************************/
void StatusMessageNItems(dword nolistitems) {
 static char buff[40];
 wsprintf(buff,"Items to Process: %lu",nolistitems);
 StatusMessage(buff);
}

/************************************************************************
* optionsinit								*
* - initialises the global options struct with some default values	*
************************************************************************/
void optionsinit(void) {
 options.loaddebug=true;
 options.mode16=false;
 options.mode32=false;
 options.loaddata=true;
 options.loadresources=false;
 options.cfa=true;
 options.demangle=true;
 options.processor=PROC_PENTIUM;
 options.codedetect=CD_PUSHBP|CD_EAXFROMESP|CD_MOVEAX;
 options.bgcolor=GetSysColor(COLOR_WINDOW);
 options.highcolor=RGB(0,255,0);
 options.textcolor=0;
 options.font=ansifont;
 options.readonly=false;
 options.winmax=false;
}


/************************************************************************
* TestThread								*
* - this is used on exit to wait for the secondary thread to finish.	*
* - I try every possible way of getting the thread to exit normally	*
*   before we eventually kill it in the MainWnd, WM_DESTROY handler	*
************************************************************************/
/*
bool TestThread(void){
 HWND sbox;
 bool ttest;
 sbox=CreateDialog(hInst,MAKEINTRESOURCE(Borg_Shutdown),MainWnd,shutbox);
 if (InThread)
    SetThreadPriority(ThreadHandle,THREAD_PRIORITY_TIME_CRITICAL);
 Sleep(2000);
 DestroyWindow(sbox);
 Sleep(5000);
  //EnterCriticalSection(&cs);
 ttest=InThread;
  //LeaveCriticalSection(&cs);
 return ttest;
}
*/

void RegisterFileTypes(void) {
 TCHAR fn[MAX_PATH],s[1024];
 static TCHAR proj[]="Compressed Borg Disassembly Project";	// used twice
 GetModuleFileName(NULL,fn,elemof(fn));
 wsprintf(s,"\"%s\" \"%%1\"",fn);
 if(RegSetValue(HKEY_CLASSES_ROOT,T(".dasm"),REG_SZ,proj+11,25)==ERROR_SUCCESS
 && RegSetValue(HKEY_CLASSES_ROOT,T(".dasm\\shell\\open\\command"),REG_SZ,s,
    lstrlen(s)+1)==ERROR_SUCCESS
 && RegSetValue(HKEY_CLASSES_ROOT,T(".cdasm"),REG_SZ,proj,36)==ERROR_SUCCESS
 && RegSetValue(HKEY_CLASSES_ROOT,T(".cdasm\\shell\\open\\command"),REG_SZ,s,
    lstrlen(s)+1)==ERROR_SUCCESS) {
  MessageBox(MainWnd,"Extensions .dasm and .cdasm registered.","Borg Message",MB_OK);
 }else ShowLastError();
}

/************************************************************************
* dasm									*
* - dasm is the application main window.				*
* - everything the main window does is in this routine (for now) and	*
*   where a response is quick it appears in one of its helper functions *
*   later in this file, otherwise it has been substantial enough to	*
*   warrant its own file and routines........				*
* - this is long							*
************************************************************************/
LRESULT CALLBACK dasm(HWND hwnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
// int killcount;

 MainWnd=hwnd;
 switch (Msg) {
  case WM_CREATE: {
   TCHAR *cmdline,*filename;
   bool inquote,inspace;
   optionsinit();
//   InitializeCriticalSection(&cs);
   Status=CreateStatusWindow(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP,
	"No File Loaded",hwnd,2);
//   KillThread=false;
//   InThread=false;
   rmenu=GetSubMenu(LoadMenu(hInst,MAKEINTRESOURCE(right_click_menu)),0);
   load_reg_entries();
   setupfont(options.font);
	// get one (here: the last) file name from command line
   inquote=false;
   inspace=false;
   filename=NULL;
   for (cmdline=GetCommandLine(); *cmdline; cmdline++) {
    switch (*cmdline) {
     case '"': {
      inquote=!inquote;
      *cmdline=0;
     }break;
     case ' ': {
      if (!inquote) {
       *cmdline=0;
       inspace=true;
      }
     }break;
     default: if (inspace) {
      inspace=false;
      filename=cmdline;
     }
    }
   }
	// if a file name is given, open it (as uncompressed)
   if (filename) loaddb(filename,0);
  }break;

  case WM_DROPFILES: {
   TCHAR filename[MAX_PATH];
   if (DragQueryFile((HDROP)wParam,(UINT)-1,NULL,0)!=1) {
    MessageBox(hwnd,"Dropping of multiple files is not supported.\n"
    "Borg will take only the first file.","Borg Message",
    MB_OK|MB_ICONINFORMATION);
   }
   DragQueryFile((HDROP)wParam,0,filename,elemof(filename));
   DragFinish((HDROP)wParam);
   loaddb(filename,0);
  }break;

  case WM_ACTIVATE: {
   if (View[0]) SetFocus(View[0]);
  }break;

  case WM_COMMAND: switch (LOWORD(wParam)) {
   case CM_RegisterFileTypes: RegisterFileTypes(); break;
   case IDM_Close: {
/*
    KillThread=true;
    killcount=0;
    Sleep(0);
    SetPriorityClass(ThreadHandle,HIGH_PRIORITY_CLASS);
    if (InThread) while (TestThread()) {
     killcount++;
     if (killcount>2) {
	// this is a nasty way of getting out.
	// sometimes the thread just will not exit nicely when its busy.
      if (TerminateThread(ThreadHandle,1)) {
       CloseHandle(ThreadHandle);
       break;
      }
     }
    }
*/
    if (dsm->dirty && MessageBox(hwnd,"Unsaved Data!\nClose file?","Borg",
      MB_YESNO|MB_ICONQUESTION)!=IDYES) break;
    CloseHandle(floader.efile);
    floader.efile=INVALID_HANDLE_VALUE;
    SetWindowText(hwnd,winname);
    exportsviewer(false);
    importsviewer(false);
    namesviewer(NULL);
    xrefsviewer(NULL);
    segviewer(false);
    changemenus(false);
   }break;
   case file_exit:	SendMessage(MainWnd,WM_CLOSE,0,0);		break;
   case file_save:	savefile_text(hwnd,true,false);			break;
   case get_comment:	getcomment();					break;
   case save_database:	savedb();					break;
   case load_database: {
    TCHAR szFile[MAX_PATH];
    UINT FilterIndex;
    if (getfiletoload(szFile, elemof(szFile),IDS_FILTERSAVE,FilterIndex))
      loaddb(szFile,FilterIndex);
   }break;
   case save_asm:
    if (MessageBox(hwnd,"Sorry, saving text file only",NULL,MB_OKCANCEL)==IDOK)
     savefile_text(hwnd,false,false);					break;
   case block_saveasm:
    if (MessageBox(hwnd,"Sorry, saving text file only",NULL,MB_OKCANCEL)==IDOK)
     savefile_text(hwnd,false,true);					break;
   case block_savetext:	savefile_text(hwnd,true,true);			break;
   case cm_decrypt:	decrypterdialog();				break;
   case file_open:	newfile();					break;
   case Seg_Viewer:	segviewer(true);				break;
   case Names_Viewer: {
    lptr loc;
    cvd->findcurrentaddr(&loc);
    namesviewer(&loc);
   } break;
   case Imports_Viewer:	importsviewer(true);				break;
   case Exports_Viewer:	exportsviewer(true);				break;
   case Xrefs_Viewer: {
    lptr loc;
    cvd->findcurrentaddr(&loc);
    xrefsviewer(&loc);
   } break;
   case make_code:
    scheduler.addtask(user_makecode,priority_userrequest,nlptr,NULL);	break;
   case make_dword:
    scheduler.addtask(user_makedword,priority_userrequest,nlptr,NULL);	break;
   case float_single:
    scheduler.addtask(user_makesingle,priority_userrequest,nlptr,NULL);	break;
   case float_double:
    scheduler.addtask(user_makedouble,priority_userrequest,nlptr,NULL);	break;
   case float_longdouble:
    scheduler.addtask(user_makelongdouble,priority_userrequest,nlptr,NULL);break;
   case make_word:
    scheduler.addtask(user_makeword,priority_userrequest,nlptr,NULL);	break;
   case make_string:
    scheduler.addtask(user_makestring,priority_userrequest,nlptr,NULL);	break;
   case pascal_string:
    scheduler.addtask(user_pascalstring,priority_userrequest,nlptr,NULL);break;
   case uc_string:
    scheduler.addtask(user_ucstring,priority_userrequest,nlptr,NULL);	break;
   case up_string:
    scheduler.addtask(user_upstring,priority_userrequest,nlptr,NULL);	break;
   case dos_string:
    scheduler.addtask(user_dosstring,priority_userrequest,nlptr,NULL);	break;
   case general_string:
    scheduler.addtask(user_generalstring,priority_userrequest,nlptr,NULL);break;
   case argover_dec:
    scheduler.addtask(user_argoverdec,priority_userrequest,nlptr,NULL);	break;
   case arg_single:
    scheduler.addtask(user_argsingle,priority_userrequest,nlptr,NULL);	break;
   case argover_hex:
    scheduler.addtask(user_argoverhex,priority_userrequest,nlptr,NULL);	break;
   case argnegate:
    scheduler.addtask(user_argnegate,priority_userrequest,nlptr,NULL);	break;
   case offset_dseg:
    scheduler.addtask(user_argoveroffsetdseg,priority_userrequest,nlptr,NULL);break;
   case argover_char:
    scheduler.addtask(user_argoverchar,priority_userrequest,nlptr,NULL);break;
   case undefine_line:
    scheduler.addtask(user_undefineline,priority_userrequest,nlptr,NULL);break;
   case undefine_lines:
    scheduler.addtask(user_undefinelines,priority_userrequest,nlptr,NULL);break;
   case undefine_lines_long:
    scheduler.addtask(user_undefinelines_long,priority_userrequest,nlptr,NULL);break;
   case block_undefine:
    scheduler.addtask(user_undefineblock,priority_userrequest,nlptr,NULL);break;
   case block_view:	blockview();					break;
   case block_top:
    scheduler.addtask(user_marktopblock,priority_userrequest,nlptr,NULL);break;
   case block_bottom:
    scheduler.addtask(user_markbottomblock,priority_userrequest,nlptr,NULL);break;
   case line_jumpto:
    scheduler.addtask(user_jumpto,priority_userrequest,nlptr,NULL);	break;
   case line_jumptoarg2:
    scheduler.addtask(user_jumptoarg2,priority_userrequest,nlptr,NULL);	break;
   case Name_Location:	namelocation();					break;
   case help_short:
    if (HelpShortcuts) SetActiveWindow(HelpShortcuts);
    else HelpShortcuts=CreateDialog(hInst,MAKEINTRESOURCE(help_shortcuts),hwnd,helpshortcuts);
   break;
   case help_about:
    DialogBox(hInst,MAKEINTRESOURCE(D_help_about),hwnd,habox);
   break;
   case Jump_Back:
    scheduler.addtask(user_jumpback,priority_userrequest,nlptr,NULL);
   break;
   case main_search:	searchengine();					break;
   case search_again:	searchmore();					break;
   case set_bg_color:
    if (choosecolour(options.bgcolor) && View[0]) InvalidateRect(View[0],NULL,true);
    scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
   break;
   case set_high_color:
    if (choosecolour(options.highcolor) && View[0]) InvalidateRect(View[0],NULL,true);
    scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
   break;
   case set_text_color:
    if (choosecolour(options.textcolor) && View[0]) InvalidateRect(View[0],NULL,true);
    scheduler.addtask(windowupdate,priority_window,nlptr,NULL);
   break;
   case font_system:	setupfont(systemfont);		break;
   case font_courier:	setupfont(courierfont);		break;
   case font_courier10:	setupfont(courierfont10);	break;
   case font_courier12:	setupfont(courierfont12);	break;
   case font_ansi:	setupfont(ansifont);		break;
   case font_user:	FontSel();			break;
//   default:
//	  return DefWindowProc(hwnd,Msg,wParam,lParam);
  }break;


  case WM_QUERYENDSESSION: 
   save_reg_entries();
   if (dsm && dsm->dirty && MessageBox(MainWnd,
     "Unsaved Data!\n"
     "Are you sure that you want to exit Borg?\n"
     "Hit Yes To Exit\n"
     "Hit No to Stay","Borg Disassembler",
     MB_ICONEXCLAMATION|MB_YESNO)==IDNO) return FALSE;
   return TRUE;
  case WM_CLOSE:
   if (!SendMessage(hwnd,WM_QUERYENDSESSION,0,0)) break;
//      scheduler.stopthread();
//      scheduler.addtask(quitborg,priority_quit,nlptr,NULL);
//      KillThread=true;
//      if(InThread)
//	SetThreadPriority(ThreadHandle,THREAD_PRIORITY_TIME_CRITICAL);
   DestroyWindow(MainWnd);
   return 0;
  case WM_DESTROY: {
//   if (View[0]) SendMessage(hwnd,WM_COMMAND,IDM_Close,0);
//   DeleteCriticalSection(&cs);
   PostQuitMessage(0);
  }break;
  case WM_SIZE: {
//      if(wParam==SIZE_MAXIMIZED)
//	options.winmax=true;
//      else if (wParam==SIZE_RESTORED)
//	options.winmax=false;
//      mainwndsize.top=0;
//      mainwndsize.left=0;
//      GetWindowRect(Status,&StatusWindowSize);
//      GetWindowRect(MainWnd,&mainwnd);
//      MoveWindow(Status,0,mainwndsize.bottom-StatusWindowSize.bottom+StatusWindowSize.top,
//      mainwndsize.right,StatusWindowSize.bottom-StatusWindowSize.top,true);
   if (Toolbar) SendMessage(Toolbar,Msg,wParam,lParam);	// self-sizing
   if (Status) SendMessage(Status,Msg,wParam,lParam);	// self-sizing
   if (View[0]) {	// Yet only one View window, later dividable
    RECT R;
    CalcClientRect(R);
    MoveWindow(View[0],R.left,R.top,R.right-R.left,R.bottom-R.top,TRUE);
   }
  }break;

//  case WM_REPEATNAMEVIEW:	namesviewer();	break;

//  case WM_REPEATXREFVIEW:	xrefsviewer();	break;
    // maximises window, used when the reg is read in at the start to maximise
    // the main window after initialisation of it
//    case WM_MAXITOUT:
//      ShowWindow(MainWnd,SW_MAXIMIZE);
//      break;

  default: return DefWindowProc(hwnd,Msg,wParam,lParam);
 }
 return 0;
}

int limit(int i, int u, int o) {
// limit i to the both bounds given; if o<u then return=u
 return max(min(i,o),u);
}

/****************************************************/
/* Window Procedure of (one of both) View window(s) */
/****************************************************/
LRESULT CALLBACK ViewWndProc(HWND hwnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
// Get (or create) associated ViewData for the window
 disio *vd=(disio*)GetWindowLong(hwnd,GWL_USERDATA);
 if (!vd) {
  vd=new disio(hwnd); //(PVIEWDATA)LocalAlloc(LPTR,sizeof(VIEWDATA));
  vd->MainBuff=0;
  SetWindowLong(hwnd,GWL_USERDATA,(LPARAM)vd);
 }
// distribute the messages
 switch (Msg) {

  case WM_CREATE: {
   SetScrollRange(hwnd,SB_VERT,0,VERTSCROLLRANGE,false);
   SetScrollPos(hwnd,SB_VERT,0,false);
  }break;

  case WM_SETFONT: if (lParam) InvalidateRect(hwnd,NULL,TRUE);
  case WM_SIZE: {
   RECT R;
   SCROLLINFO SI;
   GetClientRect(hwnd,&R);
   vd->size.x=(R.right +CharBox.x-1)/CharBox.x;	// rounding up
   vd->size.y=(R.bottom+CharBox.y-1)/CharBox.y;
   // (re)allocate space for disassembly lines
   UINT alloc=sizeof(dasm_line)*vd->size.y;
   vd->MainBuff=(dasm_line*)(
     vd->MainBuff ? LocalReAlloc(vd->MainBuff,alloc,LMEM_ZEROINIT) : LocalAlloc(LPTR,alloc));
   // correct hpos
   vd->hpos=limit(vd->hpos,0,MAX_LENGTH-vd->size.x);
   // correct the horizontal scroll bar
   SI.cbSize=sizeof(SI);
   SI.fMask=SIF_ALL;
   SI.nMin=0;
   SI.nMax=MAX_LENGTH;
   SI.nPage=vd->size.x;
   SI.nPos=vd->hpos;
   SetScrollInfo(hwnd,SB_HORZ,&SI,TRUE);
  }break;

  case WM_SETFOCUS: {
   cvd=vd;	// set global pointer to focused window
  }break;

  case WM_PAINT: {
   vd->DoPaint();
  }break;

  case WM_VSCROLL: {
   lptr scrll;
   switch (LOWORD(wParam)) {
    case SB_LINEUP:
     scrll.assign(0,(dword)-1);
     scheduler.addtask(scrolling,priority_userrequest,scrll,NULL);
    break;
    case SB_LINEDOWN:
     scrll.assign(0,1);
     scheduler.addtask(scrolling,priority_userrequest,scrll,NULL);
    break;
    case SB_PAGEUP:
     scrll.assign(0,-(vd->size.y-1));
     scheduler.addtask(scrolling,priority_userrequest,scrll,NULL);
    break;
    case SB_PAGEDOWN:
     scrll.assign(0,vd->size.y-1);
     scheduler.addtask(scrolling,priority_userrequest,scrll,NULL);
    break;
    case SB_THUMBPOSITION:
     scrll.assign(0,HIWORD(wParam));
     scheduler.addtask(vthumbposition,priority_userrequest,scrll,NULL);
    break;
   }
  }break;

  case WM_HSCROLL: {
   lptr scrll;
   int amount,x;
   switch (LOWORD(wParam)) {
    case SB_THUMBTRACK:
    case SB_THUMBPOSITION: amount=(int)HIWORD(wParam)-vd->hpos; goto set;
    case SB_LINEUP:	amount=-1; goto set;
    case SB_LINEDOWN:	amount= 1; goto set;
    case SB_PAGEUP:	amount=-8; goto set;
    case SB_PAGEDOWN:	amount= 8; set:
     x=limit(vd->hpos+amount,0,MAX_LENGTH-vd->size.x);
     amount=vd->hpos-x; vd->hpos=x;
     SetScrollPos(hwnd,SB_HORZ,vd->hpos,TRUE);
     ScrollWindow(hwnd,amount*CharBox.x,0,NULL,NULL);
    break;
   }
  }break;

  case WM_CONTEXTMENU: {
   POINT p={(short)LOWORD(lParam),(short)HIWORD(lParam)};
   if (lParam==(LPARAM)-1) {	// from keyboard
    p.x=35*CharBox.x;
    p.y=(vd->sel+1)*CharBox.y;
    ClientToScreen(hwnd,&p);
   }
   TrackPopupMenu(rmenu,0,p.x,p.y,0,MainWnd,NULL);
  }break;

  case WM_KEYDOWN: switch (wParam) {
   case VK_HOME:	SendMessage(hwnd,WM_VSCROLL,SB_TOP,0L);		break;
   case VK_PRIOR:	SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0L);	break;
   case VK_NEXT:	SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0L);	break;
   case VK_DOWN:	SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0L);	break;
   case VK_UP:		SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0L);	break;
   case VK_LEFT:	SendMessage(hwnd,WM_HSCROLL,SB_PAGEUP,0L);	break;
   case VK_RIGHT:	SendMessage(hwnd,WM_HSCROLL,SB_PAGEDOWN,0L);	break;

   case VK_RETURN:
    scheduler.addtask(
      GetKeyState(VK_SHIFT)<0 ? user_jumptoarg2 : user_jumpto,
      priority_userrequest,nlptr,NULL);
   break;

   case VK_ESCAPE:
    scheduler.addtask(user_jumpback,priority_userrequest,nlptr,NULL);
   break;

   case VK_F3:
    searchmore();
   break;
  }break;

  case WM_LBUTTONDOWN: {
   SetFocus(hwnd);
  }nobreak;

  case WM_RBUTTONDOWN: {
   vd->setpos(HIWORD(lParam)/CharBox.y);
  }break;

  case WM_LBUTTONDBLCLK: {
   SendMessage(hwnd,WM_KEYDOWN,VK_RETURN,0);
  }break;

  case WM_NCDESTROY: {
   LocalFree(vd->MainBuff);
   delete vd;
  }break;

  default: return DefWindowProc(hwnd,Msg,wParam,lParam);
 }
 return 0;
}

/************************************************************************
* WinMain..... it all starts here					*
************************************************************************/
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) {
 WNDCLASS wc;
 MSG msg;

 InitCommonControls();
 hInst=GetModuleHandle(NULL);

  /* Define window class */
 ZeroMemory(&wc,sizeof(wc));
 wc.style=CS_DBLCLKS;
 wc.lpfnWndProc=dasm;		// A fürchterlicher Name!!
 wc.hInstance=hInst;
 wc.hIcon=LoadIcon(hInst,MAKEINTRESOURCE(100));
 wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)(COLOR_APPWORKSPACE+1);
 wc.lpszMenuName=MAKEINTRESOURCE(100);
 wc.lpszClassName=szWinName;

  /* Register window classes */
 RegisterClass(&wc);

 wc.lpfnWndProc=ViewWndProc;
 wc.hbrBackground=0;
 wc.lpszClassName="BorgView";
 RegisterClass(&wc);

 Accel=LoadAccelerators(hInst,MAKEINTRESOURCE(100));
  /* Create window */
 wsprintf(winname,"Borg Disassembler v%0d.%2da",(int)BORG_VER/100,BORG_VER%100);
 MainWnd=CreateWindowEx(WS_EX_ACCEPTFILES,szWinName,winname,WS_OVERLAPPEDWINDOW,
   CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
   NULL,NULL,hInst,NULL);

  /* Display window */
 ShowWindow(MainWnd,SW_SHOWDEFAULT);

  /* Message Loop */
 for (;;){
  if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
   if (msg.message==WM_QUIT) break;
   if (KBHand && IsDialogMessage(KBHand,&msg)) continue;
   if (Accel && TranslateAccelerator(MainWnd,Accel,&msg)) continue;
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }else{
   if (!scheduler.process()) WaitMessage();
  }
 }
#ifdef _DEBUG
 _CrtMemDumpAllObjectsSince(NULL);
#endif
 return msg.wParam;
}

Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded