【问题标题】:InstallScript GetLine() can not read text file contains result from command promptInstallScript GetLine() 无法读取包含命令提示符结果的文本文件
【发布时间】:2018-05-07 21:41:22
【问题描述】:

我的安装需要检查来自cmd.exe 的命令的结果。因此,我将命令的结果重定向到一个文本文件,然后尝试读取该文件以获得如下结果:

// send command to cmd to execute and redirect the result to a text file

// try to read the file
szDir = "D:\\";
szFileName = "MyFile.txt";

if Is(FILEEXISTS, szDir ^ szFileName) then
    listID = ListCreate(STRINGLIST);
    if listID != LIST_NULL then
        if OpenFIleMode(FILE_MODE_NORMAL) = 0 then
            if OpenFile(nFileHandle, szDir, szFileName) = 0 then

                // I run into problem here
                while (GetLine(nFileHandle, szCurLine) = 0 )
                    ListAddString(listID, szCurLine, AFTER);
                endwhile;
                CloseFile(nFileHandle);

            endif;
        endif;
    endif;
endif;

问题是,在执行命令提示符并将结果重定向到MyFile.txt 之后,我可以设置打开文件模式,打开文件但我无法将任何文本读入我的列表中。 ListReadFromFile() 没有帮助。如果我打开文件,手动编辑并保存它,我的脚本就可以工作了。

经过调试,我发现GetLine() 返回一个错误代码(-1),这意味着文件指针必须在文件末尾或其他错误。但是,FILE_MODE_NORMAL 将文件设置为只读并在文件开头设置文件指针。

我可能做错了什么?这与文件的读/写访问有关吗?我试过这个命令没有结果:

icacls D:\MyFile.txt /grant Administrator:(R,W)

我正在使用 IstallShield 2018 和 Windows 10 64 位 btw。非常感谢您的帮助。

编辑 1:我怀疑编码并尝试了一些方法:

  1. 运行“wslconfig /l”后,在Notepad++中打开的MyFile.txt内容没有编码,但仍正常可读。我尝试将内容转换为 UTF-8,但没有成功。

  2. 1234563 NULL (\0) 被添加到每个字符之间,甚至替换换行符。也许这就是 GetLine() 读取文件失败的原因。
  3. 解决方法:在第 1 步之后,我运行“find "my_desired_content" MyFile.txt” > TempFile.txt 并读取 TempFile.txt(以 UTF-8 编码)。

我的最终目标是检查“my_desired_content”是否出现在“wslconfig /l”的结果中,所以这很好。但是,我不明白的是 MyFile.txt 和 TempFile.txt 都是从 cmd 命令创建的,但它们的编码不同?

【问题讨论】:

  • 鉴于下面 Michael 描述的问题,您能否在 cmd.exe 中告诉我们您在做什么,以便我们看看是否有替代方案可以避免此技术问题?
  • 简而言之,就是想在cmd.exe中运行“wslconfig”后得到结果。你可以在这里找到你要找的东西:link.
  • 是的,cmd 提示符和各种处理重定向的方式几乎是神奇的。但是echo test > echo.txtecho line2 >> echo.txtwslconfig /l > wsl.txt 产生非常不同的编码(ANSI CRLF vs Unicode CR w/o signature)。还要考虑wslconfig /l | findstr faultwslconfig /l | findstr e;两者都产生奇怪的结果。我会考虑 wslconfig 如何将其输出写入根本原因(Windows API 提供了太多方法,通常有些不兼容),但是 GetLine 在它认为是 ANSI NULL 之后无法定位 CR/LF 字符导致了这里的问题.
  • MSDN 上的这个讨论描述了相同的根本问题,即不同的程序控制自己输出的编码,如果您对 C/C++ API 层感兴趣:social.msdn.microsoft.com/Forums/windowsdesktop/en-US/… 和这个 SO 帖子有更多建议:stackoverflow.com/questions/285486/…

标签: installation command-prompt installshield


【解决方案1】:

