blitz3d/bbruntime_dll/bbruntime_dll.cpp

305 lines
6.6 KiB
C++

#pragma warning( disable:4786 )
#include "bbruntime_dll.h"
#include "../debugger/debugger.h"
#ifdef PRODEMO
#include "../shareprot/shareprot.h"
#endif
using namespace std;
#include <map>
#include <eh.h>
#include <float.h>
#include "../bbruntime/bbruntime.h"
class DummyDebugger : public Debugger{
public:
virtual void debugRun(){}
virtual void debugStop(){}// bbruntime_panic(0); }
virtual void debugStmt( int srcpos,const char *file ){}
virtual void debugEnter( void *frame,void *env,const char *func ){}
virtual void debugLeave(){}
virtual void debugLog( const char *msg ){}
virtual void debugMsg( const char *e,bool serious ){
if( serious ) MessageBox( 0,e,"Error!",MB_OK|MB_TOPMOST|MB_SETFOREGROUND );
}
virtual void debugSys( void *msg ){}
};
static HINSTANCE hinst;
static map<const char*,void*> syms;
map<const char*,void*>::iterator sym_it;
static gxRuntime *gx_runtime;
static void rtSym( const char *sym,void *pc ){
syms[sym]=pc;
}
#ifdef PRODEMO
static void killer(){
ExitProcess( -1 );
}
#endif
static void _cdecl seTranslator( unsigned int u,EXCEPTION_POINTERS* pExp ){
switch( u ){
case EXCEPTION_INT_DIVIDE_BY_ZERO:
bbruntime_panic( "Integer divide by zero" );
case EXCEPTION_ACCESS_VIOLATION:
bbruntime_panic( "Memory access violation" );
case EXCEPTION_ILLEGAL_INSTRUCTION:
bbruntime_panic( "Illegal instruction" );
case EXCEPTION_STACK_OVERFLOW:
bbruntime_panic( "Stack overflow!" );
}
bbruntime_panic( "Unknown runtime exception" );
}
int Runtime::version(){
return VERSION;
}
const char *Runtime::nextSym(){
if( !syms.size() ){
bbruntime_link( rtSym );
sym_it=syms.begin();
}
if( sym_it==syms.end() ){
syms.clear();return 0;
}
return (sym_it++)->first;
}
int Runtime::symValue( const char *sym ){
map<const char*,void*>::iterator it=syms.find( sym );
if( it!=syms.end() ) return (int)it->second;
return -1;
}
void Runtime::startup( HINSTANCE h ){
hinst=h;
}
void Runtime::shutdown(){
trackmem( false );
syms.clear();
}
void Runtime::execute( void (*pc)(),const char *args,Debugger *dbg ){
bool debug=!!dbg;
static DummyDebugger dummydebug;
if( !dbg ) dbg=&dummydebug;
trackmem( true );
_se_translator_function old_trans=_set_se_translator( seTranslator );
_control87( _RC_NEAR|_PC_24|_EM_INVALID|_EM_ZERODIVIDE|_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT|_EM_DENORMAL,0xfffff );
//strip spaces from ends of args...
string params=args;
while( params.size() && params[0]==' ' ) params=params.substr( 1 );
while( params.size() && params[params.size()-1]==' ' ) params=params.substr( 0,params.size()-1 );
if( gx_runtime=gxRuntime::openRuntime( hinst,params,dbg ) ){
#ifdef PRODEMO
shareProtCheck( killer );
#endif
bbruntime_run( gx_runtime,pc,debug );
gxRuntime *t=gx_runtime;
gx_runtime=0;
gxRuntime::closeRuntime( t );
}
_control87( _CW_DEFAULT,0xfffff );
_set_se_translator( old_trans );
}
void Runtime::asyncStop(){
if( gx_runtime ) gx_runtime->asyncStop();
}
void Runtime::asyncRun(){
if( gx_runtime ) gx_runtime->asyncRun();
}
void Runtime::asyncEnd(){
if( gx_runtime ) gx_runtime->asyncEnd();
}
void Runtime::checkmem( streambuf *buf ){
ostream out( buf );
::checkmem( out );
}
Runtime *_cdecl runtimeGetRuntime(){
static Runtime runtime;
return &runtime;
}
/********************** BUTT UGLY DLL->EXE HOOK! *************************/
static void *module_pc;
static map<string,int> module_syms;
static map<string,int> runtime_syms;
static Runtime *runtime;
static void fail(){
MessageBox( 0,"Unable to run Blitz Basic module",0,0 );
ExitProcess(-1);
}
struct Sym{
string name;
int value;
};
static Sym getSym( void **p ){
Sym sym;
char *t=(char*)*p;
while( char c=*t++ ) sym.name+=c;
sym.value=*(int*)t+(int)module_pc;
*p=t+4;return sym;
}
static int findSym( const string &t ){
map<string,int>::iterator it;
it=module_syms.find( t );
if( it!=module_syms.end() ) return it->second;
it=runtime_syms.find( t );
if( it!=runtime_syms.end() ) return it->second;
string err="Can't find symbol: "+t;
MessageBox( 0,err.c_str(),0,0 );
ExitProcess(0);
return 0;
}
static void link(){
while( const char *sc=runtime->nextSym() ){
string t(sc);
if( t[0]=='_' ){
runtime_syms["_"+t]=runtime->symValue(sc);
continue;
}
if( t[0]=='!' ) t=t.substr(1);
if( !isalnum(t[0]) ) t=t.substr(1);
for( int k=0;k<t.size();++k ){
if( isalnum(t[k]) || t[k]=='_' ) continue;
t=t.substr( 0,k );break;
}
runtime_syms["_f"+tolower(t)]=runtime->symValue(sc);
}
HRSRC hres=FindResource( 0,MAKEINTRESOURCE(1111),RT_RCDATA );if( !hres ) fail();
HGLOBAL hglo=LoadResource( 0,hres );if( !hglo ) fail();
void *p=LockResource( hglo );if( !p ) fail();
int sz=*(int*)p;p=(int*)p+1;
//replace malloc for service pack 2 Data Execution Prevention (DEP).
module_pc=VirtualAlloc( 0,sz,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE );
memcpy( module_pc,p,sz );
p=(char*)p+sz;
int k,cnt;
cnt=*(int*)p;p=(int*)p+1;
for( k=0;k<cnt;++k ){
Sym sym=getSym( &p );
if( sym.value<(int)module_pc || sym.value>=(int)module_pc+sz ) fail();
module_syms[sym.name]=sym.value;
}
cnt=*(int*)p;p=(int*)p+1;
for( k=0;k<cnt;++k ){
Sym sym=getSym( &p );
int *pp=(int*)sym.value;
int dest=findSym( sym.name );
*pp+=dest-(int)pp;
}
cnt=*(int*)p;p=(int*)p+1;
for( k=0;k<cnt;++k ){
Sym sym=getSym( &p );
int *pp=(int*)sym.value;
int dest=findSym( sym.name );
*pp+=dest;
}
runtime_syms.clear();
module_syms.clear();
}
extern "C" _declspec(dllexport) int _stdcall bbWinMain();
extern "C" BOOL _stdcall _DllMainCRTStartup( HANDLE,DWORD,LPVOID );
bool WINAPI DllMain( HANDLE module,DWORD reason,void *reserved ){
return TRUE;
}
int __stdcall bbWinMain(){
HINSTANCE inst=GetModuleHandle( 0 );
_DllMainCRTStartup( inst,DLL_PROCESS_ATTACH,0 );
#ifdef BETA
int ver=VERSION & 0x7fff;
string t="Created with Blitz3D Beta V"+itoa( ver/100 )+"."+itoa( ver%100 );
MessageBox( GetDesktopWindow(),t.c_str(),"Blitz3D Message",MB_OK );
#endif
#ifdef SCHOOLS
MessageBox( GetDesktopWindow(),"Created with the schools version of Blitz Basic","Blitz Basic Message",MB_OK );
#endif
runtime=runtimeGetRuntime();
runtime->startup( inst );
link();
//get cmd_line and params
string cmd=GetCommandLine(),params;
while( cmd.size() && cmd[0]==' ' ) cmd=cmd.substr( 1 );
if( cmd.find( '\"' )==0 ){
int n=cmd.find( '\"',1 );
if( n!=string::npos ){
params=cmd.substr( n+1 );
cmd=cmd.substr( 1,n-1 );
}
}else{
int n=cmd.find( ' ' );
if( n!=string::npos ){
params=cmd.substr( n+1 );
cmd=cmd.substr( 0,n );
}
}
runtime->execute( (void(*)())module_pc,params.c_str(),0 );
runtime->shutdown();
_DllMainCRTStartup( inst,DLL_PROCESS_DETACH,0 );
ExitProcess(0);
return 0;
}