我正在尝试将程序从VB6移植到C#,读取二进制文件并解析它。我没有编译时错误或警告但是当我尝试运行它时,在它进入Main()
之前它会抛出异常
System.TypeLoadException was unhandled
Message=Could not load type 'Conversion.DataStructures.ClientOld' from assembly
'SandboxConsole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because
it contains an object field at offset 1 that is incorrectly aligned or overlapped
by a non-object field.
Source=SandboxConsole
TypeName=Conversion.DataStructures.ClientOld
StackTrace:
at sandbox.Program.Main(String[] args)
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
以下是旧VB6代码的示例
Private Type SrcClientOld
Active As String * 1 '0
titleLength As Byte '1
title As String * 8 '2
lastNameLength As Byte '10
LastName As String * 25 '11
(...)
AddedBy As String * 3 '369
junk7 As String * 22 '372
End Type '394
这是我写的C#代码
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
struct ClientOld
{
[FieldOffset(0)]
public byte Active;
[FieldOffset(1)]
[MarshalAs(UnmanagedType.AnsiBStr)]
public string Title;
[FieldOffset(10)]
[MarshalAs(UnmanagedType.AnsiBStr)]
public string LastName;
(...)
[FieldOffset(368)]
[MarshalAs(UnmanagedType.AnsiBStr)]
public string AddedBy;
[FieldOffset(372)]
[MarshalAs(UnmanagedType.LPArray, SizeConst = 22)]
public byte[] Unknown7;
}
经过一些谷歌搜索后,我认为我错过了Pack = 1
,但补充说这并没有解决我的问题。
关于该怎么做的任何其他建议?
修改
第一个字符长度为一个字节,这是文件
中第一个记录的十六进制转储A.Dr.......Smith....................
41 03 44 72 2E 00 00 00 00 00 05 53 6D 69 74 68 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
| | | | ^LastName
| | ^title ^lastNameLength
| ^titleLength
^Active
EDIT2: 将我的代码更改为以下内容以消除所有其他可能的错误,它仍然给我相同的异常
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
struct ClientOld
{
[FieldOffset(0)]
public byte Active;
[FieldOffset(1)]
[MarshalAs(UnmanagedType.AnsiBStr)]
public string Title;
}
我尝试了fieldoffset(1)和2,但都没有工作。
答案 0 :(得分:1)
我认为
Active As String * 1
转换为
字符
在Unicode语言中不是1个字节,因此下一个字段偏移量不应该是1,但如果我理解了以下内容则可能为7:。
说明:
这是理解字符串的关键:当我们编写代码时:
Dim str As String str =“help”我们是 没有定义Unicode字符数组 本身。我们正在定义一个成员 数据类型称为BSTR,它很短 用于基本字符串。事实上,BSTR是 指向以null结尾的Unicode的指针 字符数组,以a开头 4字节长度字段。
编辑:
通过转储,似乎第二个成员应该具有[FieldOffset(2)],因为如果不是,它将在前一个成员上重叠。 (编辑误报,我看到有00的地方有一个03)。
答案 1 :(得分:0)
从我看到的,你混淆了“Active”和“TitleLength”的声明,似乎完全被跳过了。
答案 2 :(得分:0)
尝试使用IntPtr而不是字符串,然后调用Marshall.PtrToStringAnsi
您需要保留旧代码的确切布局才能使此转换生效。二进制文件将以上次保存的格式存储,因此您必须完全重现它,即使这意味着在任何地方都使用字节和字节数组。
如果您想要使用新的布局,可以使用旧布局创建版本,将复制值加载到新格式,然后使用新格式将其保存回来。从那时起,您可以使用新布局加载它们。在这种情况下,您的选择对于新格式来说是无穷无尽的。
答案 3 :(得分:0)
您不能将Layout = 1与LayoutKind.Explicit一起使用 http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.pack.aspx