在我的中,我有一个自定义的VBScript操作,它将一些文件从‘二进制’表中提取到文件系统。这是我使用的代码:
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上唯一有效的组合。
我需要在上面的代码中修改什么才能使它在日本系统上也能工作呢?
发布于 2019-07-30 11:55:55
这就是我最后的下场。
正如斯坦·斯穆尔建议的那样,我使用C# (.NET / DTF)重写了自定义操作。最初,我不太愿意用C#编写自定义操作,因为它为安装程序引入了额外的先决条件。但是事实证明,如果自定义操作的目标是.NET Framework2.0,那么大多数机器都应该支持它,而不需要手动安装该框架(参见这里)。
这是我的密码:
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);
}
}
}
}发布于 2019-07-29 12:42:05
@,我会提出这个问题作为一个答案,即使它是受你的测试(我没有办法测试我在哪里)!
我已经包含了一个这里更新的方法 (您需要向下滚动到第二个示例)
它使用msiReadStreamDirect (而不是msiReadStreamAnsi)提取字节对的字符串,将它们转换为二进制,并使用ADODB.Stream (而不是FSO)创建输出文件。
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发布于 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专家)。
Microsoft.Deployment.WindowsInstaller.dll (DTF框架)的引用。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的完整路径。
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"));
}
}
}
}
}
}https://stackoverflow.com/questions/57220922
复制相似问题