首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >非英语地区的文件损坏(编码问题?)

非英语地区的文件损坏(编码问题?)
EN

Stack Overflow用户
提问于 2019-07-26 13:19:05
回答 3查看 244关注 0票数 1

在我的中,我有一个自定义的VBScript操作,它将一些文件从‘二进制’表中提取到文件系统。这是我使用的代码:

https://www.itninja.com/question/how-to-call-an-exe-which-is-stored-in-a-binary-table-through-a-vbscript-custom-action-in-the-msi的启发

代码语言:javascript
复制
Function ExtractFromBinary(ByVal binaryName, ByVal binaryOutputFile)

 Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")

 Const msiReadStreamInteger = 0
 Const msiReadStreamBytes = 1
 Const msiReadStreamAnsi = 2 
 Const msiReadStreamDirect = 3

 Dim binaryView : Set binaryView = Session.Database.OpenView("SELECT Data FROM Binary WHERE Name = '" & binaryName & "'") 
 binaryView.Execute

 Dim binaryRecord : Set binaryRecord = binaryView.Fetch 
 Dim binaryData : binaryData = binaryRecord.ReadStream(1, binaryRecord.DataSize(1), msiReadStreamAnsi) 
 Set binaryRecord = Nothing

 Dim binaryStream : Set binaryStream = oFSO.CreateTextFile(binaryOutputFile, True, False) 
 binaryStream.Write binaryData
 binaryStream.Close
 Set binaryStream = Nothing 

End Function

这已经使用了2-3年,没有任何问题的生产。但是,现在有一个关于日本Windows安装的例子,即提取的二进制文件已损坏:

正如您所看到的,问题通常发生在“?”之后。其中,脚本要么插入'E',要么覆盖以下字符。

ReadStream方法和CreateTextFile方法都有影响编码的参数。上面显示的组合似乎是在我的英语Windows 10上唯一有效的组合。

我需要在上面的代码中修改什么才能使它在日本系统上也能工作呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-07-30 11:55:55

这就是我最后的下场。

正如斯坦·斯穆尔建议的那样,我使用C# (.NET / DTF)重写了自定义操作。最初,我不太愿意用C#编写自定义操作,因为它为安装程序引入了额外的先决条件。但是事实证明,如果自定义操作的目标是.NET Framework2.0,那么大多数机器都应该支持它,而不需要手动安装该框架(参见这里)。

这是我的密码:

代码语言:javascript
复制
public static class TemporaryFilesExtractor
{

    [CustomAction]
    public static ActionResult ExtractTemporaryFiles(Session session)
    {
        ExtractFromBinary(session, "binaryname1", "<filePath1>");
        ExtractFromBinary(session, "binaryname2", "<filePath2>");
        return ActionResult.Success;
    }

    private static void ExtractFromBinary(Session session, string binaryName, string binaryOutputFile)
    {
        session.Log($"Extracting {binaryName} to {binaryOutputFile}");
        byte[] buffer = new byte[4096];

        using (var view = session.Database.OpenView("SELECT Data FROM Binary WHERE Name = '{0}'", binaryName))
        {
            view.Execute();
            using (var record = view.Fetch())
            using (var dbStream = record.GetStream(1))
            using (var fileStream = File.OpenWrite(binaryOutputFile))
            {
                int count;
                while ((count = dbStream.Read(buffer, 0, buffer.Length)) != 0)
                    fileStream.Write(buffer, 0, count);
            }
        }
    }

}
票数 1
EN

Stack Overflow用户

发布于 2019-07-29 12:42:05

@,我会提出这个问题作为一个答案,即使它是受你的测试(我没有办法测试我在哪里)!

我已经包含了一个这里更新的方法 (您需要向下滚动到第二个示例)

它使用msiReadStreamDirect (而不是msiReadStreamAnsi)提取字节对的字符串,将它们转换为二进制,并使用ADODB.Stream (而不是FSO)创建输出文件。

代码语言:javascript
复制
Dim oFSO : Set oFSO = CreateObject("Scripting.FileSystemObject")

Dim tempFolder : tempFolder = oFSO.GetSpecialFolder(2) 
Dim outputFile : outputFile = tempFolder & "\notepad.exe"

extractFromBinary "notepad", outputFile

Function MultiByteToBinary(MultiByte)
  'obtained from http://www.motobit.com
  'MultiByteToBinary converts multibyte string To real binary data (VT_UI1 | VT_ARRAY)
  'Using recordset
  Dim RS, LMultiByte, Binary
  Const adLongVarBinary = 205
  Set RS = CreateObject("ADODB.Recordset")
  LMultiByte = LenB(MultiByte)
  If LMultiByte>0 Then
    RS.Fields.Append "mBinary", adLongVarBinary, LMultiByte
    RS.Open
    RS.AddNew
      RS("mBinary").AppendChunk MultiByte & ChrB(0)
    RS.Update
    Binary = RS("mBinary").GetChunk(LMultiByte)
  End If
  Set RS = Nothing
  MultiByteToBinary = Binary
