KCC y veut deux tableaux...et ben il en a qu'un [Resolu]

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

En fait c'est tout simple..c'est pour ça que je me fait ch...depuis une semaine :?

Je veux, enfin je voudrais, j'aimerais, ce serait gentil....avoir ce code qui me conviens tres bien, mais dans une DLL

Code : Tout sélectionner

ProcedureDLL.l CreateArray(Parametre) 
    
 Static Passage, xx, *PointerString 
 Passage + 1 
    
 If Passage = 1 
  *PointerString = AllocateMemory(100000 * 4); Tableau de pointeur 
  If Parametre = 1 
   Lettre.s = "a" 
  Else 
   Lettre.s = "c" 
  EndIf 
 Else 
  If Parametre = 2 
   Lettre.s = "b" 
  Else 
   Lettre.s = "d" 
  EndIf 
 EndIf 
  
 For x = 1 To 4 
  xx + 1 
  LenString = Len(RSet("", xx, Lettre)) 
  *String = AllocateMemory(LenString * 4) 
  PokeS(*String, RSet("", xx, Lettre)) 
  PokeI(*PointerString + (xx * 4), *String) 
 Next 
  
 If Passage = 1 
  CreateArray(Parametre) 
  ReAllocateMemory(*PointerString, (xx * 4) + 4) 
  Passage = 0 
  xx = 0 
 EndIf 
  
 PokeI(*PointerString, #Null) 
 ProcedureReturn *PointerString 
    
EndProcedure 

Dim ArrayA.s(0) 
ArrayA() = CreateArray(1) 
  
Dim ArrayB.s(0)  
ArrayB() = CreateArray(2) 

For i = 1 To (MemorySize(ArrayA()) / 4) - 1 
 Debug "Premier essai = " + ArrayA(i) 
Next 

For i = 1 To (MemorySize(ArrayB()) / 4) - 1  
 Debug "Second essai = " + ArrayB(i) 
Next
Avatar de l’utilisateur
GeBonet
Messages : 453
Inscription : ven. 29/févr./2008 16:17
Localisation : Belgique

Message par GeBonet »

ReRe Salut,

Avant même de regarder ce que tu viens de me montrer que je vais lire et essayer de comprendre... Je te renvois un de tes code que j'ai rassemblé pour être traité en une fois avant de l'essayer dans une VRAI dll...

Regarde... Et ça fonctionne à peu prêt si c'est ce que tu attend...

Code : Tout sélectionner

;
; La Dll 
;
ProcedureDLL CreateArray(Char$,NbElement.i) 

; On alloue un tableau de pointeur Dim A.s n'est en fait qu'un tableau de pointeur vers des strings 
; qui se situe ailleurs en mémoire , car on ne peut pas prévoir à l'avance leur longueur vue quelles 
; ne sont pas fixe. 
*Tab = AllocateMemory(NbElement * 4); Tableau de pointeur 


    For e = 0 To NbElement-1 
        xx+1 
        *String = AllocateMemory(xx+4) 
    	For f = 1 To xx 
    			PokeS(*String+(f-1),Mid(Char$,1,1)) ; Mid$ au cas ou len(Char$) > 1 
    	Next 
    			
    	; on construit notre tableau en lui envoyant les pointeurs *String 
    	; les uns derrière les autres. 
    	PokeI(*Tab+(e*4),*String) 
    Next 
    
    ProcedureReturn *Tab 
EndProcedure 
;
; L'exe de KCC 
;  
Global Dim ArrayA.s(0)      ;    Le GLOBAL ??? 
Global Dim ArrayB.s(0)      ; 

;If OpenLibrary(0,"c:\dllbator.dll") 

	;*PointeurArrayA = CallFunction(0, "CreateArray", "a", 5) 
	;*PointeurArrayA = CallFunction(0, "CreateArray", "a", 5) 
	
	*PointeurArrayA=CreateArray("a",5) 
	ArrayA() = *PointeurArrayA
	
	
	;*PointeurArrayB = CallFunction(0, "CreateArray", "b", 10) 
	*PointeurArrayB=CreateArray("b", 10)
	ArrayB() = *PointeurArrayB
	
	Debug *PointeurArrayA
	Debug *PointeurArrayB
	
	For i=1 To (MemorySize(*PointeurArrayA) / 4) - 1 
	Debug "ArrayA = " + ArrayA(i) 
	Next 
	
	For i=1 To (MemorySize(*PointeurArrayB) / 4) - 1 
	Debug "ArrayB = " + ArrayB(i) 
	Next 
	
;	CloseLibrary(0)

;EndIf
Je n'ai fait que neutraliser pour éviter l'appel vers la dll et surtout ajouter le GLOBAL '

Je joins une page de la doc qui elle n'était pas tout a fait traduite et l'est maintenant !
Avec quelques points importants ! Que l'on n'a pas toujours à l'esprit ?
voilà, voilà...

Construire une DLL
Introduction
PureBasic permet de créer des librairies dynamiques liées au standard Microsoft Windows (DLL : Dynamic Linked Library). Le code d'une DLL est de même nature que le code PureBasic excepté qu'aucun code ne peut exister en dehors d'une procédure. Lors de l'écriture d'une DLL, tout le code est intégré dans des procédures. Lorsqu'une procédure doit être publique (accessible par un programme tiers qui doit accéder à la DLL), le mot clef ProcedureDLL est utilisé au lieu de Procedure. C'est la seule différence pour écrire un programme.

Lorsque le codage est ainsi fait, il suffit de sélectionner 'Shared DLL' comme format de sortie (fenêtre 'Compiler Option' dans l'éditeur PureBasic ou commutateur /DLL dans la ligne de commande) et de créer un exécutable.
Exemple:
ProcedureDLL MaFonction()
MessageRequester("Bonjour", "Voici une DLL PureBasic !", 0)
EndProcedure

; Voici le programme client qui utilise la DLL
;
If OpenLibrary(0, "PureBasic.dll")
CallFunction(0, "MaFonction")
CloseLibrary(0)
EndIf
Pour les programmeurs avancés, il existe 4 procédures spéciales qui sont appelées par Windows lorsque l'un des évènements suivants survient:
- une DLL est attachée à un nouveau process
- une DLL est détachée d'un process
- une DLL est attachée à un nouveau thread
- une DLL est détachée d'un thread

Pour gérer cela, il est possible de déclarer 4 procédures spéciales nommées: AttachProcess(Instance), DetachProcess(Instance), AttachThread(Instance) et DetachThread(Instance). Cela signifie que ces 4 noms sont réservés et ne peuvent être utilisés par le programmeur pour d'autres usages.
Notes sur la création de DLL:

- La déclaration de tableaux et LinkedLists avec Dim ou newlist doit toujours être fait à l'intérieur de la procédure AttachProcess.
- Ne pas écrire le code d'un programme en dehors des procédures. La seule exception est la déclaration de variables ou structures.
- DirectX routines d'initialisation ne doit pas être écrit dans la procédure AttachProcess.

Note sur le retour des chaînes de la DLL:


Si vous souhaitez renvoyer une chaîne d'une DLL, la chaîne doit être déclaré comme Global avant de l'utiliser.

Exemple:

Global ReturnString$

ProcedureDLL.s MaFonction (var.s)
ReturnString $ var + = "test"
ProcedureReturn ReturnString $
EndProcedure

Sans les déclarer en tant que GLOBAL, les chaînes de la ProcedureDLL sont considérées locales et ne peuvent être accessibles de l'extérieur.

Lors de l'utilisation de CallFunction () (ou l'un de ses fonctions similaires CallXXX) pour une DLL, vous obtiendrez un pointeur de retour que devrez lire avec PeekS().
Exemple:
String.s = PeekS(CallFunction(0,"NomFonction",Parametre1,Parametre2))
OU
*Adresse=CallFunction(0,"NomFonction",Parametre1,parametre2)
String.s=PeekS(*Adresse)
Avatar de l’utilisateur
GeBonet
Messages : 453
Inscription : ven. 29/févr./2008 16:17
Localisation : Belgique

Message par GeBonet »

Salut
Et pour répondre a je VOUDRAIS... :D
Revoici ton code inchangé pour la partie Dll soit :

Code : Tout sélectionner

; **********************************************************************************************************
;  PARTIE : a compiler comme DLL,  (TestDllKccORG.dll) 
; **********************************************************************************************************
ProcedureDLL AttachProcess2(Instance)
  ;------------------------------------------------------------------------------------------------------
  ;						                         Initialisation 
  ;										START DLL PROGRAMME 
  ;------------------------------------------------------------------------------------------------------
EndProcedure
; **********************************************************************************************************
ProcedureDLL.l CreateArray(Parametre)  
 
    Static Passage, xx, *PointerString  
    
    Passage + 1                           ; nombre d'appel récursif ... 
    ;
    If Passage = 1  
        *PointerString = AllocateMemory(100000 * 4); Tableau de pointeur  
        If Parametre = 1  
            Lettre.s = "a"  
        Else                                    ; par récursif 
            Lettre.s = "c"  
        EndIf  
    Else  
        If Parametre = 2  
            Lettre.s = "b"  
        Else                                    ;  par récursif 
            Lettre.s = "d"  
        EndIf  
    EndIf  
    ;
    For x = 1 To 4                                              ; 
        xx + 1                                                        ; Compteur de ligne et de lettre par paramettre
        LenString = Len(RSet("", xx, Lettre))        ;
        *String = AllocateMemory(LenString * 4)  ; Augmente la mémoire pour écrire la suite
        PokeS(*String, RSet("", xx, Lettre))          ; Y écrit la lettre concernée... 
        PokeI(*PointerString + (xx * 4), *String)    ; écrit l'adresse de la chaine 
    Next  
    
    If Passage = 1                                                          ; Si le passage est le premier alors on fait un deuxième passage.... 
        CreateArray(Parametre)                                      ; Appel recursif pour une deuxième passe .
        ReAllocateMemory(*PointerString, (xx * 4) + 4)  ; Redimensionne la réserve de mémoire pour un autre cas si utile !!! 
        Passage = 0 : Debug "XX= "+Str(xx)                  ; 
        xx = 0  
    EndIf  
    yy=xx    
    PokeI(*PointerString, #Null)  
    ProcedureReturn *PointerString  
    
EndProcedure  
; ************************************************************
; ************************************************************
ProcedureDLL DetachProcess2(Instance)
;                           fin de la DLL
EndProcedure
; ************************************************************
Et la partie qui l'appelle commentée... Et cela fonctionne dans les conditions que je commente.

Code : Tout sélectionner

; ***********************************************************
;  Forme de l'EXE Appellant !!! 
;  ----------------------------------------------------------------------
;  J'ai forcé la boucle For i=1 to 2*4    A LA PLACE DE (MemorySize(@ArrayA(1)) / 4) - 1
; 
; ******  Taille=(MemorySize(@ArrayA(1)) / 4) - 1   ===> Ne peux pas marcher car c'est prendre une taille d'un tableau dont
;                                                                                          la taille n'existe pas ! Dim ArrayA(0)) fait exister le tableau mais sans taille !!!! 
;
;       De plus MemorySize(*MemoryID) donne la taille de la mémoire octroyé par AllocateMemory()                                                               
;              
;            Ce qui aurait été plus utile, c'est "ArraySize(Array() [, Dimension]) " 
;            qui aurait pu donner la taille du tableau, (voir fin de ce programme) 
;            mais comme il n'y en à pas.... Alors ça marche pas ! 
; ***********************************************************
;
Dim ArrayA.s(0)  
Dim ArrayB.s(0)   

#Bibliotheque=0
OpenLibrary(#Bibliotheque,"TestDllKccORG.dll")

    ;  -------------------------------------------------------------------------
    *PointeurArrayA = CallFunction(0, "CreateArray", 1)
	ArrayA() = *PointeurArrayA                  ; Affectation de l'adresse mémoire passé par la DLL de son AlocateMemory() 
	Debug *PointeurArrayA
	;
	Debug @ArrayA(1)                           ; Adresse du pointeur 1
	Debug PeekS(@ArrayA(1))               ; Donnée pointée par le pointeur .......... 1
	Debug PeekS(@ArrayA(2))               ; Donnée pointée par le pointeur .......... 2
	; 
	
	; ------------------------------------------------------------------------------------
    For i = 1 To 2*4                                        ; Il y a 2 appel de 4 d'ou 2*4   PAS de (MemorySize(ArrayB()) / 4) - 1   
        Debug "Premier essai = " + ArrayA(i) 
    Next                                                         
    ; 
    ; Que c'est-il passé pour que cela marche ? ICI j'ai forcé le système à lire des adresses mémoires qui correspondent à la  
    ;  mémoire réservé par AlocateMemory() dans la Dll... 
    ;  
    ;  Car dans la DLL on y a écrit des adresses et a écrit les données dans la mémoire pointé par ces adresses !!! 
    ; 
    ;  Soit exactement se que fait PB pour un tableau. 
    ;  Pour chaque indice du tableau il crée une adresse et écrit les données ou pointe l'adresse !
    ;                                                                    
    ;  -------------------------------------------------------------------------
    *PointeurArrayB = CallFunction(0, "CreateArray", 2) 
	ArrayB() = *PointeurArrayB
	Debug *PointeurArrayB
    ;
    For i = 1 To 2*4;                                             ; Il y a deux appell de 4     ???  PAS DE  (MemorySize(ArrayB()) / 4) - 1   
        Debug "Second essai = " +Str(@ArrayB(i))+" "+ArrayB(i)  
    Next
    Debug @ArrayB(i+1)
    ; ***************************************************************************************
    ;  FIN DE CETTE PARTIE !
    ; ******************************************************************************
    ;   -------------------------------------------------
    ;   Maintenant preuve sur un tableau existant ! 
    ;   Taille=ArraySize(Table$() ,1) 
    ; -----------------------------------------------------------------------------------	
    Dim Table.s(12)
    For i=1 To 12:Table(i)=Str(64+i)+Str(92+i):Next i
    ; -----------------------------------
    Taille=ArraySize(Table() ,1)                    ; Sur tableau existant OK
    Debug "*************************************************"
    Debug "Taille du Tableau existant Table() = "+Str(Taille )
    ; =========================================
    ;             Taille=ArraySize(ArrayA.s() ,1)
    ; ------------------------------------------------------------------	
    ; Taille=ArraySize(ArrayA.s() ,1)             ; <== Ici il ne veux rien entendre car il ne connait pas ??? 
    ; Debug "Taille du tableau construit  ArrayA()= "+Str(Taille)
    ;=========================================
End
; ***********************************************************
Voilà, voilà... Je ne sais pas si cela va t'aider, mais sous cette forme tu est bien partis pour une astuce. :lol:
Et moi cela ma bien aidé pour comprendre comment la mémoire est organisé !:lol:
Que la doc est explicite mais un peu trop succincte ! :?
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Message par Kwai chang caine »

Merci GEBONET 8)

Je me remet juste sur le PC depuis quelques jours.
Je regarderais ta methode dans la semaine. :D

Passe une bonne journée
Avatar de l’utilisateur
GeBonet
Messages : 453
Inscription : ven. 29/févr./2008 16:17
Localisation : Belgique

Message par GeBonet »

Salut, bon retour,
Je regarderais ta methode dans la semaine.
En fait il ne s'agit pas de ma méthode, mais de la tienne qui fonctionne dans ce cas (un truc quoi) !
Sauf qu'au lieu de renvoyer un tableau tu renvois une adresse d'AllocateMemory() qui te sert de pointeur a la table ArrayA() ou ArrayB() et comme dans la DLL tu as écris des adresses pointant tes données comme si c'était des adresses de tableau et des données à ces adresse là, alors quand on demande de lire ArrayA(1) il lit la première adresse pointé et va lire la donnée correspondante que tu y a rangé dans la DLL. Et comme tu y a rangé 2 fois 4 données pointées par 2 fois 4 adresses alors ArrayA(1... à ...8 ) te donne cela comme si c'était un tableau crée...

Idem pour le ArrayB()... Et donc solutionné ton problème... Sauf qu'en réalité les tableaux ArrayA et B, n'existent pas pour l'exe appelant... Puisque tu n'as pas donnée de dimension... Tu as crée une simulation de tableau :lol: (La preuve dans le bout juste après ; " FIN DE CETTE PARTIE !" ou il donne comme erreur la lecture de la taille de ArrayA()... normal car n'existe pas pour l'exe. Et pourtant on la lus juste avant non 8) ).

Mais tu passe bien des données écrites dans la DLL à un Tableau qui lui est dans l'exe... La seule chose obligatoire c'est de connaitre la taille du tableau fictif... Mais ça tu la connait puisque dans la DLL tu fait bien une boucle de 4 qui est exécuté deux fois (récursivité de l'appel interne)... Donc tu peux aussi appliquée à l'extérieur de la DLL !

L'erreur en fait est d'essayer d'utiliser MemorySize() pour obtenir une taille de tableau !
Extrait doc : MemorySize(*MemoryID) donne la taille de la mémoire octroyé par AllocateMemory()
Ors dans ce cas AllocateMemory() se trouve dans la Dll et n'a rien à voir avec DIM ArrayA(0) ou DIM ArrayB(0) à part le fait que tu utilise ce départ de déclaration pour y ranger l'adresse obtenue en retour et lire le contenu pointé par ces adresses comme si c'était un tableau.

Au fait il s'agit là vraiment d'une drôle d'astuce... :lol: (Involontaire peut-être, mais utilisable et a creuser) !
Répondre