Chaos Project

Game Development => Sea of Code => Topic started by: newold on September 04, 2018, 05:56:16 pm

Title: Help with dll to use with RPG Maker
Post by: newold on September 04, 2018, 05:56:16 pm
Hi all. I have the following problem:

In RPG Maker i have an array with this struct: [long, long, string]. Then, using Ruby function pack, i create this string:  [long, long, string].pack("lla*") and then i pass this string to my dll and i try change values with my function in dll. I can change value 0 and value 1, but not my string (value 2)

c++ DLL:

#include "stdafx.h"
#include <iostream>
#include <windows.h>

#define RGSSApi extern "C" __declspec(dllexport)

// I pass this struct from RPG Maker
struct ALGO
{
long value1;
long value2;
char * value3;
};


// This function is called by rpg maker and modify values.
RGSSApi void prueba(ALGO * object)
{
object->value1 = 100;
object->value2 += 200;
object->value3 = (char *)"other text";

}


RGSS script:

# My DLL
f = Win32API.new("f/MyDll.dll", "prueba", "P", "")

a = [1, 10, "Initial Text"] # My array

t = a.pack("lla*") # Pack array to string

# Show array 'a' contents, current 't' and 't' unpack
# a[0] = 1,  a[1] = 10,  a[2] = "Initial Text"
p a, t, t.unpack("lla*")

f.call(t) # Call function in c++ passing the value 't'

# Show array 'a' contents, current 't' and 't' unpack
# a[0] = 100,  a[1] = 210,  a[2] = value is wrong (it is different to "initial Text" (defined in rgss) and different to "other text" (defined in dll))
p a, t, t.unpack("lla*")

exit




any help here? im stuck :(
Title: Re: Help with dll to use with RPG Maker
Post by: KK20 on September 04, 2018, 09:36:17 pm
First off, you don't want to be using 'a' for your pack directive. A pointer is an unsigned long/integer. You want to pass to your DLL the address to your string. What you were doing was basically telling your DLL "My string is located at the address 1953066569" (explanation: take the first four bytes of your string, which is 'Init', and use an ASCII table to convert to hex, which is 49 6E 69 74, which in little endian (74 69 6E 49) is equal to the decimal value 1953066569).

Normally, you would just do this:

DLL:

void DLL_EXPORT foobar(char * mystring) { ... }

Ruby:

my_str = 'This is my string!'
Win32API.new('MyDLL', 'foobar', 'P', '').call(my_str)

Since the Ruby String object itself is a char pointer.

But when you put it into a struct/Ruby Array, we are forced to pack it now. So the question is what directive to use? Since we want the address of the string, then we should use 'P' (pointer to a structure (fixed-length string)).
t = a.pack("llP") # Pack array to string

Then we can pass t to the DLL. No need to unpack anything when it's done; you can print a to see the changes.

Now a word of advice: if you are passing a string to a DLL and want to change it, you have to manipulate the string you passed in directly. You can't just set it to a new string...that's going to be stored in a different memory address! Instead, use something like memcpy
memcpy(object->value3, (char*)"other string", 12);

Also be aware that the length of the original string is the absolute maximum size your string can be when inside the DLL (don't pass in an empty string and expect to fill it in with new characters. Null pad your string if you must: "\0" * 50 for example). Be aware that memcpy just writes over your existing string; if the replacement string is shorter, some of your original string's characters will still show through. This is why it's generally a good idea to pass in an integer to designate the size of your string.

I tested all of this myself just to make sure.
Title: Re: Help with dll to use with RPG Maker
Post by: newold on September 05, 2018, 05:06:12 am
Thanks for the info! I could solve the problem. In ruby pack i needed use 'p' for string, my string in ruby needed fixed length and in my dll i need use memcpy to change string. Now works perfet Thanks.