End Function

Function SaveBinaryData(FileName, ByteArray)
  Const adTypeBinary = 1
  Const adSaveCreateOverWrite = 2

  'Create Stream object
  Dim BinaryStream
  Set BinaryStream = CreateObject("ADODB.Stream")

  'Specify stream type - we want To save binary data.
  BinaryStream.Type = adTypeBinary

  'Open the stream And write binary data To the object
  BinaryStream.Open
  BinaryStream.Write ByteArray

  'Save binary data To disk
  BinaryStream.SaveToFile FileName, adSaveCreateOverWrite

  Set BinaryStream = Nothing
End Function

Function extractFromBinary(ByVal binaryName, ByVal binaryOutputFile)

    Const msiReadStreamInteger = 0 
    Const msiReadStreamBytes = 1 
    Const msiReadStreamAnsi = 2  
    Const msiReadStreamDirect = 3

    Dim binaryView : Set binaryView = Session.Database.OpenView("SELECT * FROM Binary WHERE Name = '" & binaryName & "'")  
    binaryView.Execute

    Dim binaryRecord : Set binaryRecord = binaryView.Fetch  
    Dim binaryData : binaryData = binaryRecord.ReadStream(2, binaryRecord.DataSize(2), msiReadStreamDirect)  
    Set binaryRecord = Nothing  

    'convert to string of byte pairs to binary
    binaryData = MultiByteToBinary(binaryData)

    'save binary data
    SaveBinaryData binaryOutputFile, binaryData

End Function

Set oFSO = Nothing
票数 2
EN

Stack Overflow用户

发布于 2019-07-26 19:23:39

日文代码页:从这篇博客文章中:“二进制文件和文件系统对象不混合”:“在日本代码页中,简单的- Chr (E0)甚至不是一个法律字符,所以Chr会将它变成一个零.不要使用FSO来读取/写入二进制文件,你只是要求一个伤害的世界,只要有人在DBCS-土地运行你的代码。”

替代品?,.NET怎么样?我意识到您正在进行自定义操作太晚了,我将这些示例作为独立的.NET控制台应用程序制作。WiX框架具有创建DTF自定义操作的机制。在github.com上找到了这个

重哈希?:我们能问一下你到底在做什么吗?为什么要用这种方式提取文件?如果您解释这个场景,还可能有其他更可靠的方法吗?

DTF / .NET:虽然我不是部署使用的超级.NET迷(依赖层太多了),但我认为在这方面使用.NET / DTF会更好。什么是DTF?

Sample DTF C# Application:下面是一个简单的C#示例应用程序,展示了从二进制表中提取二进制流的一种方法(还有其他几种方法,我不是.NET专家)。

  1. 创建一个新的C#控制台应用程序(.NET框架)。
  2. 粘贴下面的代码并调整参数。
  3. 添加对Microsoft.Deployment.WindowsInstaller.dll (DTF框架)的引用。
代码语言:javascript
复制
using Microsoft.Deployment.WindowsInstaller;

namespace MSIExtractBinaryTableEntry
{
    class Program
    {
        static void Main(string[] args)
        {
            // ADJUST 1: Name of Binary Table Entry
            var binarytableentry = "ImageBmp"; 

            // ADJUST 2: Source MSI path
            var msifullpath = @"C:\MySetup.msi";

            // ADJUST 3: Output target path for binary stream
            var binaryfileoutputpath = @"C:\Output.XXX";

            using (var db = new Database(msifullpath, DatabaseOpenMode.ReadOnly))
            {
                using (var binaryView = db.OpenView("SELECT Name, Data FROM Binary WHERE Name='" + binarytableentry + "'"))
                {
                    binaryView.Execute();
                    binaryView.Fetch().GetStream(2, binaryfileoutputpath); // force overwrites output path
                }
            }
        }
    }
}

Alternative:这里是一个调整,它将整个二进制表导出到用户桌面上的一个名为"Output“的文件夹。

与上面创建测试项目的过程相同。只需指定一个参数:输入MSI的完整路径。

代码语言:javascript
复制
using System;
using System.IO;
using Microsoft.Deployment.WindowsInstaller;

namespace MSIExtractBinaryTableEntry
{
    class Program
    {
        static void Main(string[] args)
        {
            // ADJUST 1: Specify MSI file path
            var msifullpath = @"C:\MySetup.msi";

            var outputpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), @"Output\");
            Directory.CreateDirectory(outputpath);

            using (var db = new Database(msifullpath, DatabaseOpenMode.ReadOnly))
            {
                using (var binaryView = db.OpenView("SELECT Name, Data FROM Binary"))
                {
                    binaryView.Execute();

                    foreach (var rec in binaryView)
                    {
                        rec.GetStream("Data", outputpath + rec.GetString("Name"));
                    }
                }
            }
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57220922

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档