Comment passer des tableaux d’octets en tant que propriétés UDT de VB6 / VBA à la DLL COM #?

J’ai une bibliothèque C # que j’essaie d’exposer à VBA. Je peux passer des parameters à des fonctions très bien (“ref byte [] someArray”), mais passer des objects ou des structures ne fonctionnera pas.

Si j’essaie de passer un tableau d’octets en tant que propriété d’une classe, l’erreur suivante apparaît dans VB-

Fonction ou interface marquée comme restreinte, ou la fonction utilise un type Automation non pris en charge dans Visual Basic

Si j’essaie de passer un tableau d’octets en tant que propriété d’une structure, j’obtiens l’erreur suivante dans VB-

Je me bats contre cela depuis deux jours maintenant et bien que je continue à trouver des messages prétendant avoir la réponse, aucun d’entre eux n’a travaillé pour moi.

Alors voici mon code tel qu’il se trouve actuellement:

[ComVisible(true)] [Guid("7F53F7A5-15C9-4A99-A855-38F5E87702D0")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] // Tried as InterfaceIsDual and as InterfaceIsIDispatch public interface IDetail { [DispId(1)] // Tried with and without these int SomeInt { get; set; } [DispId(2)] ssortingng SomeSsortingng { get; set; } [DispId(3)] byte[] SomeByteArray { return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)] get; [param: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)] set; } } [ComVisible(true)] [Guid("F77FB3D4-27E0-4BFA-A21E-5ACB671151E9")] [ClassInterface(ClassInterfaceType.None)] [ProgId("G4COMTest.Detail")] public class Detail:IDetail { public int SomeInt { get;set; } public ssortingng SomeSsortingng { get; set; } // Tried MarshalAs in all combinations of class and interface public byte[] SomeByteArray { [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)] get; [param: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)] set; } } [ComVisible(true)] [Guid("5E8F9FF0-3156-479E-A91D-0DADD43881FB")] [ClassInterface(ClassInterfaceType.None)] public class Worker:IWorker { // works with the 'ref' public int ReturnIntWByteArrayParam(ref byte[] testByteArray) { return testByteArray.Count(); } public int ReturnIntWObjParam(IDetail detail) { return detail.SomeInt; } public IDetail ReturnObjNoParams() { var o = new Detail(); o.SomeInt = 87; o.SomeSsortingng = "What are you doing Dave"; return o; } } [ComVisible(true)] [Guid("04962F29-DBBD-48AC-B4FB-180EEF562771")] [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IWorker { int ReturnIntWByteArrayParam(ref byte[] testByteArray); int ReturnIntWObjParam(IDetail detail); IDetail ReturnObjNoParams(); } 

L’appeler de VB6:

 Dim o As New G4COMTest.Worker Dim d As New G4COMTest.Detail Dim byt(2) As Byte d.SomeInt = 356 '// Works d.SomeSsortingng = "Hello from client" '// Works d.SomeByteArray = byt '// Errors as either class or struct MsgBox mWorker.ReturnIntWObjParam(d) 

Merci d’avance pour votre aide!

La propriété de tableau C # expose un getter et un séparateur à COM exactement comme prévu (l’atsortingbut MarshalAs n’est pas nécessaire, le marshaler le détecte correctement par défaut).

Le problème est que le créateur, comme tous les auteurs de propriétés dans .NET, passe le paramètre valeur par valeur. Malheureusement, VBA ne prend pas en charge le passage de tableaux par valeur. C’est une limitation fondamentale du langage utilisé depuis le premier jour. Encore plus malheureusement, COM Interop ne fournit aucun moyen de remplacer ce comportement par des atsortingbuts. Vous avez deux choix:

A – Définissez votre propre méthode de définition et appelez-la à partir de VBA au lieu de la propriété,

 void SetSomeByteArray(ref byte[] value) { SomeByteArray = value; } 

B – Modifiez le type de propriété en object et utilisez des tableaux de variantes au lieu de tableaux fortement typés.

PS: Soyez prudent avec ssortingng propriétés de ssortingng aussi. Celles-ci fonctionnent normalement très bien, mais si vous transmettez une valeur de chaîne null à VBA, le système générera une erreur car le type VBA Ssortingng ne peut pas stocker de références null .

Dans votre classe de code Detail, ClassInterfaceType est défini sur None. Si vous le définissez sur AutoDispatch, le code que vous possédez doit fonctionner. De MSDN:

L’utilisation de l’interface de classe est une option acceptable pour les clients scriptés, les clients Microsoft Visual Basic 6.0 ou tout client à liaison tardive qui ne met pas en cache les identificateurs DispIds des membres de l’interface. ”

http://msdn.microsoft.com/en-us/library/4fcadw4a(v=vs.110).aspx

Étant donné que le client à partir duquel vous appelez est VB6, vous pouvez définir le ClassInterfaceType sur AutoDispatch ou même l’omettre (par défaut, AutoDispatch). Cela générera uniquement l’interface de classe Dispatch et n’inclura aucun membre de l’interface. Lors de l’appel de VB6, l’affectation directe d’un tableau à une propriété doit fonctionner car il utilise la fonction Invocation IDispatch (liaison tardive).

Nous avons testé cela avec un tableau de chaînes et cela fonctionne.