DLL en Delphi lue par VBA

Résolu
otavioreis Messages postés 82 Date d'inscription jeudi 5 avril 2007 Statut Membre Dernière intervention 4 mars 2008 - 16 avril 2007 à 23:14
otavioreis Messages postés 82 Date d'inscription jeudi 5 avril 2007 Statut Membre Dernière intervention 4 mars 2008 - 19 avril 2007 à 14:17
Bonjour,

J'ai écrit une DLL en delphi. J'ai crée une autre application en Delphi pour accéder les fonctions de la DLL. ça marche bien. Maintenant il faut que j'appelle les fonctions de la DLL du VBA sur un fichier Excel. J'i bien declaré la fonction. ça ne marche pas. Vous savez pour quoi?

Voilà la fonction de la DLL sur Delphi:

function NU:string; stdcall;
var
  Buffer : array[0..255] of char;
  BufferSize : DWORD;
begin
  BufferSize := sizeOf(Buffer);
  GetUserName(@buffer, BufferSize);
  Result:=Buffer;
end;


 exports
 NU;

Voilà ma declaration sur le VBA d'Excel:
Declare Function NU Lib "C:\PrjDllDelphi\PrjDllDelphi.dll" () As String

Merci,
Otavio Reis

34 réponses

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
18 avril 2007 à 17:20
normal, il y avait un prob dans le code que j'avais tapé ici à la va vite mais la dll (avec code) du zip indiqué plus haut tourne impec avec VB/VBA.

Il fallait mettre:
BSTR __stdcall bnGetUsername()
{
char buff[264];
DWORD len = 206;
GetUserName(buff, &len);
if(!len) buff[0] = 0;
return SysAllocStringByteLen(buff, len);
}




ciao...
BruNews, MVP VC++
3
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
19 avril 2007 à 08:43
Avec la traduction en Delphi peut être ?
Testée sous Word.
=====================================
library VBATest;

uses
  windows, ActiveX;

function myGetUserName(): TBSTR; stdcall;
var
  buffer: array[0..255] of Char;
  size: Cardinal;
begin
  size:= SizeOf(buffer);
  GetUserName(buffer, size);
  if size = 0 then buffer[0]:= #0;
  Result:= SysAllocStringByteLen(buffer, size);
end;

exports
  myGetUserName;

begin

end.
=====================================

Private Declare Function myGetUserName Lib "VBATest.dll" () As String

Private Sub CommandButton1_Click()
MsgBox myGetUserName
End Sub

=====================================
[troll]

Au passage, un peu de 'semi interprété' désassemblé :

add esp, $fffffefc         ; Ceci n'est pas une allocation ^^
mov [esp],  100            ; Affectation de size
push esp                   ; On pousse l'adresse de size
lea eax, [esp+$08]         ; Calcul de l'adresse du buffer
push eax                   ; On pousse l'adresse du buffer
call GetUserName
cmp dword ptr [esp], 0     ; Comparaison entre size et 0
jnz myGetUserName + $23    ; On saute si différent de 0
mov byte ptr [esp+$04], 0  ; On met 0 à la première case
mov eax,[esp]              ; On met l'adresse de size dans eax
push eax                   ; On pousse l'adresse de size
call SysAllocStringByteLen
add esp, $104              ; dés(pas une allocation)
ret

/troll
3
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
16 avril 2007 à 23:26
Faut retourner une allocation mémoire obtenue par SysAllocString().

ciao...
BruNews, MVP VC++
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
16 avril 2007 à 23:29
Pour info vu que je ne connais pas Delphi:
var
  Buffer : array[0..255] of char;

ça déclare un tableau local à la fonction, non ?

Si oui, c'est sur la pile (retrait de ESP) et donc adresse absolument invalide en sortie de fonction.

ciao...
BruNews, MVP VC++
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
otavioreis Messages postés 82 Date d'inscription jeudi 5 avril 2007 Statut Membre Dernière intervention 4 mars 2008
16 avril 2007 à 23:48
Merci de la réponse... Mais cette DLL marche bien quand je l'appelle à partir des applications Delphi et C++. Elle ne marche pas seulement avec le VB.
C'est le pb était la pile, l'adresse serait invalide avec n'importe quel application, non? 
peut être qu'il y a un pb avec la déclaration ,non?

Otavio Reis
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
17 avril 2007 à 00:00
Le prob n'est pas de déclaration mais de logique.
Delphi et C connaissent les pointeurs, VB que nenni donc impossible de lui en passer une autre que celle d'un BSTR.

Faut revoir tes notions d'informatique, on ne donne pas en sortie de fonction une adresse d'une variable locale, son contenu sera écrasé à tout coup dans les prochaines instructions.

ciao...
BruNews, MVP VC++
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
17 avril 2007 à 00:21
Exemple:

BSTR __stdcall bnGetWinDir()
{
  char buff[260];
  DWORD len;
  len = GetWindowsDirectory(buff, 260);
  if(!len) buff[0] = 0;
  return SysAllocStringByteLen(buff, len);
}

ciao...
BruNews, MVP VC++
0
Renfield Messages postés 17287 Date d'inscription mercredi 2 janvier 2002 Statut Modérateur Dernière intervention 27 septembre 2021 74
17 avril 2007 à 08:52
pas besoin d'une dll delphi pour faire un  GetUserName ^^

 Environ$("UserName") suffit :p

Renfield
Admin CodeS-SourceS- MVP Visual Basic
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
17 avril 2007 à 10:07
C'était surement motif de tests.

