WIP: SV_DLL_WIN #17

Closed
julien.misiak wants to merge 4 commits from SV_DLL_WIN into main
7 changed files with 257 additions and 5 deletions

32
Cargo.lock generated Normal file
View File

@ -0,0 +1,32 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "clego"
version = "0.1.0"
dependencies = [
"winapi",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -1,7 +1,5 @@
[workspace]
members = [
"webapp",
"clego",
"tauri",
"clego"
]
resolver = "2"

View File

@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
winapi = { version = "0.3.8", features = ["winuser","libloaderapi"] }
Review

Comme évoqué sur Matrix, prend plutôt inspiration sur l'exemple crossplatform ici : https://forge.p4pillon.org/P4Pillon/Krys4lide/src/branch/wip-debug-lib-c pour ne pas avoir besoin de winapi

Comme évoqué sur Matrix, prend plutôt inspiration sur l'exemple crossplatform ici : https://forge.p4pillon.org/P4Pillon/Krys4lide/src/branch/wip-debug-lib-c pour ne pas avoir besoin de winapi
Review

lorsque je déclare mes accès à la dll avec la syntaxe

"extern "C" {
fn SSV_InitLIB2(pcRepSesamIni: *const c_char) -> c_ushort; ..." ,

j'ai ce problème que je n'ai pas de fichier .lib
= note: LINK : fatal error LNK1181: impossible d'ouvrir le fichier en entrée 'C:\ProgramFiles\santesocial\fsv\1.40.14\lib\ssvw64.dll.lib'

d'où l'utilisation de winapi

lorsque je déclare mes accès à la dll avec la syntaxe "extern "C" { fn SSV_InitLIB2(pcRepSesamIni: *const c_char) -> c_ushort; ..." , j'ai ce problème que je n'ai pas de fichier .lib = note: LINK : fatal error LNK1181: impossible d'ouvrir le fichier en entrée 'C:\ProgramFiles\santesocial\fsv\1.40.14\lib\ssvw64.dll.lib' d'où l'utilisation de winapi
Review

Est ce que tu as bien suivi les étapes du README de l'exemple ?

Car y'a des chemins à définir dans le path, et des chemins en fichier de config utilisés par le compilateur

Est ce que tu as bien suivi les étapes du README de l'exemple ? Car y'a des chemins à définir dans le path, et des chemins en fichier de config utilisés par le compilateur

94
clego/src/CPS.rs Normal file
View File

@ -0,0 +1,94 @@
pub fn decode_zone_memoire( ZDonneesSortie: *mut std::ffi::c_void,TTailleDonneesSortie: usize){
println!("Taille sortie SSV_LireCartePS : {}", TTailleDonneesSortie);
println!("ZDonneesSortie: {:?}", ZDonneesSortie);
// Convertir le pointeur en tranche de bytes
let bytes: &[u8] = unsafe {
std::slice::from_raw_parts(ZDonneesSortie as *const u8, TTailleDonneesSortie)
};
// Maintenant, vous pouvez accéder aux octets individuels dans `donnees`
for &octet in bytes {
println!("Octet: {}", octet);
}
let mut current_pos_general = 0;
let mut current_groupe = 0;
let mut num_champ = 0;
while current_pos_general < bytes.len() - 1 {
num_champ = 0;
current_groupe = 256 * bytes[current_pos_general] as i32 + bytes[current_pos_general + 1] as i32;
Review

Je te conseille de sortir tous les bouts de codes "un peu compliqué", comme cette ligne par exemple, dans des fonctions, pour gagner en lisibilité :

Par exemple :

fn compute_current_group(bytes: &[u8], position: usize) -> i32 {
    256 * bytes[position] as i32 + bytes[position + 1] as i32
}

pub fn decode_zone_memoire( ZDonneesSortie: *mut std::ffi::c_void,TTailleDonneesSortie: usize){
// ...
    while current_pos_general < bytes.len() - 1 {
        num_champ = 0;
        current_groupe = compute_current_group(bytes, current_pos_general);
// ...
Je te conseille de sortir tous les bouts de codes "un peu compliqué", comme cette ligne par exemple, dans des fonctions, pour gagner en lisibilité : Par exemple : ``` fn compute_current_group(bytes: &[u8], position: usize) -> i32 { 256 * bytes[position] as i32 + bytes[position + 1] as i32 } pub fn decode_zone_memoire( ZDonneesSortie: *mut std::ffi::c_void,TTailleDonneesSortie: usize){ // ... while current_pos_general < bytes.len() - 1 { num_champ = 0; current_groupe = compute_current_group(bytes, current_pos_general); // ... ```
Review

ça m'est égal, il me parait un peu too much de faire des fonctions pour remplacer une ligne de code

ça m'est égal, il me parait un peu too much de faire des fonctions pour remplacer une ligne de code
Review

L'enjeu, c'est d'avoir une bonne lisibilité du code, à long terme, pour l'ensemble des dev.

Donc ça peut s'obtenir autrement que par le découpage ; à minima par des commentaires

Mais ici, je crois qu'on gagnerait à découper certaines fonctions, car on pourrait leur mettre des tests unitaires et car on aura sans doute besoin y nouveau de décalage de bits?

L'enjeu, c'est d'avoir une bonne lisibilité du code, à long terme, pour l'ensemble des dev. Donc ça peut s'obtenir autrement que par le découpage ; à minima par des commentaires Mais ici, je crois qu'on gagnerait à découper certaines fonctions, car on pourrait leur mettre des tests unitaires et car on aura sans doute besoin y nouveau de décalage de bits?
Review

oui je crois des commentaires pourrait suffire dans ce cas,
C'est une traduction du code VB.Net bien aidé par l'IA, d'où l'absence de commentaire.

Je ferai le nécessaire pour rendre le code lisible. J'ai plutôt pour habitude de copier coller des parties de code lorsque c'est juste quelques fois,
Pour info, lorsqu'on aura programmer les quelques décodage de zone mémoire nécessaires, je garanti qu'on n'y reviendra pas.

oui je crois des commentaires pourrait suffire dans ce cas, C'est une traduction du code VB.Net bien aidé par l'IA, d'où l'absence de commentaire. Je ferai le nécessaire pour rendre le code lisible. J'ai plutôt pour habitude de copier coller des parties de code lorsque c'est juste quelques fois, Pour info, lorsqu'on aura programmer les quelques décodage de zone mémoire nécessaires, je garanti qu'on n'y reviendra pas.
Review
  • Améliorer la lisibilité du code
- [ ] Améliorer la lisibilité du code
current_pos_general += 2;
let longueur_groupe: usize;
if bytes[current_pos_general] < 128 {
longueur_groupe = bytes[current_pos_general] as usize;
} else {
let nbre_octets_longueur = bytes[current_pos_general] - 128;
longueur_groupe = (0..nbre_octets_longueur)
.fold(0, |acc, i| {
current_pos_general += 1;
acc + (256_i32.pow(i as u32) * bytes[current_pos_general] as i32) as usize
});
}
Review

Idem ici, on peut extraire tout ce bloc dans une fonction dédiée, pour clarifier le code :

/// Calcule la longueur du groupe à partir de la position actuelle dans la tranche de bytes.
///
/// Arguments:
/// * `bytes`: La tranche de bytes à analyser.
/// * `current_pos_general`: La position actuelle dans la tranche de bytes.
///
/// Retourne:
/// * La longueur du groupe calculée.
/// * La nouvelle position actuelle après calcul.
fn calculer_longueur_groupe(bytes: &[u8], mut current_pos_general: usize) -> (usize, usize) {
    let longueur_groupe: usize;
    if bytes[current_pos_general] < 128 {
        longueur_groupe = bytes[current_pos_general] as usize;
    } else {
        let nbre_octets_longueur = bytes[current_pos_general] - 128;
        longueur_groupe = (0..nbre_octets_longueur).fold(0, |acc, i| {
            current_pos_general += 1;
            acc + (256_i32.pow(i as u32) * bytes[current_pos_general] as i32) as usize
        });
    }
    current_pos_general += 1;
    (longueur_groupe, current_pos_general)
}
let (longueur_groupe, nouvelle_position) = calculer_longueur_groupe(&bytes, current_pos_general);
current_pos_general = nouvelle_position;
Idem ici, on peut extraire tout ce bloc dans une fonction dédiée, pour clarifier le code : ``` /// Calcule la longueur du groupe à partir de la position actuelle dans la tranche de bytes. /// /// Arguments: /// * `bytes`: La tranche de bytes à analyser. /// * `current_pos_general`: La position actuelle dans la tranche de bytes. /// /// Retourne: /// * La longueur du groupe calculée. /// * La nouvelle position actuelle après calcul. fn calculer_longueur_groupe(bytes: &[u8], mut current_pos_general: usize) -> (usize, usize) { let longueur_groupe: usize; if bytes[current_pos_general] < 128 { longueur_groupe = bytes[current_pos_general] as usize; } else { let nbre_octets_longueur = bytes[current_pos_general] - 128; longueur_groupe = (0..nbre_octets_longueur).fold(0, |acc, i| { current_pos_general += 1; acc + (256_i32.pow(i as u32) * bytes[current_pos_general] as i32) as usize }); } current_pos_general += 1; (longueur_groupe, current_pos_general) } ``` ``` let (longueur_groupe, nouvelle_position) = calculer_longueur_groupe(&bytes, current_pos_general); current_pos_general = nouvelle_position; ```
current_pos_general += 1;
let mut current_pos_groupe = 0;
while current_pos_groupe < longueur_groupe {
num_champ += 1;
let longueur_champs: usize;
let nbre_octets_longueur: usize;
if bytes[current_pos_general] < 128 {
longueur_champs = bytes[current_pos_general] as usize;
nbre_octets_longueur = 1;
} else {
nbre_octets_longueur = bytes[current_pos_general] as usize - 128;
longueur_champs = (0..nbre_octets_longueur)
.fold(0, |acc, i| {
current_pos_general += 1;
current_pos_groupe += 1;
acc + (256_i32.pow(i as u32) * bytes[current_pos_general] as i32) as usize
});
}
let mut bytes_champ = vec![0; longueur_champs];
if longueur_champs > 0 {
bytes_champ.copy_from_slice(&bytes[current_pos_general + nbre_octets_longueur..current_pos_general + nbre_octets_longueur + longueur_champs]);
match current_groupe {
1 => match num_champ {
1 => println!("Groupe1.Champ1: {}", String::from_utf8_lossy(&bytes_champ)),
2 => println!("Groupe1.Champ2: {}", String::from_utf8_lossy(&bytes_champ)),
3 => println!("Groupe1.Champ3: {}", String::from_utf8_lossy(&bytes_champ)),
4 => println!("Groupe1.Champ4: {}", String::from_utf8_lossy(&bytes_champ)),
5 => println!("Groupe1.Champ5: {}", String::from_utf8_lossy(&bytes_champ)),
6 => println!("Groupe1.Champ6: {}", String::from_utf8_lossy(&bytes_champ)),
7 => println!("Groupe1.Champ7: {}", String::from_utf8_lossy(&bytes_champ)),
8 => println!("Groupe1.Champ8: {}", String::from_utf8_lossy(&bytes_champ)),
_ => (),
Review

Et l'idéal, ici, serait de stocker ces valeurs dans une structure appropriée, en nommant + explicitement les champs, et éventuellement en les typant de manière + appropriée que juste un String ?

struct Groupe1 {
    champ1: String,
    champ2: String,
    champ3: String,
    champ4: String,
    champ5: String,
    champ6: String,
    Prenom: String,
    champ8: String,
}
Et l'idéal, ici, serait de stocker ces valeurs dans une structure appropriée, en nommant + explicitement les champs, et éventuellement en les typant de manière + appropriée que juste un String ? ``` struct Groupe1 { champ1: String, champ2: String, champ3: String, champ4: String, champ5: String, champ6: String, Prenom: String, champ8: String, } ```
Review

des que tu es dispo je te montrerai ce que j'avais fait en vb.
J'avais déclaré des classes avec des properties qui permettaient de bien "jouer" avec tous les éléments. (et même d'avoir des displayName)
exemple pour une date
Public Property Champ1 As String (Date mise au format « AAAAMMJJ0000)
Public Property Date_de_début_droits_AMO As Nullable(Of Date)

le set de l'un fixe la valeur de l'autre

(et c'est là que Rust qui ne gère pas les classes me parait limite, pour une programmation orientée objet la gestion de classes serait à mon sens bien plus importante que la gestion optimale de la mémoire dont on ne manquera pas, alors certes on trouvera des solutions avec des struct et des impl et des trait, mais quelle galère.... )

des que tu es dispo je te montrerai ce que j'avais fait en vb. J'avais déclaré des classes avec des properties qui permettaient de bien "jouer" avec tous les éléments. (et même d'avoir des displayName) exemple pour une date Public Property Champ1 As String (Date mise au format « AAAAMMJJ0000) Public Property Date_de_début_droits_AMO As Nullable(Of Date) le set de l'un fixe la valeur de l'autre (et c'est là que Rust qui ne gère pas les classes me parait limite, pour une programmation orientée objet la gestion de classes serait à mon sens bien plus importante que la gestion optimale de la mémoire dont on ne manquera pas, alors certes on trouvera des solutions avec des struct et des impl et des trait, mais quelle galère.... )
Review

Pas de soucis pour faire ce genre de chose en Rust, car on peut faire des choses de type Programmation objet

Dans la doc & formation Rust c'est les concepts de Structure, de Templates et de Traits

On peut se faire une session de pair programming pour implémenter ça :)

Pas de soucis pour faire ce genre de chose en Rust, car on peut faire des choses de type Programmation objet Dans la doc & formation Rust c'est les concepts de Structure, de Templates et de Traits On peut se faire une session de pair programming pour implémenter ça :)
Review

j'aurais bien besoin d'une session formation sur l'environnement de dev qui est bien plus compliqué que ce que j'ai l'habitude de mettre en place.
par exemple là, je ne sais pas tester wip-debug-libc...

Pour les concepts de Structure, de Templates et de Traits, je crois que je devrais m'en sortir quand on se sera mis d'accord sur la méthode. On pourrait commencer ensemble pour que je sois sûr que je vais dans la bonne direction et je voudrais bien voire avec toi si tu valides les concepts que j'avais mis en place dans ma programmation .Net

Donc pour se faire, on pourrait se faire du pair programming des que tu es dispo
(mais si besoin je pourrais aussi me déplacer d'ici dix à quinze jours)

j'aurais bien besoin d'une session formation sur l'environnement de dev qui est bien plus compliqué que ce que j'ai l'habitude de mettre en place. par exemple là, je ne sais pas tester wip-debug-libc... Pour les concepts de Structure, de Templates et de Traits, je crois que je devrais m'en sortir quand on se sera mis d'accord sur la méthode. On pourrait commencer ensemble pour que je sois sûr que je vais dans la bonne direction et je voudrais bien voire avec toi si tu valides les concepts que j'avais mis en place dans ma programmation .Net Donc pour se faire, on pourrait se faire du pair programming des que tu es dispo (mais si besoin je pourrais aussi me déplacer d'ici dix à quinze jours)
Review

Ça roule ; par contre, possible que j'ai pas trop de temps avant la semaine prochaine

  • Faire une session de pair programming sur la structuration des données CPS
Ça roule ; par contre, possible que j'ai pas trop de temps avant la semaine prochaine - [ ] Faire une session de pair programming sur la structuration des données CPS
},
2 => match num_champ {
1 => {
// Ajoutez votre logique pour Groupe2 ici
}
2 => {
// Ajoutez votre logique pour Groupe2 ici
}
3 => {
// Ajoutez votre logique pour Groupe2 ici
}
_ => (),
},
_ => (),
}
}
current_pos_general += longueur_champs + nbre_octets_longueur;
current_pos_groupe += longueur_champs + nbre_octets_longueur;
}
}
}

35
clego/src/INSi.rs Normal file
View File

@ -0,0 +1,35 @@
// use std::ffi::CString;
Review
  • Ne pas inclure ce fichier dans la PR
- [ ] Ne pas inclure ce fichier dans la PR
// use std::ptr::null_mut;
// use winapi::um::libloaderapi::{LoadLibraryA, GetProcAddress, FreeLibrary};
// use winapi::shared::minwindef::HMODULE;
// // use winapi::shared::winerror::ERROR_SUCCESS;
// // use winapi::um::errhandlingapi::GetLastError;
// use winapi::um::winnt::LPCSTR;
// use std::os::raw::c_void;
// pub fn test() {
// unsafe {
// let dll_path = CString::new("F:/PAPILLON/Sources/CLEGO/CLEGO/bin/Debug/CLEGO.dll").expect("Échec de la création de CString");
// let dll_handle: HMODULE = LoadLibraryA(dll_path.as_ptr());
// if dll_handle.is_null() {
// //let error_code = GetLastError();
// println!("Erreur lors du chargement de la DLL.");// Code d'erreur : {}", error_code);
// return;
// }
// let class_name = CString::new("PS_Class").expect("Échec de la création de CString");
// let class_ptr: *mut c_void = GetProcAddress(dll_handle, class_name.as_ptr()) as *mut c_void;
// if class_ptr.is_null() {
// // let error_code = GetLastError();
// println!("Classe non trouvée.");// Code d'erreur : {}", error_code);
// FreeLibrary(dll_handle);
// return;
// }
// // Convertissez class_ptr en une instance de classe Rust et appelez ses méthodes ici
// FreeLibrary(dll_handle);
// }
// }

68
clego/src/SV_DLL_Win.rs Normal file
View File

@ -0,0 +1,68 @@
extern crate winapi;
use winapi::um::libloaderapi::{ LoadLibraryA, GetProcAddress};
use std::ffi::{CString , c_void};
// Définissez une énumération pour les deux types possibles
//récupérer le handle sur la library
pub fn load_library(dll_path: &str)->*mut winapi::shared::minwindef::HINSTANCE__ {
let dll_path_c = CString::new(dll_path).expect("Chemin de DLL invalide");
unsafe {
let h_module = LoadLibraryA(dll_path_c.as_ptr());
h_module
}
}
//SSV_INITLIB2
pub fn ssv_initlib2(dll_handle:*mut winapi::shared::minwindef::HINSTANCE__ , sesamini_path :&str)->i32{
// Résolution d'une fonction exportée ("SSV_InitLIB2")
let symbol_name = CString::new("SSV_InitLIB2").expect("Nom de symbole invalide");
unsafe {
let function_ptr = GetProcAddress(dll_handle, symbol_name.as_ptr());
if function_ptr.is_null() { panic!("Échec de la résolution du symbole");}
// Convertir le pointeur en une fonction Rust
type MyFunctionType = unsafe extern "C" fn(*const i8) -> i32;
let my_function: MyFunctionType = std::mem::transmute(function_ptr);
let result = my_function(
CString::new(sesamini_path).unwrap().as_ptr()
);
result
}}
//SSV_LireCartePS
pub fn ssv_lirecarteps(dll_handle:*mut winapi::shared::minwindef::HINSTANCE__ , NomRessourcePS :&str , NomRessourceLecteur :&str , CodePorteurPS :&str,
ZDonneesSortie: &mut *mut c_void , TTailleDonneesSortie: &mut usize)->i32{// mut ZDonneesSortie: *mut c_void , mut TTailleDonneesSortie: usize)->i32{
// Résolution d'une fonction exportée ("SSV_LireCartePS")
let symbol_name = CString::new("SSV_LireCartePS").expect("Nom de symbole invalide");
unsafe {
let function_ptr = GetProcAddress(dll_handle, symbol_name.as_ptr());
if function_ptr.is_null() {
panic!("Échec de la résolution du symbole");
}
// Convertir le pointeur en une fonction Rust
type MyFunctionType = unsafe extern "C" fn(*const i8, *const i8, *const i8, *mut *mut c_void, *mut usize) -> i32;
let my_function: MyFunctionType = std::mem::transmute(function_ptr);
// appel de la fonction
//*ZDonneesSortie= std::ptr::null_mut();//ZDonneesSortie= std::ptr::null_mut();
*TTailleDonneesSortie=0;
println!("ZDonneesSortie: {:?}", ZDonneesSortie);
let result = my_function(CString::new(NomRessourcePS).unwrap().as_ptr(),
CString::new(NomRessourceLecteur).unwrap().as_ptr(),
CString::new(CodePorteurPS).unwrap().as_ptr(),
ZDonneesSortie, TTailleDonneesSortie);
// &mut TTailleDonneesSortie);
println!("ZDonneesSortie: {:?}", ZDonneesSortie);
result
}
}

View File

@ -1,3 +1,27 @@
mod SV_DLL_Win;
mod INSi;
mod CPS;
fn main() {
println!("Hello, world!");
// INSi::test;
let my_handle = SV_DLL_Win::load_library("C:/Program Files/santesocial/fsv/1.40.14/lib/ssvw64.dll");
if my_handle.is_null() {
panic!("Échec du chargement de la DLL");
}
let result_ssv_initlib2=SV_DLL_Win::ssv_initlib2(my_handle,"C:/CLEGO_Files/SanteSociale/sesam.ini");
println!("Résultat SSV_InitLIB2 : {}", result_ssv_initlib2);
let mut ZDonneesSortie: *mut std::ffi::c_void= std::ptr::null_mut();
let mut TTailleDonneesSortie: usize=55;
let result_ssv_lirecps = SV_DLL_Win::ssv_lirecarteps(my_handle, "HID Global OMNIKEY 3x21 Smart Card Reader 0","", "1234",
&mut ZDonneesSortie, &mut TTailleDonneesSortie);
println!("Résultat SSV_LireCartePS : {}", result_ssv_lirecps);
println!("Taille sortie SSV_LireCartePS : {}", TTailleDonneesSortie);
println!("ZDonneesSortie: {:?}", ZDonneesSortie);
CPS::decode_zone_memoire(ZDonneesSortie,TTailleDonneesSortie)
Review

Est-ce que tu pourrais fournir, dans un fichier d'exemple, un exemple de ZDonneesSortie et TTailleDonneesSortie ? Comme ça on pourrait travailler sur le code, même sans avoir le lecteur de carte

Est-ce que tu pourrais fournir, dans un fichier d'exemple, un exemple de ZDonneesSortie et TTailleDonneesSortie ? Comme ça on pourrait travailler sur le code, même sans avoir le lecteur de carte
Review

Est-ce que tu peux faire avec ça?
les valeurs sont en decimale

Taille sortie SSV_LireCartePS : 140
ZDonneesSortie: 0x1e75ad4cc40
Octet: 0
Octet: 1
Octet: 51
Octet: 1
Octet: 48
Octet: 1
Octet: 56
Octet: 11
Octet: 57
Octet: 57
Octet: 55
Octet: 48
Octet: 48
Octet: 53
Octet: 50
Octet: 52
Octet: 49
Octet: 57
Octet: 52
Octet: 1
Octet: 52
Octet: 2
Octet: 50
Octet: 50
Octet: 17
Octet: 80
Octet: 72
Octet: 65
Octet: 82
Octet: 77
Octet: 65
Octet: 67
Octet: 73
Octet: 69
Octet: 78
Octet: 48
Octet: 48
Octet: 53
Octet: 50
Octet: 52
Octet: 49
Octet: 57
Octet: 9
Octet: 70
Octet: 82
Octet: 65
Octet: 78
Octet: 67
Octet: 79
Octet: 73
Octet: 83
Octet: 69
Octet: 1
Octet: 84
Octet: 0
Octet: 2
Octet: 83
Octet: 1
Octet: 1
Octet: 1
Octet: 48
Octet: 1
Octet: 49
Octet: 2
Octet: 56
Octet: 54
Octet: 1
Octet: 49
Octet: 9
Octet: 48
Octet: 66
Octet: 48
Octet: 50
Octet: 50
Octet: 49
Octet: 57
Octet: 53
Octet: 56
Octet: 1
Octet: 56
Octet: 24
Octet: 80
Octet: 72
Octet: 65
Octet: 82
Octet: 77
Octet: 65
Octet: 67
Octet: 73
Octet: 69
Octet: 32
Octet: 68
Octet: 85
Octet: 32
Octet: 67
Octet: 69
Octet: 78
Octet: 84
Octet: 82
Octet: 69
Octet: 50
Octet: 50
Octet: 49
Octet: 57
Octet: 53
Octet: 8
Octet: 48
Octet: 48
Octet: 50
Octet: 48
Octet: 50
Octet: 52
Octet: 49
Octet: 57
Octet: 1
Octet: 56
Octet: 0
Octet: 1
Octet: 48
Octet: 1
Octet: 49
Octet: 2
Octet: 53
Octet: 48
Octet: 2
Octet: 49
Octet: 48
Octet: 2
Octet: 48
Octet: 48
Octet: 1
Octet: 48
Octet: 1
Octet: 48
Octet: 1
Octet: 48
Octet: 1
Octet: 49
Octet: 1
Octet: 49

Est-ce que tu peux faire avec ça? les valeurs sont en decimale Taille sortie SSV_LireCartePS : 140 ZDonneesSortie: 0x1e75ad4cc40 Octet: 0 Octet: 1 Octet: 51 Octet: 1 Octet: 48 Octet: 1 Octet: 56 Octet: 11 Octet: 57 Octet: 57 Octet: 55 Octet: 48 Octet: 48 Octet: 53 Octet: 50 Octet: 52 Octet: 49 Octet: 57 Octet: 52 Octet: 1 Octet: 52 Octet: 2 Octet: 50 Octet: 50 Octet: 17 Octet: 80 Octet: 72 Octet: 65 Octet: 82 Octet: 77 Octet: 65 Octet: 67 Octet: 73 Octet: 69 Octet: 78 Octet: 48 Octet: 48 Octet: 53 Octet: 50 Octet: 52 Octet: 49 Octet: 57 Octet: 9 Octet: 70 Octet: 82 Octet: 65 Octet: 78 Octet: 67 Octet: 79 Octet: 73 Octet: 83 Octet: 69 Octet: 1 Octet: 84 Octet: 0 Octet: 2 Octet: 83 Octet: 1 Octet: 1 Octet: 1 Octet: 48 Octet: 1 Octet: 49 Octet: 2 Octet: 56 Octet: 54 Octet: 1 Octet: 49 Octet: 9 Octet: 48 Octet: 66 Octet: 48 Octet: 50 Octet: 50 Octet: 49 Octet: 57 Octet: 53 Octet: 56 Octet: 1 Octet: 56 Octet: 24 Octet: 80 Octet: 72 Octet: 65 Octet: 82 Octet: 77 Octet: 65 Octet: 67 Octet: 73 Octet: 69 Octet: 32 Octet: 68 Octet: 85 Octet: 32 Octet: 67 Octet: 69 Octet: 78 Octet: 84 Octet: 82 Octet: 69 Octet: 50 Octet: 50 Octet: 49 Octet: 57 Octet: 53 Octet: 8 Octet: 48 Octet: 48 Octet: 50 Octet: 48 Octet: 50 Octet: 52 Octet: 49 Octet: 57 Octet: 1 Octet: 56 Octet: 0 Octet: 1 Octet: 48 Octet: 1 Octet: 49 Octet: 2 Octet: 53 Octet: 48 Octet: 2 Octet: 49 Octet: 48 Octet: 2 Octet: 48 Octet: 48 Octet: 1 Octet: 48 Octet: 1 Octet: 48 Octet: 1 Octet: 48 Octet: 1 Octet: 49 Octet: 1 Octet: 49
Review

Oui, ça va le faire :)
Je pousserais un bout de code intégrant ça

  • Intégrer un mock du vecteur d'octets, pour le debug
Oui, ça va le faire :) Je pousserais un bout de code intégrant ça - [ ] Intégrer un mock du vecteur d'octets, pour le debug
}