Page 2 of 3 FirstFirst 123 LastLast
Results 26 to 50 of 55

Thread: Export strings to pascal

  1. #26
    Join Date
    Nov 2011
    Location
    England
    Posts
    3,072
    Mentioned
    296 Post(s)
    Quoted
    1094 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    So you bypass FFI by exporting the method with Params array and Results array? Looks similar to how Simba exports its internal functions. :O Actually didn't know you could do that..
    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

  2. #27
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default



    What is going on here, some kind of error huh.

  3. #28
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post


    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

  4. #29
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Code:
    if !defined(_MSC_VER)
    #define DELPHI_CALLING_CONVENTION __attribute__((regparm(3)))
    
    #endif
    Between those lines code is grayed out and then goes into red again. Do I have to do something extra?

  5. #30
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    Code:
    if !defined(_MSC_VER)
    #define DELPHI_CALLING_CONVENTION __attribute__((regparm(3)))
    
    #endif
    Between those lines code is grayed out and then goes into red again. Do I have to do something extra?

    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

  6. #31
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Hey Brandon. Now I had time to look at it again. I has put it all together into header file.
    In main.
    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;
    }
    Other header file.
    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);
    }
    It does compile.
    But when I try to call AllocateArray(100);
    It complains that int type doesn't fit there.

  7. #32
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    It does compile.
    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

  8. #33
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    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.
    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;
    }
    Now SetPluginSimbaMemoryAllocators is definitely being called when plugin is loaded in. Text is printed.

    Nows using it, How=?

    Added this to pascal exports:
    Code:
    CHAR* PascalExports[] =
    {
    (CHAR*)"SomeFunc", (CHAR*)"Procedure SomeFunc(A: Int32) native;"
    }
    Edit44:
    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?

  9. #34
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    Thanks for helping. Nows it does somethin.
    Edit44:
    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

  10. #35
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    Omg with 1400 build it works!!
    I had 1302.

  11. #36
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    Omg with 1400 build it works!!
    I had 1302.

    Lol. Yay. Now you can take advantage of Simba's automatic memory management for Strings, Arrays, and Objects (in any language)
    Primitives are already managed

    Enjoy.
    Last edited by Brandon; 05-07-2020 at 04:22 AM.
    I am Ggzz..
    Hackintosher

  12. #37
    Join Date
    May 2018
    Posts
    4
    Mentioned
    0 Post(s)
    Quoted
    0 Post(s)

    Default

    Which IDE are you using for development/testing?

  13. #38
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    That is a funny question. If you look at this thread carefully u will find out.

  14. #39
    Join Date
    May 2018
    Posts
    4
    Mentioned
    0 Post(s)
    Quoted
    0 Post(s)

    Default

    Is it MSVC (Microsoft Visual Stuido with C++)?

  15. #40
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    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.
    Code:
    PascalRead<vector<int>>(Params[0]);
    First params[0] is declared at pascal exports as array of INT32.
    Also noticed this code:
    Code:
    	
    PascalArray* mem = static_cast<PascalArray*>(Params[0]);
    	cout << mem->length << endl;
    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.


    Edit: @BeatDat yes it is Most simplistic IDE there is in my opinion. Community edition 2019, it is free.

  16. #41
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    ....


    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

  17. #42
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Quote Originally Posted by Brandon View Post

    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.
    My global variables are lost:I

  18. #43
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    My global variables are lost:I

    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

  19. #44
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Quote Originally Posted by Brandon View Post
    What exactly do you mean by global variables are lost?
    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.

  20. #45
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    Quote Originally Posted by alar82 View Post
    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

  21. #46
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    @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

  22. #47
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    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.

  23. #48
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    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++:
    Code:
    //for
    struct intPOINTtest {
    	int x;
    	int y;
    	//string txt;
    };
    Call.
    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.

  24. #49
    Join Date
    Jul 2009
    Posts
    166
    Mentioned
    5 Post(s)
    Quoted
    69 Post(s)

    Default

    Well this is what I have came up so far:
    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;
    }
    1)That memcpy copy's all values, but I need to make it copy only needed values and GetMem(new_size) reserve proper size.

    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.

  25. #50
    Join Date
    Feb 2011
    Location
    The Future.
    Posts
    5,600
    Mentioned
    396 Post(s)
    Quoted
    1598 Post(s)

    Default

    @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

Page 2 of 3 FirstFirst 123 LastLast

Thread Information

Users Browsing this Thread

There are currently 2 users browsing this thread. (0 members and 2 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •