Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Sujet: Re: KGF_dll - nouvelles versions Jeu 28 Oct 2021 - 11:17
KGF.dll V9.59 du 28/10/2021
Nouveautés: - SQLite3: nouvelle fonction SelectAlternativeSQLite3Version
Modules modifiés: KGF.dll KGF.chm
La doc est à jour.
Cette fonction permet de remplacer la version par défaut de SQLite3 (V3.6.7 embarquée dans KGF.dll) par une autre version de SQLite (testé actuellement avec SQLite336.dll pour la version V3.36). La documention donne le mode d'emploi extact. Le programme de démo ci-après inclut une nouvelle ligne dans le menu "File" pour choisir la version. Pour cela, la DLL contenant la nouvelle version doit être copiée dans le ossier C:\SQLite367.
' récupérer le nombre de lignes de la réponse RowCount% = dll_call2("GetSQLite3RowCount",SQL%,adr(TestTable$)) item_add 1001," "+str$(rowcount%)+" Lignes dans table "+TestTable$ return
fill: if SQL%=0 message "No database open" return end_if xNbrRecords% = 10 : ' 500 min 1020,0 : max 1020,xNbrRecords% clear 1011 for x%=1 to xNbrRecords% Position 1020,x% ' construire la requête SQL sOtherID$ = str$(int(1 + Rnd(9))) sName$ = chr$(int(65+rnd(26)))+str$(x%) sNumber$ = rnd(1) p% = instr(sNumber$,",") if p%>0 then sNumber$ = left$(sNumber$,p%-1)+"."+mid$(sNumber$,p%+1,len(sNumber$)) sNotes$ = "Possibilité de stocker des données BLOB" sSQL$ = "INSERT INTO "+TestTable$+"(Name,OtherID,Number,Notes) VALUES (²"+sName$+"²,"+sOtherID$+","+sNumber$+",²"+sNotes$+"²);" item_add 1011,sSQL$ ' exécuter la requête SQL res% = dll_call2("ExecuteSQLite3Script",SQL%,adr(sSQL$)) if res%<0 item_add 1011,"Erreur dans requête SQL" return end_if next x% item_add 1011,"Database filled with "+str$(xNbrRecords%)+" records" Position 1020,0 return
fillgrid: if SQL%=0 message "No database open" return end_if ' récupérer le nombre de lignes de la réponse RowCount% = dll_call2("GetSQLite3RowCount",SQL%,adr(TestTable$)) if RowCount%<1 item_add 1011,"Table "+TestTable$+"manquante ou vide" return end_if grid_row 1034,RowCount%+1
' charger la table dans le gridRequête SQL sSQL$ = "SELECT * " sSQL$ = sSQL$ + "FROM "+testTable$ sSQL$ = sSQL$ + " WHERE (("+testTable$+".Name)" sSQL$ = sSQL$ + " Like ²"+text$(1031)+"²)" if text$(1033)<>"" sSQL$ = sSQL$ + " "+text$(1033)+";" else sSQL$ = sSQL$ + ";" end_if
' préparation de la requête: sélection des enregistrements de la table selon les critères res% = dll_call2("CompileSQLite3Script",SQL%,adr(sSQL$))
' Vider grid for i%=2 to RowCount%+1 for j%=1 to grid_column(1034) grid_write 1034,i%,j%,"" next j% next i%
' boucle d'affichage du résultat min 1020,0 : max 1020,5 : position 1020,0 for i%=1 to RowCount% position 1020,i% ' Remplissage grid par lecture de chacun des colonnes de chacun des enregistrements res% = dll_call1("GetSQLite3NextRow",SQL%) if res%<0 then exit_for for j%=1 to 5 res% = dll_call2("GetSQLite3CellText",SQL%,j%) grid_write 1034,i%+1,j%,text$(1001) : ' Ecriture dans la cellule correspondante next j% next i% res% = dll_call1("FinalizeSQLite3Request",SQL%) return
tables: if SQL%=0 message "No database open" return end_if res% = dll_call1("GetSQLite3TableNames",SQL%) item_add 1001,str$(res%)+" tables" return
columns: if SQL%=0 message "No database open" return end_if s$ = trim$(text$(1031)) if s$="" then s$ = TestTable$ res% = dll_call2("GetSQLite3ColumnNames",SQL%,adr(s$)) item_add 1001,str$(res%)+" colonnes dans table "+s$ return
Toutes les fonctions utilisées dans ce programme de démo fonctionnent avec la version 3.36 de SQLite3.
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Sujet: Re: KGF_dll - nouvelles versions Ven 29 Oct 2021 - 9:47
Nouvelle fonction WhoLaunchedMe (version V9.57 du 25/10/2021):
La documention de cette fonction est faite dans KGF.chm et dans la documentation en ligne.
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Sujet: Re: KGF_dll - nouvelles versions Ven 29 Oct 2021 - 12:23
KGF.dll V960 du 29/10/2021
Nouveautés: - SQLite3: nouvelle fonction SelectAlternativeSQLite3Folder
Modules modifiés: KGF.dll KGF.chm
La doc est à jour.
Cette fonction permet de choisir un autre dossier que C:\SQLite367 qui est le dossier par défaut. N'importe quel dossier valide est accepté. Si le dossier n'existe pas, il sera créé. Après l'appel de cette fonction, la version sélectionnée de SQLite3 est ala version embarquée V3.6.7.
Voici le programme de démo avec cette nouvelle possibilité dans le menu "File":
' récupérer le nombre de lignes de la réponse RowCount% = dll_call2("GetSQLite3RowCount",SQL%,adr(TestTable$)) item_add 1001," "+str$(rowcount%)+" Lignes dans table "+TestTable$ return
fill: if SQL%=0 message "No database open" return end_if xNbrRecords% = 10 : ' 500 min 1020,0 : max 1020,xNbrRecords% clear 1011 for x%=1 to xNbrRecords% Position 1020,x% ' construire la requête SQL sOtherID$ = str$(int(1 + Rnd(9))) sName$ = chr$(int(65+rnd(26)))+str$(x%) sNumber$ = rnd(1) p% = instr(sNumber$,",") if p%>0 then sNumber$ = left$(sNumber$,p%-1)+"."+mid$(sNumber$,p%+1,len(sNumber$)) sNotes$ = "Possibilité de stocker des données BLOB" sSQL$ = "INSERT INTO "+TestTable$+"(Name,OtherID,Number,Notes) VALUES (²"+sName$+"²,"+sOtherID$+","+sNumber$+",²"+sNotes$+"²);" item_add 1011,sSQL$ ' exécuter la requête SQL res% = dll_call2("ExecuteSQLite3Script",SQL%,adr(sSQL$)) if res%<0 item_add 1011,"Erreur dans requête SQL" return end_if next x% item_add 1011,"Database filled with "+str$(xNbrRecords%)+" records" Position 1020,0 return
fillgrid: if SQL%=0 message "No database open" return end_if ' récupérer le nombre de lignes de la réponse RowCount% = dll_call2("GetSQLite3RowCount",SQL%,adr(TestTable$)) if RowCount%<1 item_add 1011,"Table "+TestTable$+"manquante ou vide" return end_if grid_row 1034,RowCount%+1
' charger la table dans le gridRequête SQL sSQL$ = "SELECT * " sSQL$ = sSQL$ + "FROM "+testTable$ sSQL$ = sSQL$ + " WHERE (("+testTable$+".Name)" sSQL$ = sSQL$ + " Like ²"+text$(1031)+"²)" if text$(1033)<>"" sSQL$ = sSQL$ + " "+text$(1033)+";" else sSQL$ = sSQL$ + ";" end_if
' préparation de la requête: sélection des enregistrements de la table selon les critères res% = dll_call2("CompileSQLite3Script",SQL%,adr(sSQL$))
' Vider grid for i%=2 to RowCount%+1 for j%=1 to grid_column(1034) grid_write 1034,i%,j%,"" next j% next i%
' boucle d'affichage du résultat min 1020,0 : max 1020,5 : position 1020,0 for i%=1 to RowCount% position 1020,i% ' Remplissage grid par lecture de chacun des colonnes de chacun des enregistrements res% = dll_call1("GetSQLite3NextRow",SQL%) if res%<0 then exit_for for j%=1 to 5 res% = dll_call2("GetSQLite3CellText",SQL%,j%) grid_write 1034,i%+1,j%,text$(1001) : ' Ecriture dans la cellule correspondante next j% next i% res% = dll_call1("FinalizeSQLite3Request",SQL%) return
tables: if SQL%=0 message "No database open" return end_if res% = dll_call1("GetSQLite3TableNames",SQL%) item_add 1001,str$(res%)+" tables" return
columns: if SQL%=0 message "No database open" return end_if s$ = trim$(text$(1031)) if s$="" then s$ = TestTable$ res% = dll_call2("GetSQLite3ColumnNames",SQL%,adr(s$)) item_add 1001,str$(res%)+" colonnes dans table "+s$ return
On pourra utiliser n'importe quel type de fichier binaire: JPG, BMP, MP4, EXE, DLL, ...
Mais sache que des contenus de ce type gonflent énormément le volume de la base et ont donc une influence importance sur les performances. Ce type de stockage esgt utile pour de tout petis fichiers bianires genre icônes. Par contre, pour les gros fichiers, il est conseillé de mémoriser le nom du fichier dans un champ texte si c'est possible.
Marc
Nombre de messages : 2466 Age : 63 Localisation : TOURS (37) Date d'inscription : 17/03/2014
Sujet: Re: KGF_dll - nouvelles versions Ven 29 Oct 2021 - 17:09
Super ! Merci Klaus !
JP06
Nombre de messages : 20 Age : 74 Date d'inscription : 01/01/2012
Sujet: KGF_dll - nouvelles versions Dim 7 Nov 2021 - 18:58
Salut Klaus, Sauf erreur de ma part , dans la version 9.60 du 29/10/21, la fonction sqlite "GetSQLite3RowCount" pointe dans l'aide en ligne sur la fonction "GetSQLite3ColumnNames" Pourrais tu voir cela ? Merci pour ton travail.
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Oups... les pièges du copier/coller ! Merci de l'avoir signalé. Ce sera corrigé prochainement.
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Sujet: Re: KGF_dll - nouvelles versions Mer 10 Nov 2021 - 10:15
KGF.dll V9.61 du 09/11/2021
Nouveautés: - ShowMessageModal: ajout saisie d'un texte - Nouvelle fonction: GetShowMessageModalText (retour du texte saisi par ShowMessageModal) - correction de la doc selon le problème soulevé par JP06
Modules modifiés: KGF.dll KGF.chm
La doc est à jour.
L'extension de la fonction ShowMessageModal permet de gérer un champ de saisie texte (un EDIT) dans la fenêtre de dialogue ouverte par cette fonction. La valeur saisie peut être récupérée par la fonction GetShowMessageModalText .
Ceci permet de créer plus facilement des dialogues de style MESSAGE_INPUT$, mais avec plus de souplesse.
Voici une démo de ces deux fonctions:
Code:
' test_ShowMessageModal.bas
label generer
dim res%, titre$, mes$, txt$, b1$, b2$, b3$, code%
caption 0,"Test de la fonction ShowMessageModal alpha 1 : top 1,10 : left 1,10 : caption 1,"Titre de la fenêtre:" edit 11 : top 11,10 : left 11,110 : width 11,400 hint 11,"Le contenu de ce champ sera affiché en tant que titre de la fenêtre de dialogue"
alpha 2 : top 2,40 : left 2,10 : caption 2,"Message:" edit 21 : top 21,40 : left 21,110 : width 21,400 hint 21,"Le contenu de ce champ sera affiché dans un libellé de message à l'intérieur de la fenêtre de dialogue"
alpha 3 : top 3,70 : left 3,10 : caption 3,"Label bouton 1:" edit 31 : top 31,70 : left 31,110 : width 31,400 hint 31,"Le contenu de ce champ servira de libellé du bouton de gauche."+chr$(13)+chr$(10)+"Si ce champ est vide, ce bouton n'apparaît pas."
alpha 4 : top 4,100 : left 4,10 : caption 4,"Label bouton 2:" edit 41 : top 41,100 : left 41,110 : width 41,400 hint 41,"Le contenu de ce champ servira de libellé du bouton du milieu."+chr$(13)+chr$(10)+"Si ce champ est vide, ce bouton n'apparaît pas."
alpha 5 : top 5,130 : left 5,10 : caption 5,"Label bouton 3:" edit 51 : top 51,130 : left 51,110 : width 51,400 hint 51,"Le contenu de ce champ servira de libellé du bouton de droite."+chr$(13)+chr$(10)+"Si ce champ est vide, ce bouton n'apparaît pas."
alpha 6 : top 6,170 : left 6,10 : caption 6,"Zone texte:" check 61 : top 61,170 : left 61,110 : width 61,400 : caption 61," Saisie d'un texte" hint 61,"Si cette case est cochée, une zone de saisie de texte apparaîtra"
button 99 : top 99,230 : left 99,110 : width 99,400 : font_bold 99 caption 99,"Générer la fenêtre" : on_click 99,generer hint 99,"Faire apparaître la fenêtre de dialogue"
alpha 7 : top 7,320 : left 7,10 : caption 7,"Code retour:" edit 71 : top 71,320 : left 71,110 : width 71,30 alpha 72 : top 72,320 : left 72,150
alpha 8 : top 8,350 : left 8,10 : caption 8,"Texte retourné:" edit 81 : top 81,350 : left 81,110 : width 81,400
dll_on "KGF.dll" end
generer: titre$ = text$(11) mes$ = text$(21) b1$ = trim$(text$(31)) b2$ = trim$(text$(41)) b3$ = trim$(text$(51)) code% = 0 if b1$<>"" then code% = code% + 1 if b2$<>"" then code% = code% + 2 if b3$<>"" then code% = code% + 4 if checked(61)=1 then code% = code% + 8 res% = dll_call6("ShowMessageModal",adr(titre$),adr(mes$), code%, adr(b1$), adr(b2$), adr(b3$)) text 71,str$(res%) select res% case 0: caption 72,"Arrêt par la croix rouge" case 1: caption 72,"Bouton 1: "+b1$ case 2: caption 72,"Bouton 2: "+b2$ case 4: caption 72,"Bouton 3: "+b3$ end_select txt$ = string$(255," ") res% = dll_call1("GetShowMessageModalText",adr(txt$)) text 81,trim$(txt$) return
EDIT 11/11/2021: ajout de messages HINT sur les champs de paramétrage
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Sujet: Re: KGF_dll - nouvelles versions Dim 14 Nov 2021 - 14:43
KGF.dll V9.62 du 14/11/2021
Nouveautés: - Nouvelles fonctionsSetImportantHandles, SetApplicationIcon - Nouvelle mini-DLL: SetApplicationIcons.dll
Modules modifiés: KGF.dll KGF.chm
La doc est à jour.
Ces fonctions sont très simples:
Code:
res% = dll_call2("fonctionsSetImportantHandles",handle_application,handle(0)) Cette fonction mémorise deux handles importants pour la fonction SetApplicationIcon
res% = dll_call1("SetApplicationIcon",typ%) Cette fonction change les icônes de l'application typ%=0 ==> retour aux icônes initiales typ%=1 ==> changer l'icône de la barre de titre de la form 0 typ%=2 ==> comme typ%=1, mais change aussu l'icône dans labarre des tâches
Pour que l'effet perdure, il faut que la DLL reste ouverte pendant la durée de vie du programme.
Voici une démo, utilisant au choix KGF.dll ou SetApplicatioinIcons.dll:
Code:
' test_SetApplicationIcon.bas
label choixtype, choiximage, appliquer dim res%, nom$, typ%
' dll_on "KGF.dll" : ' uniquement s'il faut utiliser LoadAnyImageFile dll_on "ApplicationIcons.dll" : ' suffisant si on n'utilise pas LoadAnyImageFile !
open_dialog 1 : filter 1,"Images|*.bmp;*.jpg;*.jpeg" combo 10 : top 10,10 : left 10,80 : width 10,300 : on_click 10,choixtype item_add 10,"Annuler les icônes personnalisées" item_add 10,"Icône de la barre de titre" item_add 10,"Icône de la barre de titre et de a barre des tâches" text 10,item_read$(10,1) typ% = 0
alpha 5 : top 5,40 : left 5,10 : caption 5,"Fichier image: " edit 6 : top 6,40 : left 6,80 : width 6,300 : inactive 6 button 7 : top 7,40 : left 7,380 : width 7,30 : font_bold 7 : caption 7,"..." on_click 7,choiximage
button 9 : top 9,70 : left 9,80 : caption 9,"Appliquer" : on_click 9,appliquer
picture 2 : top 2,120 : left 2,10 : width 2,32 : height 2,32 stretch_on 2
end
choixtype: typ% = item_index(10) - 1 return
choiximage: nom$ = file_name$(1) if nom$="_" then return text 6,trim$(nom$) ' res% = dll_call1("LoadAnyImageFile",adr(nom$)) : ' utile si l'on veut utiliser d'autres formats... file_load 2,nom$ clipboard_paste 2 return
Nouveautés: - Nouvelle fonction: ExportSQLite3TableToCSV = exporter une table SQLite3 en format CSV - Nouvelle fonction: ImportSQLite3TableFromCSV = importer une table SQLite3 d'un fichier CSV
Modules modifiés: KGF.dll KGF.chm
La doc est à jour.
Ces fonctions permettent d'exporter ou importer une table entière (ou une sélection d'enregistrements d'une table), tout en triant les enregistrement selon un critère choisi.
Nouveautés: - gestion de tableaux mlti-dimensionnels (2 ou 3 dimensions) nouvelles fonctions: GetIntegerArrayFromPanoramic, SetIntegerArrayFromPanoramic, GetFloatArrayFromPanoramic, SetFloatArrayFromPanoramic, DefineMBA, ResetMDA, TestStringArray
Modules modifiés: KGF.dll
La doc suivra.
On peut maintenant accéder aux tableaux Panoramic de 2 ou 3 dimensions oà aprtir de KGF.dll (ou généralement à partir d'une DLL en Delphi). Tout ce qui est necessaire pour cela est compris dans une unite Delphi séparée. Pour cela, il faut que le tableau multi-dimensionnel soit "simulé" dans un tableau uni-dimensionnel (voir https://panoramic.1fr1.net/t6694-des-dll-pour-panoramic mon post du 18/12/2021 à 18h38).
Cet objet permet de gérer des tableaux multi-dimensionnels simulés dans un tableau Panoramic uni-dimensionnel. L'intérêt de ce système est que les tableaux uni-dimensionnels peuvent facilement être passés en paramètre à la DLL. Ce n'est pas le cas des tableaux multi-dimensionnels. L'objet MDA est conçu pour donner accès aux fonctions d'une DLL aux données d'un tableau multi-dimensionnel de Panoramic. Pour cela, il faut déclarer en Panoramic un tableau uni-dimensionnel selon la formule: dim MonTableau((dim1+1) * (dim2+1) * (dim3+1) - 1) Exemple: dim MonTableau(5,3,7) sera remplacé par dim MonTableau(6*4*8-1)
L'implémentation actuelle est prévue pour des tableaux jusqu'à 3 dimensions.
Un tableau multi-dimensionnel doit être déclaré avec son nom et ses dimenions. L'objet MDA mémorise et gère toutes les déclarations ainsi que l'accès physique aux données. Deux fonctions exportées (accessibles en Panoramic) permettent définir les tableaux: res% = dll_call4("DefineMDA",adt(tableau$),d1%,d2%,d3%) : ' crée ou modifie la déclaration d'un tableau res% = dll_call0("ResetMDA") : ' efface toutes les déclarations de tableaux Les fonctions et procédures suivantes sont utilisables dans la DLL (en Delphi), mais pas appelables par Panoramic: MDA.IndexOfArray(aName: string): string retourne l'index du tableau ou -1 si non déclaré MDA.TypeOfArray(aName: string): TypMDA retourne le type d'un tableau MDA.Count: integer; retourne le nombre de tableaux déclarés MDA.GetIntegerArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): integer retourne le contenu d'un élément MDA.GetFloatArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pfloat): double retourne le contenu d'un élément MDA.GetStringArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): string; retourne me contenu d'un élément MDA.SetIntegerArrayElement(aIndex, d1,d2,d3: integer; aValue: integer; aPanoramic: pinteger) remplace le contenu d'un élément MDA.SetFloatArrayElement(aIndex, d1,d2,d3: integer; aValue: double; aPanoramic: pfloat) remplace le contenu d'un élément MDA.SetStringArrayElement(aIndex, d1,d2,d3: integer; aValue: string; aPanoramic: pinteger) remplace le contenu d'un élément }
{ La constante StringParameterMethod indique la méthode de passage d'une chaîne de caractères en paramètre à une DLL, aussi bien en entrée qu'en sortie. Elle détermine comment le résultat de ADR(s$) doit être intreprété: Méthode 1: ADR(s$) donne l'adresse du premier caractère du texte Méthode 2: ADR(s$) donne l'adresse d'un mot contenant l'adresse du premier caractère du texte Ceci est valable en environnement compilé (PCompiledMode=true). En version interprétée (PCompiledMode=false), uniquement la méthode 2 est employée ! } const StringParameterMethod = 2; type Pfloat = ^Double;
type TypMDA = (tMDAundefined, tMDAfloat, tMDAinteger, tMDAstring); type TMDA = class private fNames: array of string; fTypes: array of TypMDA; fDimensions: array of array of integer; fMemoHandle: HWND; published function IndexOfArray(aName: string): integer; function TypeOfArray(aName: string): TypMDA; function Count: integer; function GetIntegerArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): integer; function GetFloatArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pfloat): double; function GetStringArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): string; procedure SetIntegerArrayElement(aIndex, d1,d2,d3: integer; aValue: integer; aPanoramic: pinteger); procedure SetFloatArrayElement(aIndex, d1,d2,d3: integer; aValue: double; aPanoramic: pfloat); procedure SetStringArrayElement(aIndex, d1,d2,d3: integer; aValue: string; aPanoramic: pinteger); procedure AddArray(aName: string; d1, d2, d3: integer); procedure ModifyArray(aName: string; d1, d2, d3: integer); property MemoHandle: HWND read fMemoHandle write fMemoHandle; constructor CreateNew(aMemoHandle: HWND); destructor Destroy; end;
var MDA: TMDA; PCompiledMode: boolean = false; // flag "DLL appelée par un programme compilé" // la variable PCompiledMode est initialisée par défaut ) "faux". // ce ci signifie que Panoramic est en mode "interprété", pas en mcde "compile" // pour développer un code opérationnel dans les deux modes, il faut détecter l'état de l'exécutable. // Ceci peut être fait au chzrgement de la DLL, dans la procédure d'initialisation // en plaçant cette variable dans une unité de données globales et en appelant ceci: { procedure DetectCompiledMode; // routine conçue et testée par Klaus var exename: string; myFile: File; data: integer; begin PCompiledMode := false; // défaut: généré par Panoramic_Editor.exe ou Panoramic.exe exename := application.exename; AssignFile(myFile, exename); FileMode := fmOpenRead; Reset(myFile, 4); // Now we define one record as 4 byte BlockRead(MyFile,data,1); CloseFile(MyFile); // compilé: $00905A4D // interprété: $00505A4D if data<>$00505A4D then PCompiledMode := true; end; }
implementation
// procédure d'aide specifique pour copier un string dans uune variable Panoramic // procédure compatible avec la version compilée de PANORAMIC // s = string (éventuellement multi-ligne) à envoyer à Panoramic // par = identifiant de destination soit ADR(s$) soit HANDLE(memo%) procedure CopyStringToPanoramic(s: string; par: integer); var p1, p2: pchar; n, p: integer; s1, s2: string; pi, po: pbyte; zero: byte;
begin zero := 0; p1 := @zero; n := length(s); if n>0 then p1 := @s[1]; if PCompiledMode then begin // mode compilé pi := pbyte(@s[1]); {$if StringParameterMethod=1} po := pbyte(par); // méthode V1 (Jack): ADR(s$) pointe vers l'adresse du premier caractère {$else} po := pbyte(pinteger(par)^); // méthode V2 (Jack): ADR(s$) pointe vers un mot contenant l'adresse du premier caractère {$ifend} while po^<>0 do begin if pi^<>0 then begin po^ := pi^; inc(po); inc(pi); end else begin po^ := 32; inc(po); end; end; end else begin //mode interprété if n>0 then p1 := pchar(@s[1]); p2 := pchar(pinteger(par)^); while p2^<>#0 do begin if n>0 then begin if p1<>#0 then p2^ := p1^ else dec(p2); end else begin p2^ := #32; end; inc(p1); inc(p2); dec(n); end; end; end;
destructor TMDA.Destroy; begin SetLength(fNames,0); SetLength(fTypes,0); SetLength(fDimensions,0); inherited; end;
function TMDA.IndexOfArray(aName: string): integer; var i: integer; begin result := -1; if Length(fNames)=0 then exit; for i:=0 to high(fNames) do begin if fNames[i]=aName then begin result := i; exit; end; end; end;
function TMDA.TypeOfArray(aName: string): TypMDA; var i: integer; begin result := tMDAundefined; i := IndexOfArray(aName); if i>=0 then result := fTypes[i]; end;
function TMDA.Count: integer; begin result := Length(fNames); end;
function TMDA.GetIntegerArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): integer; var pi: pinteger; offset: integer; begin result := 0; if (aIndex<0) or (aIndex>high(fNames)) then exit; if fTypes[aIndex]<>tMDAinteger then exit; pi := aPanoramic; offset := 0; if fDimensions[aIndex][1]>0 then begin offset := offset + d1*fDimensions[aIndex][1]; if fDimensions[aIndex][2]>0 then begin offset := offset + d2*fDimensions[aIndex][2]; offset := offset + d3; end else begin offset := offset + d2; end; end else begin offset := d1; end; inc(pi,offset); result := pi^; end;
function TMDA.GetFloatArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pfloat): double; var pf: pfloat; offset: integer; begin result := 0; if (aIndex<0) or (aIndex>high(fNames)) then exit; if fTypes[aIndex]<>tMDAfloat then exit; pf := aPanoramic; offset := 0; if fDimensions[aIndex][1]>0 then begin offset := offset + d1*fDimensions[aIndex][1]; if fDimensions[aIndex][2]>0 then begin offset := offset + d2*fDimensions[aIndex][2]; offset := offset + d3; end else begin offset := offset + d2; end; end else begin offset := d1; end; inc(pf,offset); result := pf^; end;
function TMDA.GetStringArrayElement(aIndex, d1,d2,d3: integer; aPanoramic: pinteger): string; var pi: pinteger; offset: integer; adr: integer; s: string; begin result := ''; if (aIndex<0) or (aIndex>high(fNames)) then exit; if fTypes[aIndex]<>tMDAstring then exit; pi := aPanoramic; offset := 0; if fDimensions[aIndex][1]>0 then begin offset := offset + d1*fDimensions[aIndex][1]; if fDimensions[aIndex][2]>0 then begin offset := offset + d2*fDimensions[aIndex][2]; offset := offset + d3; end else begin offset := offset + d2; end; end else begin offset := d1; end;
// if MemoHandle<>0 then DumpPanoramic(MemoHandle,integer(pi),48); //showmessage('a4');
inc(pi,offset); result := pstring(pi)^; end;
procedure TMDA.SetIntegerArrayElement(aIndex, d1,d2,d3: integer; aValue: integer; aPanoramic: pinteger); var pi: pinteger; offset: integer; begin if (aIndex<0) or (aIndex>high(fNames)) then exit; pi := aPanoramic; offset := 0; if fDimensions[aIndex][1]>0 then begin offset := offset + d1*fDimensions[aIndex][1]; if fDimensions[aIndex][2]>0 then begin offset := offset + d2*fDimensions[aIndex][2]; offset := offset + d3; end else begin offset := offset + d2; end; end else begin offset := d1; end; inc(pi,offset); pi^ := aValue; end;
procedure TMDA.SetFloatArrayElement(aIndex, d1,d2,d3: integer; aValue: double; aPanoramic: pfloat); var pf: pfloat; offset: integer; begin if (aIndex<0) or (aIndex>high(fNames)) then exit; pf := aPanoramic; offset := 0; if fDimensions[aIndex][1]>0 then begin offset := offset + d1*fDimensions[aIndex][1]; if fDimensions[aIndex][2]>0 then begin offset := offset + d2*fDimensions[aIndex][2]; offset := offset + d3; end else begin offset := offset + d2; end; end else begin offset := d1; end; inc(pf,offset); pf^ := aValue; end;
procedure TMDA.SetStringArrayElement(aIndex, d1,d2,d3: integer; aValue: string; aPanoramic: pinteger); var pi: pinteger; offset: integer; begin if (aIndex<0) or (aIndex>high(fNames)) then exit; pi := aPanoramic; offset := 0; if fDimensions[aIndex][1]>0 then begin offset := offset + d1*fDimensions[aIndex][1]; if fDimensions[aIndex][2]>0 then begin offset := offset + d2*fDimensions[aIndex][2]; offset := offset + d3; end else begin offset := offset + d2; end; end else begin offset := d1; end; inc(pi,offset); CopyStringToPanoramic(aValue,integer(pi)); end;
procedure TMDA.AddArray(aName: string; d1, d2, d3: integer); var i: integer; begin i := Length(fNames); SetLength(fNames,i+1); SetLength(fTypes,i+1); SetLength(fDimensions,i+1); SetLength(fDimensions[i],3); fNames[i] := aName; fTypes[i] := tMDAfloat; if RightStr(aName,1)='%' then fTypes[i] := tMDAinteger; if RightStr(aName,1)='$' then fTypes[i] := tMDAstring; fDimensions[i][0] := d1; fDimensions[i][1] := d2; fDimensions[i][2] := d3; end;
procedure TMDA.ModifyArray(aName: string; d1, d2, d3: integer); var i: integer; begin i := self.IndexOfArray(aName); fNames[i] := aName; fTypes[i] := tMDAfloat; if RightStr(aName,1)='%' then fTypes[i] := tMDAinteger; if RightStr(aName,1)='$' then fTypes[i] := tMDAstring; fDimensions[i][0] := d1; fDimensions[i][1] := d2; fDimensions[i][2] := d3; end;
// copier un tableau de type integer de Panoramic dans un tableau dynamique Delphi dans la DLL function GetIntegerArrayFromPanoramic(aIntegerArray: pinteger; nDimension: integer): integer; stdcall; export; var IntegerArray: array of Integer; i: integer; pi: pinteger; begin result := -1; try if aIntegerArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide SetLength(IntegerArray,nDimension+1); // affecter la mémoire pi := aIntegerArray; // boucle de lecture for i:=0 to nDimension do begin IntegerArray[i] := pi^; // ccpier un élément inc(pi); // ajuster le pointeur showmessage(format('GetIntegerArrayFromPanoramic %d: %d',[i,IntegerArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports GetIntegerArrayFromPanoramic;
// copier un tableau de type integer d'un tableau dynamique Delphi dans la DLL vers un tableau dans Panoramic function SetIntegerArrayFromPanoramic(aIntegerArray: pinteger; nDimension: integer): integer; stdcall; export; var IntegerArray: array of Integer; i: integer; pi: pinteger; begin result := -1; try if aIntegerArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide
// les 2 lignes suivantes sont là pour "simuler" un tableau existant dans la DLL... SetLength(IntegerArray,nDimension+1); // affecter la mémoire for i:=0 to nDimension do IntegerArray[i] := i*2;
if nDimension>=Length(IntegerArray) then exit; // trop de données demandées ? pi := aIntegerArray; // boucle d'écriture for i:=0 to nDimension do begin pi^ := IntegerArray[i]; // ccpier un élément inc(pi); // ajuster le pointeur end; result := 0; except end; end; exports SetIntegerArrayFromPanoramic;
// copier un tableau de type float de Panoramic dans un tableau dynamique Delphi dans la DLL function GetFloatArrayFromPanoramic(aFloatArray: pfloat; nDimension: integer): integer; stdcall; export; var FloatArray: array of double; i: integer; pf: pfloat; begin result := -1; try if aFloatArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide SetLength(FloatArray,nDimension+1); // affecter la mémoire pf := aFloatArray; // boucle de lecture for i:=0 to nDimension do begin FloatArray[i] := pf^; // ccpier un élément inc(pf); // ajuster le pointeur showmessage(format('GetFloatArrayFromPanoramic %d: %f',[i,FloatArray[i]])); // juste pour montrer le résultat - ligne à supprimer ! end; result := 0; except end; end; exports GetFloatArrayFromPanoramic;
// copier un tableau de type float d'un tableau dynamique Delphi dans la DLL vers un tableau dans Panoramic function SetFloatArrayFromPanoramic(aFloatArray: pfloat; nDimension: integer): integer; stdcall; export; var FloatArray: array of double; i: integer; pf: pfloat; begin result := -1; try if aFloatArray=nil then exit; // il faut au moins une adresse if nDimension<0 then exit; // il faut une dimenion Panoramic valide
// les 2 lignes suivantes sont là pour "simuler" un tableau existant dans la DLL... SetLength(FloatArray,nDimension+1); // affecter la mémoire for i:=0 to nDimension do FloatArray[i] := i*2.002;
if nDimension>=Length(FloatArray) then exit; // trop de données demandées ? pf := aFloatArray; // boucle de lecture for i:=0 to nDimension do begin pf^ := FloatArray[i]; // ccpier un élément inc(pf); // ajuster le pointeur end; result := 0; except end; end; exports SetFloatArrayFromPanoramic;
{ Objet MDA - Multi-DimensionalArray
Cet objet permet de gérer des tableaux multi-dimensionnels simulés dans un tableau Panoramic uni-dimensionnel. L'intérêt de ce système est que les tableaux uni-dimensionnels peuvent facilement être passés en paramètre à la DLL. Ce n'est pas le cas des tableaux uni-dimensionnels.
L'implémentation actuelle est prévue pour des tableaux jusqu'à 3 dimensions.
}
function GetStringFromPanoramic(par: integer): string; begin result := pstring(par)^; end;
// cette fonction ajoute ou modifie la déclaration d'un tableau function DefineMBA(aName: integer; d1, d2, d3: integer; hMemo: HWND): integer; stdcall; export; var s: string; index: integer; begin result := -1; try if not assigned(MDA) then MDA := TMDA.CreateNew(hMemo); // créer la table maître si besoin s := Trim(GetStringFromPanoramic(aName)); // prendre le nom Panoramic du tableau if s='' then exit; // nom manquant ? index := MDA.IndexOfArray(s); // chercher le tableau dans la table maître if index<0 then begin // tableau pas encore enregistré ? MDA.AddArray(s,d1,d2,d2); // ajouter une nouvelle déclaration end else begin // tableau déjà enregistré - changer dimensions MDA.ModifyArray(s,d1,d2,d3); // modifier la définition du tableau end; result := MDA.IndexOfArray(s); // retourner l'indice du tableau except end; end; exports DefineMBA;
// cette fonctiob efface toutes les déclarations de tableaux (PAS LES TABLEAUX !) function ResetMDA: integer; stdcall; export; begin result := -1; try if not assigned(MDA) then exit; MDA.Free; result := 0; except end; end; exports ResetMDA;
function TestStringArray(ind: integer; aArray: pinteger; d1,d2,d3: integer): integer; stdcall; export; var s, s1: string; begin result := -1; try if not assigned(MDA) then exit; if (ind<0) or (ind>=MDA.Count) then exit; s := MDA.GetStringArrayElement(ind,d1,d2,d3,aArray); if MDA.MemoHandle<>0 then begin s := format('%d,%d = %s',[d1,d2,s]); SendMessage(MDA.MemoHandle,WM_SETTEXT,0,integer(@s[1])); end; s1 := 'ABCDEFG'; MDA.SetStringArrayElement(ind,d1,d2,d3,s1,aArray); result := 0; except end; end; exports TestStringArray;
end.
Et voici une démo qui crée un tableau de chaînes de caractères de 6x4 éléments, comme ceci:
Code:
' dim strings$(5,3) dim strings$(6*4-1) : ' les longueurs des dimensions sont 6 x 4 cases !
Le tableau est rempli, puis on appelle la fonction TestStringArray qui lit de façon interne l'élément (3,2) et montre son contenui dans un mémo, puis modifie les données de cet élément en les remplaçant par "ABCDEF". Le contenu du tableau est affiché à l'écran, avantg et après l'appel de TestStringArray.
' dim strings$(5,3) dim strings$(6*4-1) : ' les longueurs des dimensions sont 6 x 4 cases !
full_space 0 memo 1 : top 1,0 : left 1,250 : width 1,300 : height 1,500 : bar_both 1
for i%=0 to 5 for j%=0 to 3 s$ = str$(i%)+","+str$(j%) ' message str$(i%)+","+str$(j%)+"="+s$ strings$(s$,i%,j%) next j% next i%
for i%=0 to 5 s$ = "" for j%=0 to 3 s$ = s$ + fstrings$(i%,j%) + " " next j% print s$ next i%
dll_on "KGF.dll" nom$ = "entiers$" ind% = dll_call5("DefineMBA",adr(nom$),5,3,0,handle(1)) message "DefineMBA: index = "+str$(ind%) res% = adr(strings$) res% = dll_call5("TestStringArray",ind%,adr(strings$),3,2,m1%) : ' lire l'élément (3,2) et le remplacer par "ABCDEF" message "TestStringArray = "+str$(res%)
print print "strings$(3,2) remplacé par ABCDEF:" for i%=0 to 5 s$ = "" for j%=0 to 3 s$ = s$ + fstrings$(i%,j%) + " " next j% print s$ next i%
end
' *** lire l'élément (i%,j%) du tableau entiers% ' ATTENTION: la fonction ne peut PAS avoir le même nom que le tableau ! ' Son nom est donc précédé d'un "f" pour signaler "fonction" fnc fstrings$(i%,j%) result strings$(i%*4+j%) : ' la première dimension a une longueur de 6 ! end_fnc
' *** écrire la valeur v$ dans l'élémént (i%,j%) du tableau strings$ sub strings$(v$,i%,j%) strings$(i%*4+j%) = v$ end_sub
Ceci devrait permettre aux développeurs de DLL d'accéder aux tableaux Panoramic, éventuellement en réimplémentant l'unité KGF_unit_MDA.pas dans un autre langage (C+, ...).
EDIT 21/12/2021 à 20h59: actualisation du code de l'unité KGF_unit_MDA avec deux modifications majeures: 1. rendre cette unité totalement indépendante des autres modules de KGF 2. ajouter la gestion des tableaux de chaînes de caractères
Dernière édition par Klaus le Mar 21 Déc 2021 - 21:00, édité 3 fois
papydall
Nombre de messages : 7017 Age : 74 Localisation : Moknine (Tunisie) Entre la chaise et le clavier Date d'inscription : 03/03/2012
Je viens de télécharger la nouvelle version de KGF.DLL.
Dans le code KGF_unit_MDA.pas, dans la partie remarque à l'intérieur des {…}, tu as écris "Ce n'est pas le cas des tableaux uni-dimensionnels." Tu veux sans doute dire : … des tableaux multi-dimensionnels.
Dans le code test ligne 33, il y a une erreur de frappe : deux-points au lieu d'un point-virgule.
A part ça, c'est bon, clair, net et précis. Bravo !
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Merci, Papydall, d'avoir lu si attentivement mon post ! J'ai corrigé les deux erreurs ci-dessus.
Pour ce qui est le ";" à la place d'un ":" en ligne 33, cela s'explique par le rajout ce ce commentaire après les tests, pour la clarté lors de la publication.
Je travaille sur la documentation de ces fonctions ainsi que sur des "conseils" d'utilisation des cds techniques pour les créateurs de DLLs.
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Dans mon post di-dessus, j'ai apporté une amélioration importante: EDIT 21/12/2021 à 20h59: actualisation du code de l'unité KGF_unit_MDA avec deux modifications majeures: 1. rendre cette unité totalement indépendante des autres modules de KGF 2. ajouter la gestion des tableaux de chaînes de caractères
Le module est ainsi directement utilisable dans n'importe quelle DLL.
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
J'ai publié la documentation de l'objet MDA (Multi Dimensional Arrays), en version CHM et en version "en ligne".
J'ai longuement développé les règles d'accès aux tableaux Panoramic à partir d'une DLL, à l'exemple d'une DLL en Delphi, mais le principe est adaptable à tout langage capable de produire des DLLs.
Dans la doc, il y a non seulement un programme de démo en Panoramic, mais également une unité Delphi entièrement indépendante de KGF.dll. Cette unité contient les fonctions décrites dans le chapitre MDA, mais également une petite routine (dans les commentaires au début du module) qui permet de déterminer si le programme e, cours d'exécution est en mode "compilé" ou en mode "interprêté". Cela peut être utile...
JL35
Nombre de messages : 7112 Localisation : 77 Date d'inscription : 29/11/2007
Sujet: Re: KGF_dll - nouvelles versions Dim 2 Jan 2022 - 20:13
Bonsoir Klaus, et bonne année !
J'ai un petit problème avec KGF.dll, je n'arrive pas à exécuter la fonction "RichEditFileInsert" Les autres fonctions RichEdit marchent parfaitement. J'ai repris l'exemple de la documentation, avec un petit fichier texte de quelques lignes :
Code:
dim RE1%, res%, f$ DLL_ON "C:\PANORAMIC\KGF\KGF.dll" RE1% = dll_call1("RichEditCreate",handle(0)) f$ = "Z:\Test.txt" res% = dll_call2("RichEditFileInsert",RE1%,adr(f$)) DLL_OFF END
(avec correction de RE en RE1 ligne 5)... rien ne s'affiche...
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Super ! ça marche ! Merci Klaus pour cette réaction au quart de tour ! je suis content. Du coup, encore Bonne Année à toi.
Juste une remarque: Le texte intégré depuis le fichier se conforme aux enrichissements de texte en cours dans le RichEdit, mais je n'ai plus la main et je ne peux plus rien y changer ni en rajouter...
Dernière édition par JL35 le Lun 3 Jan 2022 - 9:17, édité 1 fois
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
Nouveautés: - nouvelle fonction! SaveScannerImageToFile
Modules modifiés: KGF.dll
La doc suivra.
Cette fonction permet d'enregistrer directement l'image scannée dans un fichier. Elle sera copiée également dans le presse-papier. Toutes les extensions de fichier image acceptées par la fonction SaveAnyImageFile sont acceptées ici.
La doc de la fonction SaveScannerImageToFile est disponible (fichier CHM et doc en ligne).
Yannick aime ce message
Yannick
Nombre de messages : 8635 Age : 53 Localisation : Bretagne Date d'inscription : 15/02/2010
Sujet: re Jeu 17 Fév 2022 - 16:35
Salut Klaus.
Un petit souci avec l'objet scanner dans le sous programme EVENT du user_event :
Code:
EVENT: if bin_and(user_event_wparam,hex$("FF000000"))=hex$("05000000") if bin_and(user_event_wparam,hex$("00FF0000"))=hex$("010000") Active 0 end_if end_if return
J'ai un retour erreur pour une expression pas logique sur la ligne du premier if.
D'autre part, sur la doc, il manque une parenthèse pour fermer bin_and et les guillemets pout fermer hex$ sur les deux if.