ciao...
BruNews, MVP VC++
0
cs_rt15 Messages postés 3874 Date d'inscription mardi 8 mars 2005 Statut Modérateur Dernière intervention 7 novembre 2014 13
17 avril 2007 à 14:51
Le principal souci dans les appels de dll classique, c'est les allocations. Si tu alloue une chaîne dans une dll en C, avec un malloc par exemple, et que tu essaye de libérer tout ça dans une appli en Delphi, tu risque de gros problème. En effet, le gestionnaire de mémoire de Delphi ne comprendrat pas du tout d'où sort le pointeur.

La ton tableau est effectivement alloué sur la pile : c'est joué avec le feu -> cela ne fonctionne que dans des cas particuliers.

Donc soit il faut allouer et libérer que d'un côté, soit il faut s'arranger pour que les deux côtés utilisent le même gestionnaire de mémoire (cf sharmem en Delphi par exemple, ou les Sys*String*).

Le plus simple dans ton cas est de suivre l'exemple du Win32, ou les allocations et libérations de ce genre de chaînes se font côté exe (Comme dans GetUserName par exemple ). Le pointeur sur la zone allouée et la taille de cette zone sont envoyés à la dll, qui remplit et vérifie que la zone est assez grande.

En VB, pour allouer un bout une chaîne d'une taille précise, soit on la remplie d'espaces :

dim s as string
s = space(20)

Soit on la déclare de taille fixe :

Dim s As String * 20
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
17 avril 2007 à 19:02
"alloué sur la pile" est déjà un abus de langage ce qui induit les incompréhensions. Il n'y a aucune allocation pour une variable locale mais un simple retrait du registre ESP, celui ci étant replacé en sortie de fonction il est tout à fait clair que ça ne peut jamais fonctionner puisque la zone de pile peut se faire réécrire à tout moment.

ciao...
BruNews, MVP VC++
0
otavioreis Messages postés 82 Date d'inscription jeudi 5 avril 2007 Statut Membre Dernière intervention 4 mars 2008
17 avril 2007 à 20:03
ça veut dire que si j'utilise une variable globale, ça va marcher?

Otavio Reis
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
17 avril 2007 à 20:13
Nenni, une 'String' vb DOIT être un BSTR car vb appelle SysFreeString() quand la String sort de la portée.

ciao...
BruNews, MVP VC++
0
otavioreis Messages postés 82 Date d'inscription jeudi 5 avril 2007 Statut Membre Dernière intervention 4 mars 2008
17 avril 2007 à 21:04
Mais alors je peut conclure que créer une DLL en utilisant des pointeurs et Strings ne marche pas sur VBA? Il y a-til une solution?

Otavio Reis
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
17 avril 2007 à 21:16
ah mais je n'y crois pas !!!
Je t'ai donné l'exemple prêt à l'emploi et c'est tout ce que tu trouves à conclure.

ciao...
BruNews, MVP VC++
0
otavioreis Messages postés 82 Date d'inscription jeudi 5 avril 2007 Statut Membre Dernière intervention 4 mars 2008
17 avril 2007 à 21:26
Ok, j'ai changé la DLL. J'alloue la mémoire. Je crois que tout est bon. MAis ça marche toujours pas sur le VBA. T'as une idée?

function NU: pchar; StdCall;
Var
  Buffer : array[0..255] of char;
  BufferSize : DWORD;



begin
  BufferSize := sizeOf(Buffer);
  GetUserName(@buffer, BufferSize);





  GetMem(Result, BufferSize);




  StrCopy(Result, @Buffer);
end;





 
Je ne suis pas experient dans ce domaine.
Merci de votre aide,
Otavio Reis
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
17 avril 2007 à 21:42
Tu vois un rapport avec ça ???
BSTR __stdcall bnGetUsername()
{
  char buff[264];
  DWORD len;
  len = GetUserName(buff, 260);
  buff[len] = 0;
  return SysAllocStringByteLen(buff, len);
}

moi aucun.
Il faut allouer une String avec une des fonctions de la famille SysAllocString() !!!

Laisse ton Delphi et fais en C, on sort la dll en 2.5 Ko. Si c'est pour fournir à un inbterprété du code dll en semi interprété, aucun intérêt, autant faire depuis VB.

ciao...
BruNews, MVP VC++
0
jmfmarques Messages postés 7666 Date d'inscription samedi 5 novembre 2005 Statut Membre Dernière intervention 22 août 2014 27
17 avril 2007 à 21:51
Bonsoir, otavioreis,

Tu sais quoi  ?
Quand je relis ceci, signé Renfield :
 Environ$("UserName")
et que je vois ton acharnement à alourdir ainsi ton appli avec une fonction Delphi pour faire ce qui est déjà une fonction VB faisant parfaitement cette toute petite chose
j'ai vraiment envie de pleurer....

J'ose espérer que ta Dll écrite en Delphi n'utilise pas un composant écrit en VB faisant lui-même appel à une fonction écrite en C; qui se servirait d'une fonction d'une des librairies de l'API de Windows  !!! (Quien sabe ?)
0
otavioreis Messages postés 82 Date d'inscription jeudi 5 avril 2007 Statut Membre Dernière intervention 4 mars 2008
18 avril 2007 à 09:33
Brunews,

j'ai essayé ta fonction et le VC++ donne le message d'erreur suivant:

Erreur 1 error C2664: 'GetUserNameW' : cannot convert parameter 1 from 'char [260]' to 'LPWSTR' c:\Documents and Settings\virtual\Desktop\temporaire\DllNUC++\DllSimple\DllSimple.cpp 29 

Otavio Reis
0
BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
18 avril 2007 à 09:44
Faut mettre ton projet en ANSI au lieu de UNICODE.

Utilise ceci pour avoir les bons réglages:
TEMPLATES C/C++ POUR VS 2005
http://www.cppfrance.com/code.aspx?ID=36940

ciao...
BruNews, MVP VC++
0
Rejoignez-nous