Je dois créer une DLL qui est utilisée par une application VB6. Cette DLL doit fournir plusieurs fonctions, certaines d'entre elles doivent renvoyer des chaînes.
Ceci est la déclaration VB6: P>
function MyProc(AParam: PChar): PChar; stdcall; var ReturnValue: string; begin ReturnValue := GetReturnValue(AParam); Result := ???; end;
7 Réponses :
Utilisez l'API Windows pour allouer la mémoire que le pointeur Pchal pointe dans. Ensuite, l'application VB peut annuler la mémoire après utilisation, à l'aide de l'API Windows, également. P>
Cela vous lie à une implémentation particulière (lecture: stratégie d'allocation de mémoire). La fourniture de routines d'allocation / dealLocae couplées est plus transparente.
Vous devez gérer un BSTR à la place. Les chaînes VB6 sont en réalité BSTRS. Appelez Si sysallocstring () code> sur le côté Delphi et renvoyez le BSTR sur le côté VB6. Le côté VB6 devra appeler
sysfreestring () code> pour libérer la chaîne - il le fera automatiquement. P>
pCHAR code> correspond à une chaîne ANSI (votre cas), vous devez le convertir manuellement en Unicode - Utilisez
MultiByteTowidechar () code> pour cela. Voir Cette réponse pour savoir comment mieux utiliser
sysallocstringlen () code> et
multibytetowidechar () code> ensemble. p>
J'ai fait des expériences avant de demander. J'ai utilisé une variable de chaîne globale (ANSI) et je viens de rentrer de Pansichal (Myglobalvar) et cela a fonctionné. Pourquoi cela a-t-il travaillé quand en fait je dois retourner un BSTR (= deux octets par caractère)?
AFAIK En ce qui concerne les appels API, VB6 jette implicitement toutes les cordes aux chaînes d'ANSI, même si VB6 fonctionne avec BStrs en interne.
Le Dr est correct - si vous utilisez BYVAL dans la déclaration DLL, VB6 convertira implicitement toutes les chaînes vers et depuis les chaînes ANSI lors de l'appel des DLL.
Je viens de lire ceci: vb.mvps.org/tips/vb5dll.asp . Maintenant, je ne comprends plus rien ... Parfois, les cordes sont converties, parfois pas, mais elles sont toujours bstrs ...?!?!?!?!
Selon ce texte de magie noire, vous pouvez simplement faire comme indiqué dans la fonction majusculeByval ().
Si vous utilisez BIEVAL, VB6 convertit les chaînes vers / depuis ANSI et transmet la DLL un pointeur à la chaîne ANSI. Le Microsoft Doc affirme que, mais de manière assez confuse. Concentrez-vous sur lorsque vous passez une chaîne byVal, Visual Basic passe un pointeur au début des données de chaîne code>
Je dirais que quiconque alloue la mémoire doit également la libérer dans ce cas. Vous rencontrerez des problèmes avec d'autres scénarios. Donc, la manière la plus sûre et la plus propre serait:
La configuration serait comme ceci: p>
Pour autant que je sache, ce n'est pas comment vb6 / com fonctionne. Avec BSTRS, l'appelant est responsable de la libération de toutes les chaînes i>, aussi étranges que cela pourrait sonner. Voir cette question à la question: Stackoverflow.com/Questtions/872794/who-owns-returned-bstr
Oh, tu sais ça. Je ne connais pas très bien VB. Oui, c'est un peu déroutant si vous me demandez.
Cela fonctionnerait, mais je veux pouvoir utiliser la fonction DLL car j'utiliserais toute autre fonction VB6. Un appel de freePointer supplémentaire après chaque appel à ma fonction gâcherait mon code. Je crains également que, avec cela, les fonctions de traitement des chaînes internes de VB6 puissent interférer.
Compris. J'ai trouvé que le moyen le plus propre à Delphes. Mais je comprends ton point.
@DR L'appelant est responsable de la libération de toutes les chaînes sous com i>. Votre DLL n'est pas une COM dLL de sorte que d'autres questions ne s'appliquent pas.
combiner la réponse Sharptooth et Lars d'A; ne sont pas des ravages déjà alloués via Windows et BSTR? P>
J'aurais dû mentionné: Delphi 2005
Les ravins sont afaik d4 +, donc pas de problème là-bas.
N'a-t-elle pas Delphi libérer le widstring automatiquement? Quoi qu'il en soit, je suis allé avec la réponse de Sharmpooth, car comme indiqué dans plusieurs réponses et commentaires, VB6 emballe une chaîne ANSI dans un BSTR, ce qui entraînerait des moulages laids sur le côté Delphi.
Je ne connais pas dephi, mais voici les deux options principales lors de l'utilisation de chaînes avec une DLL non COM et VB6.
Option 1. Utilisez des chaînes "ANSI". p> option deux. Utiliser bstrs. p> Je suggère également de regarder le Conseils Microsoft sur la rédaction de DLL de VB. Publié à l'origine avec VB5 mais toujours pertinent pour VB6. p> p>
Peut-être une meilleure référence est la section Hardcore Visual Basic i> sur les chaînes de passage aux appels d'API (votre Delphi DLL est comme un appel API du point de vue VB6) vb.mvps.org/hardcore/html/stringsinsIseOut.htm
Vous ne pouvez pas retourner une pCHAR en tant que résultat de la fonction, mais vous pouvez transmettre un paramètre PCHAR supplémentaire et copier la chaîne que vous souhaitez revenir à ce PCHAR. Remarque, que VB doit allouer cette chaîne à la taille requise avant de la transmettre à la DLL. En outre, dans VB, ce paramètre doit être déclaré comme BYVAL PARAM en tant que chaîne et il doit être transmis avec BYVAL:
param = "aaaaaaaaaaaaaaaaaaaa" ' reserve 20 characters call myproc(byval param)
Cette restriction est-elle disponible que vous ne pouvez pas retourner pCHAR en tant que résultat de la fonction, VB spécifique?
Je ne pense pas que cela soit vrai. Il y a beaucoup de documents MSDN sur ce sujet, je ne semble tout simplement pas la comprendre.
Avez-vous essayé ma approche? Alloué et transaction de mémoire dans votre DLL. Ou est-ce que le problème est en réalité dans le format de la mémoire renvoyée (convention PCHAR ou quelque chose de similaire)? Mon code est testé dans BDS 2006 et RAD 2010 et fonctionne parfaitement.
@Runner: VB n'a pas de type PCHAR mais ne peut convertir que son propre type de chaîne en Pchak et en arrière. Donc, il n'ya aucun moyen que vous puissiez appeler une fonction freememory de VB (OK, il pourrait y avoir du piratage pour le faire). (Je parle de VB6 comme dans la question initiale, je n'ai aucune idée de vb.net à cet égard.)
Si vous ne voulez pas risquer des accidents ou des fuites de mémoire, achetez votre API à l'aide de l'API Windows comme modèle. Là-bas, les fonctions de l'API n'allouent généralement pas leur propre mémoire. Au lieu de cela, l'appelant passe un tampon et raconte à l'API quelle est la taille du tampon. L'API remplit le tampon jusqu'à cette limite. Voir la fonction Une autre amélioration que vous pouvez apporter à cette technique est de permettre à la fonction dire em> l'appelant Quelle est la taille du tampon. Lorsque le pointeur d'entrée est un pointeur NULL, la fonction peut renvoyer le nombre d'octets dont l'appelant doit fournir. L'appelant appellera la fonction deux fois. P>
Vous n'avez pas besoin de dériver votre API de zéro. Utilisez des API déjà fonctionnelles comme exemples pour savoir comment exposer le vôtre. P> getwindowtext code>, par exemple. Les fonctions ne sont pas retournez em> les pointeurs, sauf si elles sont des indications sur des choses que l'appelant déjà fourni. Au lieu de cela, l'appelant fournit tout lui-même et la fonction utilise simplement tout ce qu'elle est donnée. Vous ne voyez presque jamais un paramètre de mémoire tampon de sortie qui n'est pas accompagné d'un autre paramètre en disant la taille du tampon. P>
Bonne réponse, +1. Comment retourner les chaînes est un sujet qui semble être discuté encore et encore, bien que des variations et avec différentes langues. Je souhaite qu'il y ait une réponse qui pourrait être dirigée vers référence. C'est au moins un début vers une telle réponse.