Bypass FFI by appending the method header with "native" then it will use the default importing system.
https://github.com/nielsAD/lape/blob...types.pas#L145
https://github.com/MerlijnWajer/Simb...read.pas#L1623
Bypass FFI by appending the method header with "native" then it will use the default importing system.
https://github.com/nielsAD/lape/blob...types.pas#L145
https://github.com/MerlijnWajer/Simb...read.pas#L1623
What is going on here, some kind of error huh.
As the author of this code, you need to use `regparm` which is only available in GCC, G++, Clang, Clang++.. Visual Studio does NOT support it..
So to fix this, you need to IFDEF that code for visual studio but then also use:
cpp Code:#ifndef TMEMORYMANAGER_HXX_INCLUDED
#define TMEMORYMANAGER_HXX_INCLUDED
#if !defined(_MSC_VER)
#define DELPHI_CALLING_CONVENTION __attribute__((regparm(3)))
typedef struct
{
std::uint32_t TotalAddressSpace;
std::uint32_t TotalUncommited;
std::uint32_t TotalCommited;
std::uint32_t TotalAllocated;
std::uint32_t TotalFree;
std::uint32_t FreeSmall;
std::uint32_t FreeBig;
std::uint32_t Unused;
std::uint32_t Overhead;
std::uint32_t HeapErrorCode;
} THeapStatus;
typedef struct
{
std::uintptr_t MaxHeapSize;
std::uintptr_t MaxHeapUsed;
std::uintptr_t CurrHeapSize;
std::uintptr_t CurrHeapUsed;
std::uintptr_t CurrHeapFree;
} TFPCHeapStatus;
typedef struct
{
bool NeedLock;
void* (*GetMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
std::intptr_t (*FreeMem)(void* &ptr) DELPHI_CALLING_CONVENTION;
std::intptr_t (*FreeMemSize)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
void* (*AllocMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
void* (*ReAllocMem)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
std::intptr_t (*MemSize)(void* ptr) DELPHI_CALLING_CONVENTION;
void (*InitThread)() DELPHI_CALLING_CONVENTION;
void (*DoneThread)() DELPHI_CALLING_CONVENTION;
void (*RelocateHeap)() DELPHI_CALLING_CONVENTION;
THeapStatus (*GetHeapStatus)() DELPHI_CALLING_CONVENTION;
TFPCHeapStatus (*GetFPCHeapStatus)() DELPHI_CALLING_CONVENTION;
} TMemoryManager;
typedef struct
{
bool NeedLock;
void* (*GetMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
std::intptr_t (*FreeMem)(void* &ptr) DELPHI_CALLING_CONVENTION;
std::intptr_t (*FreeMemSize)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
void* (*AllocMem)(std::intptr_t size) DELPHI_CALLING_CONVENTION;
void* (*ReAllocMem)(void* &ptr, std::intptr_t size) DELPHI_CALLING_CONVENTION;
std::intptr_t (*MemSize)(void* ptr) DELPHI_CALLING_CONVENTION;
void (*InitThread)() DELPHI_CALLING_CONVENTION;
void (*DoneThread)() DELPHI_CALLING_CONVENTION;
void (*RelocateHeap)() DELPHI_CALLING_CONVENTION;
THeapStatus (*GetHeapStatus)() DELPHI_CALLING_CONVENTION;
TFPCHeapStatus (*GetFPCHeapStatus)() DELPHI_CALLING_CONVENTION;
} __attribute__((__packed__)) TCMemoryManager;
#endif
typedef struct
{
void (__cdecl *Sync)(void(__cdecl *synchronize_method)(void*), void* data);
} __attribute__((__packed__)) TSimbaMethods;
typedef struct
{
void* (__cdecl *GetMem)(std::size_t size);
void (__cdecl *FreeMem)(void* ptr);
} __attribute__((__packed__)) TSimbaMemoryAllocators;
#endif // TMEMORYMANAGER_HXX_INCLUDED
Then you have to do:
cpp Code:#if !defined(_MSC_VER)
TMemoryManager PLUGIN_MEMORY_MANAGER = {0};
#endif
TSimbaMethods PLUGIN_SYNC_METHODS = {0};
TSimbaMemoryAllocators PLUGIN_MEMORY_ALLOCATORS = {0};
#if !defined(_MSC_VER)
void SetPluginMemManager(TMemoryManager MemMgr)
{
PLUGIN_MEMORY_MANAGER = MemMgr;
}
#endif
void SetPluginSimbaMethods(TSimbaMethods Methods)
{
PLUGIN_SYNC_METHODS = Methods;
}
void SetPluginSimbaMemoryAllocators(TSimbaMemoryAllocators Allocators)
{
PLUGIN_MEMORY_ALLOCATORS = Allocators;
}
Then to allocate a string or array, I do:
cpp Code:typedef struct
{
std::make_signed_t<std::size_t> refCount;
std::make_signed_t<std::size_t> length;
char data[];
} __attribute__((__packed__)) PascalArray;
#if defined(FPC2)
typedef struct
{
std::make_signed_t<std::size_t> refCount;
std::make_signed_t<std::size_t> length;
char data[];
} __attribute__((__packed__)) PascalString;
#else
typedef struct
{
std::uint16_t codePage;
std::uint16_t elementSize;
#if defined(__x86_64__)
std::uint32_t dummy;
#endif
std::make_signed_t<std::size_t> refCount;
std::make_signed_t<std::size_t> length;
char data[];
} __attribute__((__packed__)) PascalString;
#endif // defined
template<typename T, std::size_t size>
struct __attribute__((__packed__)) StaticPascalArray
{
const std::make_signed_t<std::size_t> refCount = -1;
const std::make_signed_t<std::size_t> length = size;
T data[size] = {0};
};
template<typename T>
int PascalHigh(T* Arr)
{
return reinterpret_cast<int*>(Arr)[-1];
}
template<typename T>
int PascalLength(T* Arr)
{
return PascalHigh<T>(Arr) + 1;
}
template<typename T>
T* AllocateArray(std::size_t size, std::size_t element_size = sizeof(T))
{
std::size_t new_size = (size * element_size) + sizeof(PascalArray);
#if !defined(_MSC_VER)
PascalArray* ptr = static_cast<PascalArray*>(PLUGIN_MEMORY_MANAGER.AllocMem(new_size));
#else
PascalArray* ptr = static_cast<PascalArray*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size));
#endif
ptr->refCount = 1;
ptr->length = size - 1;
return reinterpret_cast<T*>(++ptr);
}
template<typename T>
T* AllocateString(std::size_t size, std::size_t element_size = sizeof(T))
{
std::size_t new_size = (size * element_size) + sizeof(PascalString);
#if !defined(_MSC_VER)
PascalString* ptr = static_cast<PascalString*>(PLUGIN_MEMORY_MANAGER.AllocMem(new_size + 1));
#else
PascalString* ptr = static_cast<PascalString*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size + 1));
#endif
ptr->refCount = 1;
ptr->length = size;
return reinterpret_cast<T*>(++ptr);
}
template<typename T>
T* GetArray(void* ptr, std::size_t* size)
{
PascalArray* mem = static_cast<PascalArray*>(ptr);
return reinterpret_cast<T*>((--mem)->data);
}
template<typename T>
T* GetString(void* ptr)
{
PascalString* mem = static_cast<PascalString*>(ptr);
return reinterpret_cast<T*>((--mem)->data);
}
Usage then becomes:
cpp Code:int* IntArray = AllocateArray(100); //equivalent to SetLength(TIntegerArray, 100);
char* CharArray = AllocateArray(100); //equivalent to SetLength(TCharArray, 100);
char* StrArray = AllocateString(5); //Allocates a string of length 5 in pascal.
strcpy(StrArray, "Hello");
//Array of array:
int** Array2D = AllocateArray(4, sizeof(int)); //explicitly specify we want an array of array of integers (in this example, 4 x 5).
for (int i = 0; i < 4; ++i)
{
Array2D[i] = AllocateArray(5);
Array2D[i][0] = 1;
Array2D[i][1] = 2;
Array2D[i][2] = 3;
Array2D[i][3] = 4;
Array2D[i][4] = 5; //Can also use memcpy or memset to set values..
}
//Alternatively:
Array2D[0][0] = 0;
Array2D[0][1] = 1;
Array2D[0][2] = 2;
//etc..
Array2D[1][0] = 0;
Array2D[1][1] = 1;
Array2D[1][2] = 2;
//etc..
Array2D[2][0] = 0;
Array2D[2][1] = 1;
Array2D[2][2] = 2;
//etc..
You can always specialize the template to allocate array of arrays without specifying `sizeof(whateverType)` by doing: `sizeof(typename std::remove_pointer<T>::type)` instead.. but that's for another day.. Too lazy and most of my code works with this already so..
To export functions, I use Simba's "NATIVE" keyword:
cpp Code:static const char* PascalExports[] =
{
"SomeFunc", "Function SomeFunc(A: Int32; B: String; C: Char): Boolean; native;"
}
void SomeFunc(void** Params, void** Result)
{
int32_t A = ReadPointer(Params[0]); //*static_cast<int32_t*>(Params[0])
char* B = ReadPointer(Params[1]); //*static_cast<char**>(Params[1])
char C = ReadPointer(Params[2]); //*static_cast<char*>(Params[2])
WritePointer(Result, true); //*static_cast<bool*>(Result) = true;
}
Last edited by Brandon; 01-31-2020 at 05:41 PM.
I am Ggzz..
Hackintosher
Between those lines code is grayed out and then goes into red again. Do I have to do something extra?Code:if !defined(_MSC_VER) #define DELPHI_CALLING_CONVENTION __attribute__((regparm(3))) #endif
It's greyed out on purpose because you won't be able to use those structs UNLESS you write assembly to call the functions using the `regparm` calling convention..
So the code that's "outside" of the IFDEF is the new code to use. @Olly; exported it for us to use without having to use `TMemoryManager`.
IE: https://github.com/MerlijnWajer/Simb...ment-436310146
The code outside of that is using this.. instead of the TMemoryManager when it's available.
I am Ggzz..
Hackintosher
Hey Brandon. Now I had time to look at it again. I has put it all together into header file.
In main.
Other header file.Code:TSimbaMethods PLUGIN_SYNC_METHODS = { 0 }; TSimbaMemoryAllocators PLUGIN_MEMORY_ALLOCATORS = { 0 }; void SetPluginSimbaMethods(TSimbaMethods Methods) { PLUGIN_SYNC_METHODS = Methods; } void SetPluginSimbaMemoryAllocators(TSimbaMemoryAllocators Allocators) { PLUGIN_MEMORY_ALLOCATORS = Allocators; }
It does compile.Code:typedef struct { void(__cdecl* Sync)(void(__cdecl* synchronize_method)(void*), void* data); }TSimbaMethods; typedef struct { void* (__cdecl* GetMem)(std::size_t size); void(__cdecl* FreeMem)(void* ptr); }TSimbaMemoryAllocators; typedef struct { std::make_signed_t<std::size_t> refCount; std::make_signed_t<std::size_t> length; char data[]; }PascalArray; #if defined(FPC2) typedef struct { std::make_signed_t<std::size_t> refCount; std::make_signed_t<std::size_t> length; char data[]; }PascalString; #else typedef struct { std::uint16_t codePage; std::uint16_t elementSize; #if defined(__x86_64__) std::uint32_t dummy; #endif std::make_signed_t<std::size_t> refCount; std::make_signed_t<std::size_t> length; char data[]; }PascalString; #endif // defined template<typename T, std::size_t size> struct StaticPascalArray { const std::make_signed_t<std::size_t> refCount = -1; const std::make_signed_t<std::size_t> length = size; T data[size] = { 0 }; }; template<typename T> int PascalHigh(T* Arr) { return reinterpret_cast<int*>(Arr)[-1]; } template<typename T> int PascalLength(T* Arr) { return PascalHigh<T>(Arr) + 1; } template<typename T> T* AllocateArray(std::size_t size, std::size_t element_size = sizeof(T)) { std::size_t new_size = (size * element_size) + sizeof(PascalArray); PascalArray* ptr = static_cast<PascalArray*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size)); ptr->refCount = 1; ptr->length = size - 1; return reinterpret_cast<T*>(++ptr); } template<typename T> T* AllocateString(std::size_t size, std::size_t element_size = sizeof(T)) { std::size_t new_size = (size * element_size) + sizeof(PascalString); PascalString* ptr = static_cast<PascalString*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size + 1)); ptr->refCount = 1; ptr->length = size; return reinterpret_cast<T*>(++ptr); } template<typename T> T* GetArray(void* ptr, std::size_t* size) { PascalArray* mem = static_cast<PascalArray*>(ptr); return reinterpret_cast<T*>((--mem)->data); } template<typename T> T* GetString(void* ptr) { PascalString* mem = static_cast<PascalString*>(ptr); return reinterpret_cast<T*>((--mem)->data); }
But when I try to call AllocateArray(100);
It complains that int type doesn't fit there.
Hey, it seems MSVC is unable to infer the type of int (template<typename T>) for the template. The error message is just vague. It should have told you that it can't determine the type of `T` for the templates.
So just do:
c++ Code://Allocating
int* foo = AllocateArray<int>(100); //Explicitly specify to `AllocateArray` that you want `int` type.
float* something = AllocateArray<float>(100); //returns space for simba array with 100 floats.
char* string = AllocateString<char>(100); //returns space for simba string with 100 characters.
//testing..
for (int i = 0; i < 100; ++i)
{
foo[i] = i;
}
Also make sure that SetPluginSimbaMemoryAllocators is actually getting called by your version of Simba That's about it. I am using these in my own plugins so I know they work
Example: https://gist.github.com/Brandon-T/5e...cef4933c66a319
Hop on the srl discord I check it more frequently than the forums.
Last edited by Brandon; 05-04-2020 at 01:50 PM.
I am Ggzz..
Hackintosher
Thanks for helping. Nows it does somethin.
Code:void Testt() { int* IntArray = AllocateArray <int>(100); for (int i = 0; i < 100; ++i) { IntArray[i] = i + 1; } for (int i = 0; i < 100; ++i) { cout << IntArray[i] << endl; } }
Is this now stored in simbas memory not just plugins?
Edit:
Now I have changed my main code to.
Now SetPluginSimbaMemoryAllocators is definitely being called when plugin is loaded in. Text is printed.Code:TSimbaMethods PLUGIN_SYNC_METHODS = { 0 }; TSimbaMemoryAllocators PLUGIN_MEMORY_ALLOCATORS = { 0 }; extern "C" __declspec(dllexport) void SetPluginSimbaMethods(TSimbaMethods Methods) { PLUGIN_SYNC_METHODS = Methods; } extern "C" __declspec(dllexport) void SetPluginSimbaMemoryAllocators(TSimbaMemoryAllocators Allocators) { cout << "SetPluginSimbaMemoryAllocators called" <<endl; PLUGIN_MEMORY_ALLOCATORS = Allocators; }
Nows using it, How=?
Added this to pascal exports:
Edit44:Code:CHAR* PascalExports[] = { (CHAR*)"SomeFunc", (CHAR*)"Procedure SomeFunc(A: Int32) native;" }
It doesn't even matter. It crashes if i try to access that memory. I have attached visual studio debugger thing to see what is happening. Any ideas?
Do I have to declare array before?
Code is good and you've gotten it working for the most part . Look at the debugger though. It shows the value 0x63 was passed by value? Without seeing your Simba code, I can't figure out what is missing.
The first thing I noticed is that you are missing a `Result` parameter natively (without this parameter, you will have stack corruption due to invalid function signature).
I wrote some helpers that will read/write automatically for you:
c++ Code:template<typename T>
T PascalRead(void* ptr)
{
return *static_cast<T*>(ptr);
}
template<typename T>
void PascalWrite(void* result, T value)
{
*static_cast<T*>(result) = value;
}
c++ Code:CHAR* PascalExports[] =
{
(CHAR*)"SomeFunc", (CHAR*)"Procedure SomeFunc(A: Int32); native;",
(CHAR*)"SomeFunc2", (CHAR*)"Function SomeFunc2(size: Int32): Array of Int32; native;",
}
void SomeFunc(void** Params, void** Result) //YOU MUST have a Result parameter even if you aren't going to use it (for procedures and functions).
{
int32_t a = PascalRead<int32_t>(Params[0]);
//int32_t b = PascalRead<int32_t>(Params[1]);
//size_t length = 0;
//int32_t* indices = GetArray<int32_t>(PascalRead<void*>(Params[2]), &length);
printf("%d\n", a); //or std::cout<<a<<"\n";
}
void SomeFunc2(void** Params, void** Result)
{
//retrieve parameter..
int32_t size = PascalRead<int32_t>(Params[0]);
//allocate int32 array..
int32_t* arr = AllocateArray<int32_t>(size);
for (int i = 0; i < arr; ++i)
{
arr[i] = i + 1;
}
//Return arr..
PascalWrite(Result, arr);
}
Are you also using: https://github.com/ollydev/SimbaDevelopment/releases
@alar82;
Last edited by Brandon; 05-06-2020 at 04:06 PM.
I am Ggzz..
Hackintosher
Which IDE are you using for development/testing?
That is a funny question. If you look at this thread carefully u will find out.
Is it MSVC (Microsoft Visual Stuido with C++)?
Hey Olly.
I has noticed some different things using development version.
First plug-in is ejected when using stop button. I am sure that should not be happening. I mean plug-in functions still stay at side list. But if it is intentional then make it optional.
Pic:
Hey Brandon trying to use vector arrays gives no results.
First params[0] is declared at pascal exports as array of INT32.Code:PascalRead<vector<int>>(Params[0]);
Also noticed this code:
Give some kind of big number. If it would be standard array length. I could Insert one array into those vector arrays, if I would know size that is.Code:PascalArray* mem = static_cast<PascalArray*>(Params[0]); cout << mem->length << endl;
Edit: @BeatDat yes it is Most simplistic IDE there is in my opinion. Community edition 2019, it is free.
Hey, because of the error you got, I discovered a bug in my code. It is fixed now.
Change to:
c++ Code:template<typename T>
T* GetArray(void* ptr, std::size_t* size) noexcept
{
PascalArray* mem = static_cast<PascalArray*>(ptr) - 1;
*size = mem->length;
return reinterpret_cast<T*>(mem)->data);
}
It was just a copy paste error. It was reading the length from the raw pointer instead of offsetting to the pascal pointer.
The above should fix it.
Now for the vector stuff, Vector is a container and it's not a raw pointer to int32_t array as you've already mentioned. So the code as it is, will NOT work with vector. You can't do `PascalRead<vector<int>>` because `PascalRead` literally just dereferences and casts the result to template type T.
For any container that you want to read, you have to overload OR specialize the templates using template overloads or specialization..
Add this to your file and now it'll automatically covert a pascal array of type T to a vector of type T where T is primitive. I don't think you need T to be another container or generic?
c++ Code:template<typename T>
std::vector<T> GetArray(void* ptr) noexcept
{
std::size_t size = 0;
T* raw_data = GetArray<T>(ptr, &size);
return std::vector<T>{raw_data, raw_data + size};
}
std::string GetString(void* ptr) noexcept
{
return GetString<char>(ptr);
}
template<typename T>
void PascalWrite(void* result, const std::vector<T> &value)
{
T* array = AllocateArray<T>(value.size());
std::memcpy(array, value.data(), value.size() * sizeof(T));
PascalWrite(result, array);
}
template<typename T>
void PascalWrite(void* result, const std::string &value)
{
T* str = AllocateString<char>(value.size());
std::memcpy(str, value.data(), value.size() * sizeof(T));
PascalWrite(result, str);
}
void Usage_Example(void** Params, void** Result)
{
std::vector<int> vec = GetArray<int>(Params[0]);
std::string str = GetString<char>(Params[1]);
}
Also, the plugin unloading thing is intentional. Don't worry, it's not unloading forever. It's just that scripts are now ran in their own process so if a plugin or script crashes, it will only crash that process and won't crash your Simba itself. The next time you run the script, it will just load the plugin again.
This shouldn't cause you any problems.
Last edited by Brandon; 05-09-2020 at 09:51 PM.
I am Ggzz..
Hackintosher
Global variables in the plugin? They will be re-created since it's a brand new process being spawned.
It's like loading your plugin into 5 Simbas or Simba tabs. They will each have their own memory and variables and stuff.
If you put a `print` in `DllMain`, it you will see that it gets called every time because Simba reloads your plugin.
Advantage: You can overwrite your plugin in the ./Simba/Plugin folder without having to restart Simba every time. If your plugin crashes or access-violates, you do not lose your script or anything.
What exactly do you mean by global variables are lost?
I am Ggzz..
Hackintosher
Old version:
I has plainly declared variables. Vars like AOB scan results, so I wouldn't need to re-search them. I stop the script they stay there, re-start script instant go. Open different script tab, amazingly it uses those previous vars instantly.
New version:
It also kills my detached debug thread, which is just annoying, I have to keep script running to display it. Loses all vars.
Plain vars:
Although new Simba feels faster than previous.
In all honesty, you should be saving them so shm or something and not rely on the process staying alive. MAYBE one day, Simba will implement some communication between tabs or processes.. Alternatively, you can inject into the process itself and keep your variables that way.. but you are doing RPM (ReadProcessMemory) right?
Maybe with some preprocessor magic in the future we'd be able to specify that stuff shouldn't unload but for now, I think that's how it'll be (like Chrome where if a tab crashes it doesn't crash the entire process and kill all tabs).
I am Ggzz..
Hackintosher
@alar82;
I made a change to my own plugins to support UTF-8. Not sure if you care, but I do suggest using it instead of the default code-page:
c++ Code:template<typename T>
T* AllocateString(std::size_t size, std::size_t element_size) noexcept
{
std::size_t new_size = (size * element_size) + sizeof(PascalString) + sizeof(T);
PascalString* ptr = static_cast<PascalString*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size));
ptr->refCount = 1;
ptr->length = size;
ptr->codePage = 65001; //CP_UTF8
ptr->elementSize = sizeof(T);
*reinterpret_cast<char*>(ptr + 1) = '\0';
return reinterpret_cast<T*>(++ptr);
}
This will technically serve you better in the long run. As a side note, if you still want to use Simba 1.3, you can compile your plugin with Mingw instead btw. Then it'll be compatible with 1.3 and you'd still get to keep your global variables.
I am Ggzz..
Hackintosher
Erm yes.
Anyhow I did find funny video that explains void* usage. https://www.youtube.com/watch?v=j0_u26Vpb4w @16:20. I think this video contains generally useful stuff for beginners.
I must ask, can that (void** Result) return multi value. Like c++ structs. So I could send several values in one go, like npc hp and location.
Edit: I has discovered that AllocateArray can take almost any struct and make array out of it, only problem seems to be strings.
Now I has thinkin to return multi values to simba. It is possible by custom record. It has to be declared before loading plugin or simba will be very confused.
Struct in c++:
Call.Code://for struct intPOINTtest { int x; int y; //string txt; };
Code:(CHAR*)"SomeFunc", (CHAR*)"Function SomeFunc(A: Int32; B: String; C: Char): Array of dataP; native;"Simba Code:program Test;
//custom data type
type
dataP= record
x: Int32;
y: Int32;
// txt: string;
end;
{$loadlib MemoryError}
begin
wait(199);
SetupRSReading(True,0);
wait(100+random(1099));
repeat
wait(5000+random(1099));
Writeln(SomeFunc(99,"test","t"));
until(false)
end.
Main problem is that it gives runtime error when I use string there, anything else is fine. It allocates fine any struct but when it comes sending it all back to simba it flops.
Well this is what I have came up so far:
1)That memcpy copy's all values, but I need to make it copy only needed values and GetMem(new_size) reserve proper size.Code:template<typename T> T* AllocateArrayTest(std::vector<intPOINTtest> value) { std::size_t new_size = (1 * sizeof(UINT32)) + sizeof(PascalArray); //x PascalArray* ptr1 = static_cast<PascalArray*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size)); ptr1->refCount = 1; ptr1->length = 1; std::memcpy(ptr1, value.data(), value.size()); //y PascalArray* ptr2 = static_cast<PascalArray*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size)); ptr2->refCount = 1; ptr2->length = 1; std::memcpy(ptr2, value.data(), value.size()); //txt PascalString* ptr3 = static_cast<PascalString*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size)); ptr3->refCount = 1; ptr3->length = 1; ptr3->codePage = 65001; //CP_UTF8 ptr3->elementSize = sizeof(T); *reinterpret_cast<char*>(ptr3 + 1) = '\0'; std::memcpy(ptr3, value.data(), value.size()); cout <<"x:"<< *(int*)ptr1 << endl; cout <<"y:"<< *(int*)ptr2 << endl; cout << "txt:" << *(char*)ptr3 << endl; return 0; }
2)Somehow pass it onto each separate dataP member on simba.
3)Can this type record(dataP) made in plugin? I mean functions can be declared. Why not this.
@alar82; Sorry for the late reply.. @Olly; alerted me about the issue a while back.. just haven't had time to reply.. but here goes:
C++ Code:PascalString* ptr3 = static_cast<PascalString*>(PLUGIN_MEMORY_ALLOCATORS.GetMem(new_size));
Does NOT allocate a string! You are casting the memory to a string but that ain't going to work.
C++ Code:#define EXPORT __declspec(dllexport)
static const char* PascalExports[] =
{
"Pascal_Alloc_Struct", "Function Pascal_Alloc_Struct(): Array of SomeRecord; native;"
};
static const char* PascalTypes[] =
{
//You don't have to use multi-line string..
//You can just make it all one string: "packed record x, y: Int32; txt: String; end;".. etc.. if you wanted.
"SomeRecord", "SomeRecord", R"(
packed record
x, y: Int32;
txt: String;
end;
)"
};
static const long int PascalExportCount = sizeof(PascalExports) / (sizeof(PascalExports[0]) * 2);
static const long int PascalTypeCount = sizeof(PascalTypes) / (sizeof(PascalTypes[0]) * 2);
int GetPluginABIVersion() noexcept
{
return 2;
}
int GetFunctionCount() noexcept
{
return PascalExportCount;
}
int GetTypeCount() noexcept
{
return PascalTypeCount;
}
int GetFunctionInfo(int Index, void** Address, char** Definition) noexcept
{
if (Index < PascalExportCount)
{
*Address = (void*)GetProcAddress(module, PascalExports[Index * 2]);
strcpy(*Definition, PascalExports[Index * 2 + 1]);
return Index;
}
return -1;
}
int GetTypeInfo(int Index, char** Type, char** Definition) noexcept
{
if (Index < PascalTypeCount)
{
strcpy(*Type, PascalTypes[Index * 2 + 0]);
strcpy(*Definition, PascalTypes[Index * 2 + 1]);
return Index;
}
return -1;
}
C++ Code:extern "C" {
void Pascal_Alloc_Struct(void** Params, void** Result);
}
typedef struct
{
std::int32_t x;
std::int32_t y;
char* txt;
} __attribute__((__packed__)) SomeRecord; //#pragma push(1) //#pragma pack(1)
void Pascal_Alloc_Struct(void** Params, void** Result)
{
SomeRecord* arr = AllocateArray<SomeRecord>(4); //allocate however many you want..
for (std::uint32_t i = 0; i < 4; ++i) //fill them..
{
arr[i].x = i + 1;
arr[i].y = i + 1;
arr[i].txt = AllocateString<char>(11); //string length..
strcpy(arr[i].txt, "Hello World"); //copy string..
}
PascalWrite(Result, arr);
}
Result:
Simba Code:Succesfully compiled in 121 milliseconds.
[{X = 1, Y = 1, TXT = Hello World}, {X = 2, Y = 2, TXT = Hello World}, {X = 3, Y = 3, TXT = Hello World}, {X = 4, Y = 4, TXT = Hello World}]
Last edited by Brandon; 07-02-2020 at 02:23 PM.
I am Ggzz..
Hackintosher
There are currently 1 users browsing this thread. (0 members and 1 guests)