• C# File.Exists 判断系统文件,警惕32位和64位的差异


    今天在调试一个Winform程序,使用File.Exists 判断一个已经存在的驱动文件,程序一直返回false。因为驱动文件属于系统目录,心想难道是权限不够导致的?然后用管理员身份运行软件,依然返回false。吓的我赶紧去系统目录C:Windowssystem32drives 搜索该文件,一看在这里啊,怎么还是返回false。开始还以为VS出问题了,然后尝试判断一个D盘下的文件,发现可以判断成功。

    判断代码如下

    // 获取系统目录
    var system = Environment.GetFolderPath(Environment.SpecialFolder.System);
    var filePath = system + @"driversevserial7.sys";
    var flag = File.Exists(filePath);
    MessageBox.Show("系统路径:" + filePath + "
    " + "checkDrives:" + flag);

    运行结果

    在系统中找文件确实存在,如下图

    奇怪在于当我把程序设置成Release运行的时候判断又成功了,第一张图Debug运行的,下图是Release

    当时心想为什么Release和Debug不一样呢,一时有点诧异,然后就想着,看看反编译后的IL代码,看两者是不是有什么差别?

    Debug反编译

    Release反编译

    这样看两者并没有任何差异,因为我们判断是路径,所以我们只看IL中路径是否有不同编译, 两者中IL_0002: call string [mscorlib]System.Environment::GetFolderPath(valuetype [mscorlib]System.Environment/SpecialFolder)都是一样的,说明系统路径一样,后面拼接字符串更加不会有任何差别。

    最终通过stackoverflow找到原因,因为我当前程序编译的是32位即X86,32位应用程序在64位系统中是无法访问system32目录的。为什么我程序要选择编译32位呢,因为我程序当中需要调用一个C++写的dll,该dll是32位的,我无法改变。如果我程序编译时选择AnyCPU或者X64,那么该dll是无法调用的。所以我只能改成X86。

    为什么当我用Release又能判断正确,原因在于上图的这个生成配置页面在Release的时候目标平台仍然是:Any CPU。(不是X86),所以能判断成功。当把Release模式的目标平台改为X86后结果就是false了。

    那么编译的32位程序到底该怎么判断64位系统中的系统文件呢?其实当我们32位应用程序访问system32文件夹的时候,64位系统会自动帮我们重定向到SysWoW64文件夹。通过专业解释该文件夹主要是被设计用来处理许多在32-bit Windows和64-bit Windows之间的不同的问题,使得可以在64-bit Windows中运行32-bit程序。

    所以我们在32位程序的时候判断系统路径其实已经重定向到了:  C:WindowsSysWoW64driversevserial7.sys,这是系统自动重定向,所以IL代码中我们也看不到差异。这个目录肯定不存我们的文件,所以导致返回判断false。

    那我们如何在32位下真正的访问system32目录呢?不要系统重定向。使用 C:WindowsSysNative路径,这是个虚拟路径,我们在Windows资源管理器中是无法找到的。但是他最终还是会指向到system32中。SysNative文件夹目的就是让32位应用程序访问64位系统文件的方法。

    现在我将代码改下,前面的 Environment.GetFolderPath(Environment.SpecialFolder.System)是获取system32这里要改为Environment.SpecialFolder.Windows,获取windows目录,并在下面拼接上Sysnative目录。

    这只是在判断系统文件的时候会存在32位和64位的差异,普通文件就不存在任何影响了。

    最后修改代码如下

    // 获取windows目录
    var system = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
    var filePath = system + @"Sysnativedriversevserial7.sys";
    var flag = File.Exists(filePath);
    MessageBox.Show("系统路径:" + filePath + "
    " + "checkDrives:" + flag);

    运行结果

  • 相关阅读:
    修改mysql密码的四种方法
    phpcms模板生成原理
    如何给虚拟主机安装phpMyAdmin
    如何修改数据库密码
    web 服务器、PHP、数据库、浏览器是如何实现动态网站的
    编写shell时,提示let/typeset:not found
    Linux下采用VI编辑器删除复制或移动多行文本内容
    BASH 学习笔记小结
    list容器的C++代码实现
    Groovy入门教程
  • 原文地址:https://www.cnblogs.com/rui1236/p/13381322.html
Copyright © 2020-2023  润新知