Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

C# - VB6 ActiveX (Passage Parametres...)

7 réponses
Avatar
Cybertof
Hello,

Quelle est la bonne m=E9thode pour appeler depuis C# une fonction vb6 d'un=
=20
activex (import=E9 avec tlbimp...et r=E9f=E9renc=E9), de telle facon que la=
=20
fonction vb6 appell=E9e puisse retourner/remplir un tableau de double.

Comment d=E9clarer des 2 cot=E9s (c# / vb6) ce tableau de double afin que l=
e=20
tableau soit reconnu comme tel, et puisse etre rempli depuis l'activex=20
vb6 ?

Si vous avez des id=E9es, exemples, ...


Merci.
Cybertof.

7 réponses

Avatar
Fabrice MALAINGRE
Bonsoir Cybertof,

Comment déclarer des 2 cotés (c# / vb6)
ce tableau de double afin que le tableau soit
reconnu comme tel, et puisse etre rempli
depuis l'activex vb6 ?



Si vous avez des idées, exemples, ...



Va pour un exemple :

'======= VB6.0 Code ====== Option Explicit
Option Base 0

Public Function AllocAndFillArray(ByVal length As Long,
data() As Double)
ReDim data(length)
Call FillArray(data)
End Function

Public Function FillArray(data() As Double)
Call Randomize

Dim index As Long
For index = LBound(data) To UBound(data)
data(index) = Rnd()
Next index
End Function
'======= VB6.0 Code ======
//======= C# Code ====== using System;

namespace ConsoleApplication1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
MyVB6Object.SampleClass myVB6Obj
= new MyVB6Object.SampleClass();

Console.WriteLine("Alloc and Fill");
Array myArray = null;
myVB6Obj.AllocAndFillArray(25, ref myArray);
for (int index = 0; index < myArray.Length; index++)
{
Console.WriteLine("myArray["
+ index.ToString()
+ "] = "
+ myArray.GetValue(index).ToString());
}

Console.WriteLine("");

Console.WriteLine("Just Fill");
myArray = new double[50];
myVB6Obj.FillArray(ref myArray);
for (int index = 0; index < myArray.Length; index++)
{
Console.WriteLine("myArray["
+ index.ToString()
+ "] = "
+ myArray.GetValue(index).ToString());
}

Console.ReadLine();
}
}
}
//======= C# Code ======
Cordialement

____________________________
Fabrice MALAINGRE
Architecte Logiciel - Chef de Projet
THEORIS - www.theoris.fr
Avatar
Cybertof
In article ,
says...
Bonsoir Cybertof,


Va pour un exemple :

'======= VB6.0 Code =======
Option Explicit
Option Base 0





Super Fabrice !


2 petites questions supplémentaires :

1/ Pour les chaines de caractères, pour les BSTR de VB6, tu emploierais
quelle syntaxe (toujours tableau de chaine).

2/ Pour un tableau de structure...c'est faisable ?


"
En VB les chaînes sont stockées sous la forme d'un type appelé BSTR. En
C, le type de chaîne est LPSTR qui est un pointeur vers une chaîne
terminée par le caractère nul. Passer une chaîne BSTR par valeur revi ent
à transmettre un pointeur sur le premier caractère de la chaîne, ce
qu'attend votre fonction C.
Avant de passer la chaîne à la fonction C, vous devez lui allouer un
espace mémoire suffisant, par exemple avec la fonction String().
Dans cet exemple la chaîne passée en paramètre est modifiée par la
fonction GetMessage.
"


Thanks.
Avatar
Fabrice MALAINGRE
Bonjour Cybertof,

1/ Pour les chaines de caractères,
pour les BSTR de VB6, tu emploierais
quelle syntaxe (toujours tableau de chaine).
2/ Pour un tableau de structure...c'est faisable ?



'======= VB6.0 Code ====== Option Explicit
Option Base 0

Public Type DataStruct
Name As String
Value As Double
End Type

