2011-05-04 11 views
1

J'essaye de porter un programme de VB6 à C# qui lit dans un fichier binaire et l'analyse. Je reçois aucune erreur de temps de compilation ou des avertissements mais lorsque je tente de l'exécuter, avant qu'il ne pénètre même Main() il jette l'exceptionSystem.TypeLoadException: Impossible de charger le type 'x' depuis l'assembly 'y'

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: 

Voici un exemple de l'ancien code 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 

Et ici est mon code C# J'ai écrit

[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; 
} 

Après quelques googleing je pensais que c'était que je manque le Pack = 1, mais en ajoutant que n'a pas résolu mon problème.

D'autres suggestions sur ce qu'il faut faire?

EDIT:

Le premier charater est un octet, voici un vidage hexadécimal du premier enregistrement dans le fichier

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: Changer mon code à ce qui suit pour éliminer toutes les autres erreurs possibles, il me donne toujours la même exception

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)] 
struct ClientOld 
{ 
    [FieldOffset(0)] 
    public byte Active; 

    [FieldOffset(1)] 
    [MarshalAs(UnmanagedType.AnsiBStr)] 
    public string Title; 
} 

J'ai essayé à la fois fieldoffset (1) et 2 et aucun ne fonctionne.

+0

Pouvez-vous poster le Len VB6 (SrcClientOld) de la struct? Peut-être avec seulement les deux premiers membres? –

+0

@Marino Šimić Len renvoie 394 pour l'ensemble de la structure pour chaque enregistrement. Dans le code VB6, il enregistrerait tout le bloc de largeur fixe pour l'enregistrement, puis, quand il tirait réellement des données de la structure, il ferait quelque chose comme 'Left (recClient.LastName, recClient.lastNameLength)' –

+0

Hmm, pourquoi déclarez-vous qu'est-ce qui était un type 'String' en tant que' byte' maintenant? Plus précisément, le premier membre de la structure, 'Active'. –

Répondre

1

Je pense que

actif As String * 1

translatées à

Char

qui, dans un langage Unicode n'est pas 1 octet, de sorte que le champ suivant décalage ne doit pas être 1, mais probablement 7 si je compris correctement ce qui suit:

Explication:

Voici la clé de cordes comprendre: quand on écrit le code:

Dim str As String str = "help" nous sommes ne pas définir un tableau de caractères Unicode par se. Nous définissons un membre d'un type de données appelé BSTR, qui est court pour la chaîne de base. Un BSTR est, en fait, un pointeur vers un tableau de caractères Unicode à terminaison nulle précédé d'un champ de longueur de 4 octets .

Edit:

Par votre décharge, il semble que le second élément doit avoir [FieldOffset (2)], car sinon chevaucherait sur le membre précédent.(éditer fausse alarme, j'ai vu un 00 où il y a un 03).

+0

Oui, il devrait, j'ai, mis à jour ma question pour inclure un exemple de la première partie du premier enregistrement. –

+0

Donc le décalage de champ est défini par le début de la chaîne, pas le début de la longueur de la chaîne? Que se passerait-il si j'avais une chaîne comme premier élément, est-ce que j'utiliserais offset (1) pour cela? –

+0

désolé j'ai vu un 00 où il y a un 03, de mauvais yeux aujourd'hui :) Vous explication de la décharge a aidé à le voir. –

0

D'après ce que je vois, vous confondre les déclarations de "actives" et "TitleLength" qui semble être complètement désactivé ..

+0

Active est un charateur à un seul octet, faisant un caractère ou une chaîne lue sur deux octets. Aussi pour Title toutes les chaînes sont codées ANSI ce qui signifie qu'il y a un octet de longueur d'un byte (TitleLength) suivi par la chaîne, faire MarshalAs (UnmanagedType.AnsiBStr) devrait lire automatiquement cet octet et lire le nombre de caractères correct dans la chaîne. –

0

Essayez d'utiliser un IntPtr à la place d'une chaîne, puis appelez Marshall.PtrToStringAnsi

Vous aurez besoin de conserver la mise en page exacte de l'ancien code pour que cette conversion au travail. Le binaire va être stocké dans le format dans lequel il a été sauvegardé, donc vous devez le reproduire exactement, même si cela signifie utiliser des tableaux d'octets et d'octets partout. Si vous souhaitez utiliser votre nouvelle mise en page à la place, vous pouvez créer une version avec l'ancienne mise en page, charger les valeurs de copie dans votre nouveau format, puis les sauvegarder avec le nouveau format. À partir de ce moment, vous pouvez les charger avec votre nouvelle mise en page à la place. Avec ce scénario, vos options sont infinies pour votre nouveau format.

+0

Selon le [MSDN] (http://msdn.microsoft.com/en-us/library/8c0157f5.aspx) MarshalAs (UnmanagedType.AnsiBStr) fait exactement ce que l'ancien code essaie de faire. il va lire dans un octet, utilisez cela comme la longueur de la chaîne dans les octets suivants. –

+0

Mes jours COM interop sont loin derrière moi. J'ai mis à jour ma réponse. –

0
+0

La suppression du Pack = 1 ne modifie pas l'erreur. –

+0

Je pense que cette erreur se produit car toutes les valeurs sont alignées sur des limites de 4 octets. Si vous modifiez le décalage de Titre de 1 à 4 dans votre structure à 2 champs, le code s'exécutera sans exception. Vous pouvez essayer d'utiliser LayoutKind.Sequential avec Pack = 1 et définir [MarshalAs (UnmanagedType.ByValTStr, SizeConst =)] pour chaque chaîne; [MarshalAs (UnmanagedType.ByValArray, SizeConst =)] pour les tableaux pour résoudre votre problème. – Charge

Questions connexes