Pass FString as a parameter to UObject::ProcessEvent(UFunction*, void*)

Hello,
I’ve been writing some c++ code that allows the user to call a function by name. Additionally, it allows the user to pass parameters and get the return values from OUT parameters. To make this easier, I’ve predefined some types that are allowed to be passed as arguments, such as bool or int32. For instance, a function with the declaration

void SomeFunc(int32 MyInt, bool& OUT_MyOutBool);

would be called like this using ProcessEvent (roughly):

UObject* Caller = // Get the caller.
UFunction* Function = // Get the ufunction associated with the given name.
int32 Value = // Get the int32 input.

uint8* Buffer = FMemory::Malloc(Function->ParamsSize);
FMemory::Memcpy(Buffer, &Value, sizeof(int32));

Caller->ProcessEvent(Function, Buffer);

bool OutBool;
FMemory::Memcpy(&OutBool, Buffer + sizeof(int32), sizeof(bool));

// Do things with the out parameter.

FMemory::Free(Buffer);

Now I want to introduce FString as an input as well. The problem is, it is an object. I can’t Memcpy the given FString into Buffer and pass it to ProcessEvent. Doing so (and using the FString inside the function) throws an exception. How can I pass objects as parameters to ProcessEvent?

I’ve tried checking engine code but intellisense is giving me a hard time looking up all the functions. Any help is appreciated.

Solved it. For anyone interested, basically anything can be passed as parameter, following these steps:

UObject* Caller = // Get the caller.
UFunction* Function = // Get the ufunction associated with the given name.

int32 IntValue = // Get the int32 input.
FString StrValue = // Get string input.

uint8* Buffer = (uint8*)FMemory_Alloca(Function->ParamsSize);
FMemory::Memzero(Buffer, Function->ParmsSize);

for (TFieldIterator<UProperty> It(Function); It && It->HasAnyPropertyFlags(CPF_Parm); ++It) {
    UProperty* FunctionProperty = *It;
    FString Type = FunctionProperty->GetCPPType();
​​​​​​​
    if (Type == "int32") {
        *Function->ContainerPtrToValuePtr<int32>(Buffer) = IntValue;
    } else if (Type == "FString") {
        *Function->ContainerPtrToValuePtr<FString>(Buffer) = StrValue;
    }
}

Caller->ProcessEvent(Function, Buffer);
1 Like

By any chance, in this part:

if (Type == "int32") { *Function->ContainerPtrToValuePtr<int32>(Buffer) = IntValue; } else if (Type == "FString") { *Function->ContainerPtrToValuePtr<FString>(Buffer) = StrValue; }

Shouldn’t it be like this?

if (Type == "int32") { *FunctionProperty->ContainerPtrToValuePtr<int32>(Buffer) = IntValue; } else if (Type == "FString") { *FunctionProperty->ContainerPtrToValuePtr<FString>(Buffer) = StrValue; }

UFunction doesn’t have that “ContainerPtrToValuePtr” function, it’s something from UProperty.

1 Like

UFunctions and UProperties have been changed in 4.24 or 4.25. This post is valid for 4.22 as I have posted. Though I no longer maintain it so I dont know the correct way for later versions.