System.TypeLoadException: не удалось загрузить тип 'x' из сборки 'y' - PullRequest
1 голос
/ 04 мая 2011

Я пытаюсь перенести программу из 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, но добавление не решило мою проблему.

Любые другие предложения о том, что делать?

EDIT:

Первый символ длиной в один байт, вот шестнадцатеричный дамп первой записи в файле

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, и ни одна из них не работает.

Ответы [ 4 ]

1 голос
/ 04 мая 2011

Я думаю, что

Active As String * 1

преобразуется в

Char

, что на языке Unicode не равно 1 байту, поэтомусмещение следующего поля должно быть не 1, а, вероятно, 7, если я правильно понял следующее:.

Объяснение:

Вот ключ к пониманию строк: когда мы пишем код:

Dim str Как String str = "help", мы не определяем массив символов Unicode как таковой.Мы определяем элемент типа данных с именем BSTR, что сокращенно от Basic String.Фактически BSTR - это указатель на массив символов Unicode с нулевым символом в конце, которому предшествует поле длиной 4 байта.

Редактировать:

По вашему дампу кажется,что второй член должен иметь [FieldOffset (2)], потому что в противном случае он будет перекрывать предыдущий член.(редактировать ложную тревогу, я видел 00, где есть 03).

0 голосов
/ 04 мая 2011

Вы не можете использовать Pack = 1 с LayoutKind.Explicit http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.pack.aspx

0 голосов
/ 04 мая 2011

Попробуйте использовать IntPtr вместо строки, а затем вызовите Marshall.PtrToStringAnsi

Вам нужно будет сохранить точное расположение старого кода, чтобы это преобразование работало. Двоичный файл будет сохранен в том формате, в котором он был сохранен в последний раз, поэтому вам нужно точно воспроизвести его, даже если это означает использование байтов и байтовых массивов везде.

Если вы хотите использовать вместо этого новый макет, вы можете создать версию со старым макетом, загрузить их значения копий в новый формат и затем сохранить их обратно в новом формате. С этого момента вы можете загрузить их с новым макетом. С этим сценарием ваши варианты бесконечны для вашего нового формата.

0 голосов
/ 04 мая 2011

Из того, что я вижу, вы перепутали объявления "Active" и "TitleLength", которые, похоже, полностью пропущены.

...