Public Function FillStringArray(data() As String)
Call Randomize

Dim index As Long
For index = LBound(data) To UBound(data)
data(index) = CStr(Rnd())
Next index
End Function

Public Function FillStruct(data As DataStruct)
data.Name = "Pi"
data.Value = 3.14159265
End Function
'======= VB6.0 Code ======
//======= C# Code ====== using System;

namespace ConsoleApplication1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
MyVB6Object.SampleClass myVB6Obj
= new MyVB6Object.SampleClass();

Console.WriteLine("Strings!");
myArray = string[50];
myVB6Obj.FillStringArray(ref myArray);
for (int index = 0; index < myArray.Length; index++)
{
Console.WriteLine("myArray["
+ index.ToString()
+ "] = "
+ myArray.GetValue(index).ToString());
}

Console.WriteLine("");

Console.WriteLine("Struct!");
MyVB6Object.DataStruct myData = new MyVB6Object.DataStruct();
myVB6Obj.FillStruct(ref myData);
Console.WriteLine(myData.Name + "= " + myData.Value.ToString());

Console.ReadLine();
}
}
}
//======= C# Code ======

"En VB les chaînes sont stockées sous la
forme d'un type appelé BSTR.
En C, le type de chaîne est LPSTR
qui est un pointeur vers une chaîne
terminée par le caractère nul.
Passer une chaîne BSTR par valeur revient
à transmettre un pointeur sur le premier
caractère de la chaîne, ce qu'attend votre fonction C.
Avant de passer la chaîne à la fonction C,
vous devez lui allouer un espace mémoire suffisant,
par exemple avec la fonction String().
Dans cet exemple la chaîne passée
en paramètre est modifiée par la fonction GetMessage."


C'est le boulot du marshalling de ComInterop !


Cordialement

____________________________
Fabrice MALAINGRE
Architecte Logiciel - Chef de Projet
THEORIS - www.theoris.fr
Avatar
Cybertof
Le marshaller de cominterop a l'air de bien marcher.

Par contre, coté C#, es-tu es obligé de déclarer

MyVB6Object.DataStruct myData = new MyVB6Object.DataStruct();
myVB6Obj.FillStruct(ref myData);

J'aurai voulu faire cela :

struct CStruct
{
string name;
double value;
}

puis remplacer les 2 lignes precedentes par :

CStruct myData = new CStruct();
myVB6Obj.FillStruct(ref myData);

Mais le compilateur n'arrive pas à convertir

ref MyVB6Object.DataStruct
en
ref ConsoleApplication1.Class1.Cstruct

Y a moyen de caster la structure VB6 en structure C# ?

Ce qui me permet de manipuler par la suite uniquement du managed data.
(sans marshalling à chaque accès à une donnée de la structure si c' est
dans un tableau).

Je souhaite en fait manipuler un tableau de structure, il faudrait donc
que je cast
un tableau de MyVB6Object.DataStruct
en
un tableau de ConsoleApplication1.Class1.Cstruct




Thanks.
Avatar
Fabrice MALAINGRE
Bonsoir Cybertof;

