Skip to content

Commit

Permalink
Throwing exceptions in DLLs!
Browse files Browse the repository at this point in the history
伟大的历史转折
  • Loading branch information
ZiYueCommentary committed Sep 17, 2024
1 parent edd0d42 commit 15b7a24
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 12 deletions.
49 changes: 48 additions & 1 deletion EXTENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,33 @@ Now HERE is how we would write a DLL:

**ATTENTION!** When building a standalone executable for your game, you must place the userlib's DLL alongside the executable (you don't need the declarations file anymore, though).

### Throwing exceptions in DLLs

> [!IMPORTANT]
> This feature is available in Blitz3D TSS v1.334 or above only. Other Blitz3D or BlitzPlus will occur "Unknown runtime exception", no matter what type of exception you threw.
Blitz3D TSS is using [Structured Exception Handling](https://learn.microsoft.com/en-us/windows/win32/debug/about-structured-exception-handling) to receive your exceptions. There are two types of exceptions are available for throwing:

* `0xE0000001` : Throwing a runtime error and crashing the program immediately. Requires runtime error message.
* `0xE0000002` : Throwing an exception which can be shown in the customized MAV message. Requires function name and exception message.

To throw exceptions in DLLs, you need to use [RaiseException function](https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-raiseexception).

For example:
```cpp
ULONG_PTR args[1]{};
args[0] = reinterpret_cast<ULONG_PTR>("This is a runtime error!");
RaiseException(0xE0000001, 0, 1, args);
```
```cpp
ULONG_PTR args[2]{};
args[0] = reinterpret_cast<ULONG_PTR>("Function name");
args[1] = reinterpret_cast<ULONG_PTR>("Exception message");
RaiseException(0xE0000002, 0, 2, args);
```

**ATTENTION!** Make sure that your `const char*` is pointing to the memory which is still available after your function ends.

## Sample Code

**MyLib.h**
Expand All @@ -67,6 +94,8 @@ Now HERE is how we would write a DLL:

BLITZ3D(float) VecDistance(float x1, float y1, float z1, float x2, float y2, float z2);
BLITZ3D(const char*) Ping();
BLITZ3D(void) ErrorFunction();
BLITZ3D(void) MyExceptionFunction();
```
**MyLib.cpp**
Expand All @@ -87,6 +116,22 @@ BLITZ3D(const char*) Ping()
{
return "Pong";
}
BLITZ3D(void) ErrorFunction()
{
ULONG_PTR args[1]{};
args[0] = reinterpret_cast<ULONG_PTR>("This is a runtime error!");
RaiseException(0xE0000001, 0, 1, args);
}
BLITZ3D(void) MyExceptionFunction()
{
ULONG_PTR args[2]{};
args[0] = reinterpret_cast<ULONG_PTR>("MyExceptionFunction");
args[1] = reinterpret_cast<ULONG_PTR>("Hello world!");
RaiseException(0xE0000002, 0, 2, args);
}
```

**MyLib.decls**
Expand All @@ -96,8 +141,10 @@ BLITZ3D(const char*) Ping()
VecDistance#(x1#, y1#, z1#, x2#, y2#, z2#):"_VecDistance@24"
Ping$():"_Ping@0"
ErrorFunction():"_ErrorFunction@0"
MyExceptionFunction():"_MyExceptionFunction@0"
```

Hopefully this guide will help you.

If you find any issues with this guide, please open an issue or contact Nora#6365 on the TSS discord server.
If you find any issues with this guide, please open an issue.
52 changes: 41 additions & 11 deletions bbruntime/bbruntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,22 +313,49 @@ bool bbruntime_destroy() {
return true;
}

inline void program(void (*pc)()) {
inline static const wchar_t* CharToWchar(const char* ch) {
const size_t len = strlen(ch) + 1;
wchar_t* wch = new wchar_t[len];
mbstowcs(wch, ch, len);
return wch;
}

inline const char* getCharPtr(std::string str) {
char* cha = new char[str.size() + 1];
memcpy(cha, str.c_str(), str.size() + 1);
const char* p = cha;
return p;
}

inline static unsigned long ExceptionFilter(PEXCEPTION_POINTERS ex, PEXCEPTION_POINTERS& pex) {
if (
ex->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO ||
ex->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION ||
ex->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW ||
ex->ExceptionRecord->ExceptionCode == EXCEPTION_INT_OVERFLOW ||
ex->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_OVERFLOW ||
ex->ExceptionRecord->ExceptionCode == EXCEPTION_FLT_DIVIDE_BY_ZERO ||
ex->ExceptionRecord->ExceptionCode == 0xE0000001
) {
pex = ex;
return EXCEPTION_EXECUTE_HANDLER;
} else if (ex->ExceptionRecord->ExceptionCode == 0xE0000002) {
errorfunc = getCharPtr(reinterpret_cast<const char*>(ex->ExceptionRecord->ExceptionInformation[0]));
errorlog = getCharPtr(reinterpret_cast<const char*>(ex->ExceptionRecord->ExceptionInformation[1]));
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}

inline static void program(void (*pc)()) {
PEXCEPTION_POINTERS ex = NULL;
__try {
if (!gx_runtime->idle()) RTEX(0);
pc();
gx_runtime->debugInfo(MultiLang::program_ended);
}
__except (
GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ||
GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ||
GetExceptionCode() == EXCEPTION_STACK_OVERFLOW ||
GetExceptionCode() == EXCEPTION_INT_OVERFLOW ||
GetExceptionCode() == EXCEPTION_FLT_OVERFLOW ||
GetExceptionCode() == EXCEPTION_FLT_DIVIDE_BY_ZERO
? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH
) {
switch (GetExceptionCode()) {
__except (ExceptionFilter(GetExceptionInformation(), ex)) {
switch (ex->ExceptionRecord->ExceptionCode) {
case EXCEPTION_INT_DIVIDE_BY_ZERO:
bbruntime_panic(MultiLang::integer_divide_zero);
break;
Expand All @@ -347,6 +374,9 @@ inline void program(void (*pc)()) {
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
bbruntime_panic(MultiLang::float_divide_zero);
break;
case 0xE0000001:
bbruntime_panic(CharToWchar(reinterpret_cast<const char*>(ex->ExceptionRecord->ExceptionInformation[0])));
break;
}
}
}
Expand Down

0 comments on commit 15b7a24

Please # to comment.