During some more testing I noticed the `eject` program was failing to eject the disc sometimes and I think it comes down to all the device resources not being removed yet. (The CDROMEJECT ioctl was returning EBUSY.) Adding in a small delay fixes it for me (was able to run eject 10 times with no failure when before it would fail like one every three times). As for why it wasn't happening before, I can only assume that the extra overhead from the shell system() makes was accounting enough for it. The util-linux eject program doesn't actually open the block device until it does the unmounting (also by calling umount) so the extra overhead from opening the device might add enough delay there as well.
I'm not super happy with this fix but as FSCTL_DISMOUNT_VOLUME normally takes a couple seconds anyway it probably won't cause any serious performance issues.