Y a moyen de caster la structure
VB6 en structure C# ?
Ce qui me permet de manipuler
par la suite uniquement du managed data.
(sans marshalling à chaque accès à une donnée
de la structure si c'est dans un tableau).



La ligne de code suivante
"MyVB6Object.DataStruct myData = new MyVB6Object.DataStruct();"
alloue une structure managée côté CLR et non côté VB6 (i.e. Win32) !

Le marshalling n'est utilisé que sur l'appel à la méthode "FillStruct".
A ce moment, les différents champs de la structure sont "marshallés"
afin d'être interprétable côté VB6.

Il suffit de désassembler la DLL "Interop.MyVB6Object.dll" pour
s'en convaincre.

Cordialement

____________________________
Fabrice MALAINGRE
Architecte Logiciel - Chef de Projet
THEORIS - www.theoris.fr
Avatar
Cybertof
In article ,
says...
Bonsoir Cybertof;

La ligne de code suivante
"MyVB6Object.DataStruct myData = new MyVB6Object.DataStruct();"
alloue une structure managée côté CLR et non côté VB6 (i.e. Win 32) !

Le marshalling n'est utilisé que sur l'appel à la méthode "FillStru ct".
A ce moment, les différents champs de la structure sont "marshallés"
afin d'être interprétable côté VB6.

Il suffit de désassembler la DLL "Interop.MyVB6Object.dll" pour
s'en convaincre.



Hello Fabrice,

Ok.

Mais comment faire pour que je puisse manipuler une fois ma structure
remplie (ou mon tableau de structure) uniquement des éléments de type C #
struct CStruct
{
string name;
double value;
}

et non pas de type VB6AX.VB6Struct

Car mon type dépend de ma DLL, alors que je souhaite travaille coté C#
uniquement avec un tableau de type CStruct, la DLL n'étant utilisée que
pour remplir mon tableau.

En fait je voudrai caster
VB6AX.DataStruct en CStruct
quelque part (définition ? Declaration ? Appel ?)

afin de ne pas utiliser VB6AX.VB6Struct
comme type de base de mes éléments.

Pour les tableaux, ca donne en declaration

// Declaration
VB6AX.VB6Struct[] array1 = new VB6AX.VB6Struct[50];
CSharpStruct[] array2 = new CSHarpStruct[50]

// Function Call
MyVB6Object.Fill_ArrayStruct(100, ref array1); // OK
MyVB6Object.Fill_ArrayStruct(100, ref array2); // PAS OK

PAS OK car le 2eme parm ref array2 n'est pas pas de type
ref VB6AX.VBStruct[].
(la methode de ma classe VB6 attend un tableau de structure definies
dans les declarations publiques de la classe).

Quand j'ajoute la reference à mon activex, VS.NET s'attend à ce que
cette methode lui soit passee un tableau de structure du type interne a
l'activex (via la reference).

Comment faire pour faire accepter le 2eme appel (celui PAS OK) ?
(pour eviter d'etre obligé d'utilier le type à l'interieur de ma classe
VB6...)


Merci encore pour ta patience.


Cybertof.
Avatar
Fabrice MALAINGRE
Bonsoir Cybertof;

Car mon type dépend de ma DLL, alors
que je souhaite travaille coté C#
uniquement avec un tableau de type CStruct,
la DLL n'étant utilisée que pour remplir mon tableau.
[...]
afin de ne pas utiliser VB6AX.VB6Struct
comme type de base de mes éléments.



Au risque de paraître légèrement têtu (si si, on peut le dire...),
une fois importé grâce à "TlbImp.exe" la structure
"VB6AX.VB6Struct" est un type managé défini
dans le "CLR Callable Wrapper" implémenté
par l'assembly "Interop.MyVB6Object.dll".

Le meilleur moyen de son convaincre, c'est d'essayer de
déclarer un pointeur sur le type "VB6AX.VB6Struct".
Le compilateur va "hurler" en disant :
"Impossible de prendre l'adresse ou la taille d'une variable d'un type
managé ('VB6AX.VB6Struct')".

Donc, "VB6AX.VB6Struct" est un type managé...
Donc, pourquoi ne pas s'en servir directement ?

Maintenant, si la déclaration du type "doit" être faite en C#
(mais encore une fois cela ne change rien),
je suppose qu'il faudrait exposer la classe C#
comme un ActiveX (Attributs + "RegAsm.exe"),
puis utiliser directement dans VB6 les types exposés par
le "COM Callable Wrapper" généré via "RegAsm.exe".
Mais rien de moins sûr...

Cordialement

____________________________
Fabrice MALAINGRE
Architecte Logiciel - Chef de Projet
THEORIS - www.theoris.fr