问题出在文件的内容上。假设这是您的链接问题生成的文件,您可以在十六进制编辑器中检查其内容以找出以下事实:

  • 其内容以 UTF-16 (LE) 编码,没有 BOM
  • 它的换行符被编码为 CR 或 CR CR 而不是 CR LF

我认为换行符比文本编码更重要,但事实证明我把它倒过来了。如果我单独更改这些内容,GetLine 似乎对于 CR、CR CR 或 CR LF 都可以正常工作,但仅在 BOM 存在时才处理 UTF-16。 (也就是说,在十六进制编辑器中,文件以 FF FE 57 00 而不是以字符 W 开头的文件的 57 00 开头。)

对于解决此问题的最佳方法,我有点不知所措。如果您准备迎接挑战,您可以使用 FILE_MODE_BINARYREADONLY 读取文件,并且可以使用您对文件中应包含内容的额外知识来确保正确解释其编码。请注意,对于大多数 UTF-16,您可以通过以下方式组合两个字节来创建单个代码单元:

szResult[i] = (nHigh << 8) + nLow;

其中nHighnLow 可能是szBuffer[2*i + 1]szBuffer[2*i] 之类的值,假设您通过调用ReadBytes 填充了一个STRING szBuffer。

其他未经证实的想法包括以二进制编辑它以确保 BOM (FF FE) 存在,找出确保文件最初是使用 BOM 创建的方法,找出以替代编码创建它的方法,找到另一个命令您可以调用以“修复”文件,或向供应商(我的雇主)提出请求,并希望开发团队做出改变以更好地处理这种情况。


这里有一个更简单的解决方法。如果您可以安全地假设该命令将附加没有签名的 UTF-16 字符,则可以将此输出附加到仅具有签名的文件中。你怎么得到这样的文件?

  • 您可以在开发环境中创建一个仅包含 BOM 的文件,并将其添加到您的支持文件中。如果需要多次使用,请先复制一遍。
  • 您可以使用代码创建它。只需调用以下代码(为清楚起见省略了错误检查)

    OpenFileMode(FILE_MODE_APPEND_UNICODE);
    CreateFile(nFileHandle, szDir, szFileName);
    CloseFile(nFileHandle);
    

    如果 szDir ^ szFileName 不存在,它现在将是一个只有 UTF-16 签名的文件。

假设这个文件被称为sig.txt,那么你可以调用命令 wslconfig /l <strong>&gt;&gt; sig.txt</strong> 写入该文件。注意加倍的&gt;&gt; 用于追加。生成的文件将包含您提前创建的 Unicode 签名,以及 wslconfig 输出的 Unicode 数据,GetLine 应该可以正确解释。

这里最大的问题是这种硬编码围绕 wslconfig 的行为,并且该行为可能随时改变。这就是 Christopher 提到推荐 API 的原因,我完全同意。同时,您可以尝试通过在 cmd /U 中调用它来使其更加健壮(但我对它的作用或保证的理解充其量是模糊的),或者尝试原始方式然后使用 BOM。

【讨论】:

  • 我怀疑有类似但不完全理解和完全解决的问题,我在问题的编辑部分提到了这一点。我非常感谢您的解决方案。这可能是我一直在寻找的,但仍然需要测试。再次感谢。
  • 我想出了另一种方法:如果您可以安全地假设输出将保持 Unicode 而没有 BOM,您可以创建一个带有签名的文件并附加到它。有关详细信息,请参阅我的编辑。
【解决方案2】:

整个 WSL 的东西都很新。我没有看到任何 API,而是屏幕抓取命令输出,您可能希望查看此注册表项:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss

它似乎有来自商店的已安装发行版列表。来自商店可能解释了为什么这是 HKCU 而不是 HKLM。

一个勇敢的新世界....叹息。

【讨论】:

  • 这确实是个好主意,但不幸的是,在这个项目中,我们坚持使用“wslconfig”命令。多亏了这一点,我遇到了很多问题并学到了一些东西。所以,干杯。此外,WSL 刚刚正式发布,尽管我必须激活开发者模式才能使用它(它来自内部程序)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-16
  • 1970-01-01
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多