Open Risto-Paasivirta opened 9 months ago
I did not manage to fix this easily other than modify the C++ side to pass the information as char** arrays instead of safearrays.
Here is an example on how I managed to Marshal a string array of unknown length from the C++ to C# This might be better than to rely on the safearrays, I could not find any information on if this is some version or runtime SDK related thing on why the conversion 29 is not working for me on any machine.
DIRECTINPUTFORCEFEEDBACK_API const char** TestMarshal(int* count);
DIRECTINPUTFORCEFEEDBACK_API void FreeStrings(const char** strings, int count);
const char** TestMarshal(int* count) {
// Example strings
const char* strings[] = { "Marshal", "String", "Array", "Test", nullptr };
// Calculate the number of strings
*count = 0;
while (strings[*count] != nullptr) {
*count += 1;
}
// Allocate memory for the array of strings
const char** result = new const char* [*count];
for (int i = 0; i < *count; ++i) {
result[i] = _strdup(strings[i]);
}
return result;
}
void FreeStrings(const char** strings, int count) {
for (int i = 0; i < count; ++i) {
free((void*)strings[i]);
}
delete[] strings;
}
And here is the C# part
[DllImport(DLLFile)] public static extern IntPtr TestMarshal(out int count);
[DllImport(DLLFile)] public static extern IntPtr FreeStrings(IntPtr strings, int count);
public static string[] TestMarshaling()
{
IntPtr stringsPtr;
int count;
stringsPtr = Native.TestMarshal(out count);
// Read the array of strings directly from memory
string[] resultStrings = new string[count];
for (int i = 0; i < count; ++i)
{
IntPtr currentPtr = Marshal.ReadIntPtr(stringsPtr, i * IntPtr.Size);
// Read each character until a null character is encountered
int charIndex = 0;
byte currentByte;
while ((currentByte = Marshal.ReadByte(currentPtr, charIndex)) != 0)
{
charIndex++;
}
// Allocate a byte array and copy the characters
byte[] bytes = new byte[charIndex];
Marshal.Copy(currentPtr, bytes, 0, charIndex);
// Not sure if need to use different encoding?
resultStrings[i] = System.Text.Encoding.ASCII.GetString(bytes);
}
// Free the memory allocated in C++
Native.FreeStrings(stringsPtr, count);
return resultStrings;
}
Wonderful, this will help massively. I will admit, extended characters slipped my mind 😅. The SAFEARRAY started just to run some tests during development. I'm just doing some interviews, but I'll get to this issue in the coming days.
If you don't mind me asking, what's your use case for this library?
I can't say much about the project since I'm under NDAs, it is a work for a customer (non-game simulation), and we need to convey forces back to the user as it is vital component of the simulation. Good thing is that the end machines are pre-known hardware so we don't need to cater to various different setups as the program is not made for public use.
Overall it works and I want to thank you for the hard work you have put into this plugin 👍 Weird that Unity hasn't done anything like this by default with their new input system.
If there's anything I can help with polishing this let me know. C++ is not my forte, but ChatGPT is helping me greatly to get things rolling 😄
Cannot call certain functions of the library: GetDeviceCapabilities GetActiveDevices
Throws an error of: MarshalDirectiveException: string/stringbuilder marshalling conversion 29 not implemented