views:

368

answers:

5

The process is elevated and I ensured that the path was correct in VS debugger (I'm using Environment.GetFolderPath(Environment.SpecialFolder.System) not hard coding it in) but File.Exists still returns false.

The reason I need this is a workaround for ensuring some 3rd party drivers are installed because their registry settings aren't removed on uninstall.

I know writes are redirected via virtualization but is this also true for checking a file's existence?

+2  A: 

Is your process 32 bit or 64 bit? and are the drivers 64 or 32? What I'm getting at is that maybe your host OS redirects you to the Wow64 folder instead.

Remus Rusanu
A: 

This is an virtualization issue - the file just isn't there. You will have to look for it in the folder the contains the virtualized files.

Daniel Brückner
A: 

If you have the rights, why don't you attempt to create a file in the same location in your code, and see where it ends up? As suggested by another, Windows might be redirecting your call based on a few settings.

Also, you could try doing a DirectoryInfo and enumerating Files it contains to see if anything looks familiar.

rwmnau
+7  A: 

Yes, virtualization happens at a very low level. The File.Exists method basically calls the Win32 CreateFile method and checks for errors. CreateFile is redirected by the WOW subsystem.

You can disable virtualization temporarily before calling.

[DllImport( "kernel32", CharSet=CharSet.Unicode, SetLastError=true )]
public static extern bool Wow64DisableWow64FsRedirection( ref IntPtr oldValue );

[DllImport( "kernel32", CharSet=CharSet.Unicode, SetLastError=true )]
public static extern bool Wow64RevertWow64FsRedirection( IntPtr oldValue );

Of course to be complete you'll have to check for file existence with virtualization on as well as off. The same applies for checking registry entries as well.

public static bool FileExists( string path )
{
    if( File.Exists( path ) ) return true;
    IntPtr oldValue = IntPtr.Zero;
    try
    {
        if( Environment.GetEnvironmentVariable( "PROCESSOR_ARCHITEW6432" ) == null )
            return false;

        Wow64DisableWow64FsRedirection( ref oldValue );
        if( File.Exists( path ) ) return true;

        return false;
    }
    finally
    {
        if( oldValue != IntPtr.Zero )
            Wow64RevertWow64FsRedirection( ref oldValue );            
    }   
}

Update: You may also need to check the OS version before disabling the WOW redirection because earlier versions of XP (Pre SP2 I believe) do not expose those methods.

Update 2: Added OS check for 64-bit. All 64-bit versions of the OS implement these methods and you only need to disable the sate if running on a 64-bit OS.

Paul Alexander
So with the try/finally do I still need to check the OS version? I suppose the finally block would also throw if it's not supported.
Davy8
Yes - the finally block still calls the Wow64XXX method.
Paul Alexander
+1  A: 

Have you tried disabling folder virtualization for your app? You'll need add a manifest file containing:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

However, if you need to write to those folders you'll have to request admin ability. To do that, change level="asInvoker" to level="requireAdministrator" in the xml.

Wilka