filePath is declared as an array within SetName - so allocates memory on the stack - into which you copy your string and then set .name to point to that memory.
SetName then returns - so the filePath memory is cleaned up as the stack frame unwinds (and may be reused later for other things in subsequent calls) - but .name still points to that, now invalid, memory.
So when you then call PrintName, who knows what the memory that .name points to might then contain! If it still contained your string that would be purely coincidence - unlikely because the PrintName call / stack frame itself stands a fair chance of overwriting it - and unfortunate because it would hide a nasty bug.
Remember, your .name is only a pointer to a string - your _file struct does not contain the actual string itself.
Somewhere you need to manage the memory that the string is stored in.
If you declared name using:
TCHAR name[MAX_PATH]
and then copied the string to it using
StringCchCopy((*image).name, MAX_PATH, dir)
that works - the string is now stored in the _file struct and not on the stack.
Alternatively, manage the memory for your strings elsewhere outside _file and outside SetName - and continue to use pointers.
Which route you go depends in part on things like efficient use of memory, avoiding copying strings from one place to another more often than necessary etc.
Hope this helps.