The only actual foolproof way is there's a low level function which will actually give you a list of where all the clusters allocated to a file are. You can walk the list and count them to get the actual size on disk, and you can see the fragmentation too while you're at it. Use the DeviceIoControl API with FSCTL_GET_RETRIEVAL_POINTERS. See good article here on the Cluster walk APIs .
What a pain.
Oh, and it's kind of an ambiguous question whether you should include the size of the MFT entry as part of the "size on disk" for a given file. Every file takes up 1k in the MFT, which may or may not include some of the file data.