Example C++ plugin¶
main.h¶
#ifndef __MAIN_H__
#define __MAIN_H__
#include <cstdint>
#if defined(_WIN32) || defined(_WIN64)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT [[gnu::visibility("default")]]
#endif
#if INTPTR_MAX == INT32_MAX
typedef int32_t NativeInt;
typedef uint32_t NativeUInt;
#else
typedef int64_t NativeInt;
typedef uint64_t NativeUInt;
#endif
struct __attribute__((__packed__)) TSimbaInfo
{
int SimbaVersion;
int SimbaMajor;
char* FileName;
void* Compiler;
};
struct __attribute__((__packed__)) TSimbaMethods
{
void (*RunOnMainThread)(void(*TMainThreadMethod)(void*), void* data);
void* (*GetMem)(std::size_t size);
void (*FreeMem)(void* ptr);
void* (*AllocMem)(std::size_t size);
void* (*ReAllocMem)(void** ptr, std::size_t size);
std::size_t (*MemSize)(void* ptr);
void(*RaiseException)(const char* message);
void* (*GetTypeInfo)(void* Compiler, const char* Type);
void* (*GetTypeInfoSize)(void* TypeInfo);
std::size_t (*GetTypeInfoFieldOffset)(void* TypeInfo, const char* FieldName);
void* (*AllocateRawArray)(std::size_t element_size, std::size_t length);
void (*ReAllocateRawArray)(void** array, std::size_t element_size, std::size_t new_length);
void* (*AllocateArray)(void* TypeInfo, std::size_t length);
void* (*AllocateString)(const char* data);
void* (*AllocateUnicodeString)(const wchar_t* data);
void (*SetArrayLength)(void* TypeInfo, void** var, std::size_t new_len);
std::size_t (*GetArrayLength)(void* array);
void* (*ExternalImage_Create)(bool AutoResize);
void (*ExternalImage_SetMemory)(void* img, void* bgra_data, std::int32_t width, std::int32_t height);
void (*ExternalImage_Resize)(void* img, std::int32_t new_width, std::int32_t new_height);
void (*ExternalImage_SetUserData)(void* img, void* userdata);
void* (*ExternalImage_GetUserData)(void* img);
};
TSimbaInfo* SIMBA_INFO = {0};
TSimbaMethods* SIMBA_METHODS = {0};
extern "C"
{
EXPORT int GetTypeCount();
EXPORT int GetTypeInfo(int Index, char** Name, char** Definition);
EXPORT int GetFunctionCount();
EXPORT int GetFunctionInfo(int Index, void** Address, char** Definition);
EXPORT void RegisterSimbaPlugin(TSimbaInfo* Information, TSimbaMethods* Methods);
}
#endif // __MAIN_H__
main.cpp¶
#include "main.h"
#include "stdio.h"
#include <cstring>
template<typename T>
void MemWrite(void* ptr, int offset, T item) noexcept
{
memcpy((char*)ptr+offset, &item, sizeof(T));
}
template<typename T>
T MemRead(void* ptr) noexcept
{
T result;
memcpy(&result, ptr, sizeof(T));
return result;
}
void* ARR_TYPEINFO = 0;
void* REC_TYPEINFO = 0;
NativeUInt REC_SIZE = 0;
NativeUInt REC_STR_OFFSET = 0;
void GetIntArray(void** Params, void** Result)
{
int Count = MemRead<int>(*Params);
void* Arr = SIMBA_METHODS->AllocateRawArray(sizeof(int32_t), Count);
for (int i=0; i<Count; i++) {
MemWrite(Arr, i*sizeof(int), i);
}
MemWrite<void*>(Result, 0, Arr);
}
void GetRecord(void** Params, void** Result)
{
MemWrite<int>(Result, 0, 123456);
MemWrite<void*>(Result, REC_STR_OFFSET, SIMBA_METHODS->AllocateString((char*)"Hello world"));
}
void GetArrayOfRecord(void** Params, void** Result)
{
char str0[] = "Hello in array index 0";
char str1[] = "Hola in array index 1";
char str2[] = "Bonjour in array index 2";
void* mem = SIMBA_METHODS->AllocateArray(ARR_TYPEINFO, 3);
for (int i=0; i<3; i++) {
void* str = nullptr;
switch (i) {
case 0: str = SIMBA_METHODS->AllocateString((void*)str0); break;
case 1: str = SIMBA_METHODS->AllocateString((void*)str1); break;
case 2: str = SIMBA_METHODS->AllocateString((void*)str2); break;
}
// write arr[i].i
MemWrite<int>(mem, i*REC_SIZE, i);
// write arr[i].str
MemWrite<void*>(mem, (i*REC_SIZE)+REC_STR_OFFSET, str);
}
MemWrite<void*>(Result, 0, mem);
}
void RegisterSimbaPlugin(TSimbaInfo* Info, TSimbaMethods* Methods)
{
SIMBA_INFO = Info;
SIMBA_METHODS = Methods;
REC_TYPEINFO = SIMBA_METHODS->GetTypeInfo(SIMBA_INFO->Compiler, (char*)"TMyRecord");
REC_SIZE = SIMBA_METHODS->GetTypeInfoSize(REC_TYPEINFO);
REC_STR_OFFSET = SIMBA_METHODS->GetTypeInfoFieldOffset(REC_TYPEINFO, (char*)"str");
ARR_TYPEINFO = SIMBA_METHODS->GetTypeInfo(SIMBA_INFO->Compiler, (char*)"array of TMyRecord");
}
int GetTypeCount()
{
return 1;
}
int GetTypeInfo(int Index, char** Name, char** Definition)
{
switch(Index) {
case 0:
strcpy(*Name, "TMyRecord");
strcpy(*Definition, "record i: Int32; str: String; end;");
break;
}
return Index;
}
int GetFunctionCount()
{
return 3;
}
int GetFunctionInfo(int Index, void** Address, char** Definition)
{
switch(Index) {
case 0:
strcpy(*Definition, "function GetIntArray(Count: Int32): array of Int32; native;");
*Address = (void*)GetIntArray;
break;
case 1:
strcpy(*Definition, "function GetRecord: TMyRecord; native;");
*Address = (void*)GetRecord;
break;
case 2:
strcpy(*Definition, "function GetArrayOfRecord: array of TMyRecord; native;");
*Address = (void*)GetArrayOfRecord;
break;
}
return Index;
}