As @blabb says undname is correct so it's your other tool that is 'incorrect'.
However, it's worth looking at this in more detail as it's probably not as incorrect as you think.
To understand this though you have to delve a little into ABIs and think how a C++ function call works in practice.
Firstly, a C++ member function is in some sense like a C function with a 'hidden' this
pointer passed as the first parameter. (This is what __thiscall
is saying behind the scenes.)
// this function
void class::member();
// is really
void __thiscall class::member();
// and works like
void __stdcall class_member( Class* this );
Secondly, the caller of function returning a ('complicated') struct/class is responsible for allocating the memory for the struct/class and passing the function a pointer to this memory. The function can then write the relevant details there. Hence -
// this function
complex_struct_return_type function();
// works like
void function( complex_struct_return_type * );
Putting these together (and ignoring accessiility specifiers)-
// this function
FName __thiscall User::GetClassNameW( int param );
// works like
void __stdcall User_GetClassNameW( User* this, FName* pointer_to_return_value, int param );
You will see this is very similar is essence to your other tool's output.
I'd just observe that -
- it is still labelling the function as
__thiscall
. This doesn't quite make sense but is probably being done to indicate that the first parameter has special treatment in 32-bit code.
- it is changing the case of the initial letters. This again is strictly incorrect.
How these parameters get passed (by msvc) depends on whether it's compiled for 32 or 64-bit .
- For 32-bit code,
this
has special treatment and is passed in ecx
with the rest of the parameters on the stack.
- For 64-bit code,
this
is treated as like the other parameters and hence, being the first of up to 4 parameters being passed in registers will be in rcx