#pragma warning(disable : 4786) #include "bbruntime_dll.hpp" #include "../debugger/debugger.hpp" using namespace std; #include #include #include #include "bbruntime.hpp" 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 syms; map::iterator sym_it; static gxRuntime* gx_runtime; static void rtSym(const char* sym, void* pc) { syms[sym] = pc; } 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::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)) { 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 module_syms; static map 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::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; }