Il est souvent intéressant de faire des pauses dans une conception, ça permet de sortir la tête du guidon, et de revenir avec des idées plus claires.
Remarque de casse-couille, DTO, ça veut dire "Data Transfert Objet", donc des objets qui doivent facilement migrer entre les couches d'une application. Le seul moyen simple d'assurer cela est dans faire de simple structure, composer de champs publics dont les types sont des types de "bases".
Donc y ajouter une méthode statique, c'est commencer à faire une entorse au Design Pattern de base.
Il n'est pas interdit d'y faire des entorses, mais il faut évaluer le pour et le contre, et c'est assez souvent un mauvais choix.
Comme vous le suggérez dans votre EDIT, je pense que mettre cette méthode dans la classe Wlan permettrait de ne pas faire d'entorses, et, pour moi, serait plus "naturel" (c'est aussi un avantage des Design Pattern, c'est qu'en les respectant, on n'est plus confortable car les détails de conception sont déjà connus, d'où le "naturel").
2ème remarques à la con, évitez le franglais avec "Wlan" qui est un acronyme anglais et "Reseau" qui est français dans le même code. Ici "Reseau" c'est le "n" de Wlan (network) ou c'est "Wlan" en entier ?
Vous devriez "marquer" le caractère DTO de la classe "Reseau" avec un nom l'indiquant, comme un suffixe, comme "ReseauDTO" (mais je préfèrerais WlanInfos ou WlanParams).
Si vous suivez le DP DTO, il n'est pas forcement pertinent d'utiliser "tout" les champs du DTO pour les appels suivants mais juste un champ "id" ou une "sous-structure" identifiantes. Si l'utilisateur fait le con avec les autres champs du DTO, c'est ces oignons.
Vous suivez l'approche qui est de faire une API qui correspond à vos besoins présents (et avenir si possible) et pas de "mimiquer" celle induite par les composants que vous utiliserez dans les couches basses. Cela permet d'avoir une API plus simple d'utilisation, plus spécialisée à vos besoins et plus facilement portable MAIS plus complexe à implémenter.
Si vous suivez l'approche de "mimiquer" celle induite par les composants que vous utiliserez dans les couches basses, c'est faire un wrapper C++ à l'API C qui vous cherchez à utiliser, vous avez les avantages et inconvénients inverses de l'approche API "originale", mais aussi vous avez une conception offerte sur un plateau. Un avantage bien pratique quand on débute.
>Wlan qui n'a qu'une fonction, son constructeur
C'est un peu limiter comme service rendu pour une classe, mais je pense qu'on pourra facilement y ajouter des services sympas.
>auquel on passe en argument un Reseau
Je serais plus chaud pour un identifiant (champs du DTO) plutôt que tout le DTO.
>Ainsi on à des objets fonctionnels à la sortie du constructeur,
Nickel.
> moins de risque d'erreur dans les arguments car Reseau ne peut être construit "à la main",
C'est encore plus vrai avec un "Identifiant".
Que l'utilisateur de la classe DTO fasse des conneries avec, c'est ses oignons, tant qu'il respect le contrat de ne pas toucher au champ "Identifiant".
>De plus on pourra mettre certaines infos de Reseau en private
Je ne mettrais pas cela dans le DTO mais dans une classe interne à votre librairie, que l'identifiant permet de récupérer dans une map, par exemple.
>Ou Reseau amie de Wlan, dans quel sens le faire ?
Avec des classes internes, vous pouvez être moins regardant sur l'isolation. Si c'est Wlan qui a besoin de regarder le contenu de la classe "Reseau interne", c'est Wlan qui doit être l'ami de "Reseau interne" et pas l'inverse.
>Si ca appartient à Reseau, c'est une classe, sinon c'est une bête structure.
DTO => bête structure
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
> Comme vous le suggérez dans votre EDIT, je pense que mettre cette méthode dans la classe Wlan permettrait de ne pas faire d'entorses, et, pour moi, serait plus "naturel" (c'est aussi un avantage des Design Pattern, c'est qu'en les respectant, on n'est plus confortable car les détails de conception sont déjà connus, d'où le "naturel").
ca me parait bien.
> C'est un peu limiter comme service rendu pour une classe, mais je pense qu'on pourra facilement y ajouter des services sympas.
Enfin une fonction "principale", nécessaire à l'API pour rendre un objet utilisable et faire d'autres actions.
Ensuite je n'ai pas tout compris les trucs de l'identifiant, qu'est-ce que vous appelez un identifiant ? Une clé d'un map ?
Et on passerait cet identifiant en paramètre à Wlan qui en interne utiliserait la fonction getAvilablesNetworks ? (j'ai changé le nom)
Dans ce cas la autant passer directement le nom en paramètre du constructeur de Wlan non ?
"La valeur n'attend point le nombre des années" Le Cid, Pierre Corneille, Don Rodrigue parlant au Comte
>qu'est-ce que vous appelez un identifiant ? Une clé d'un map ?
Par exemple, ou simplement un indice dans un tableau, comme l'est la majorité des "handle" des API C.
Un truc qui identifie de manière unique le réseau. Attention à ne pas forcement prendre des trucs qui ont un sens dans l'API C.
L'utilisateur n'a pas à connaitre l'API C que vous wrappez/cachez.
>Dans ce cas la autant passer directement le nom en paramètre
Si cela identifie de manière unique le "Wlan" et que ce n'est pas un détail d'implémentation de votre librairie ou de l'API C sous-jacente, oui c'est un bon identifiant.
Un SSID n'est pas obligatoire pour un Wifi, je crois, donc SSID est différent du "nom".
Si "nom" a du sens pour l'utilisateur sans avoir à connaitre comment fonctionne précisément le Wifi, oui "nom" est un bon identifiant.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Un SSID est obligatoire il me semble mais pas toujours visible (réseau masqué).
J'y pense mais il faut aussi un moyen d'identifier sur quel carte réseau on veut se connecter !
Pourquoi ne pas créer une autre structure, sous-jacente à Reseau qui contient le SSID, le GUID et éventuellement un nom ou un numéro pour l'identifier sans doutes possibles.
Un code d'exemple serait alors
std::vector<Reseau> reseaux;
reseaux = Wlan::getNetworkInfos();
//affichage des infos
std::cout << "Quel réseau voulez vous choisir ?" << std::endl;
int numéro;
std::cin >> numéro;
std::cout << "Saisissez le mot de passe" << std::endl;
std::string password;
std::cin >> password;
Wlan wlan(reseaux[numéro].connectionInfos, password);
On commence à etre pas mal non ?
"La valeur n'attend point le nombre des années" Le Cid, Pierre Corneille, Don Rodrigue parlant au Comte
exceptionWlan.h (pas forcemement la peine de lire)
#pragma once
#include <Windows.h>
#include <exception>
#include <string>
class ExceptionWlan : public std::runtime_error
{
public:
ExceptionWlan(const char *msg) : std::runtime_error(msg) {};
};
class NetworkNotFound : public ExceptionWlan
{
public:
NetworkNotFound(std::string nomReseau) : ExceptionWlan((std::string("ERREUR : Il n'existe aucun réseau nommé ") + nomReseau + " à proximités.").c_str()) {};
};
class ErrorNotSupported : public ExceptionWlan
{
public:
ErrorNotSupported(std::string function) : ExceptionWlan(std::string("ERREUR : Votre requete dans la fonction " + function + " n'est pas supportée par votre système.").c_str()) {};
};
class ServiceNotActive : public ExceptionWlan
{
public:
ServiceNotActive(std::string function) : ExceptionWlan(std::string("ERREUR : L'AutoConfig Wlan n'est pas activé sur votre système? L'erreur est survenue dans la fonction " + function).c_str()) {};
};
class AccessDenied : public ExceptionWlan
{
public:
AccessDenied(std::string fonction) : ExceptionWlan((std::string("ERREUR : Acces refusé dans la fonction ") + fonction).c_str()) {};
};
class InvalidParameter : public ExceptionWlan
{
public:
InvalidParameter(std::string function) : ExceptionWlan((std::string("ERREUR : Un des arguments passé en paramètre est invalide dans la fonction ") + function).c_str()) {};
};
class RadioTurnedOff : public ExceptionWlan
{
public:
RadioTurnedOff(std::string function) : ExceptionWlan((std::string("ERREUR : La radio est désactivée sur l'interface passée en argument à la fonction ") + function).c_str()) {};
};
class InvalidHandle : public ExceptionWlan
{
public:
InvalidHandle(std::string function) : ExceptionWlan((std::string("ERREUR : Le handle passé en paramètre est invalide dans la fonction ") + function).c_str()) {};
};
class NotEnoughMemory : public ExceptionWlan
{
public:
NotEnoughMemory(std::string function) : ExceptionWlan((std::string("ERREUR : Pas assez de memoire pour appeller la fonction ") + function).c_str()) {};
};
class OtherError : public ExceptionWlan
{
public:
OtherError(std::string function, DWORD error) : ExceptionWlan((std::string("ERREUR : Une erreur inconnue s'est produite dans la fonction ") + function + ". Voici le code d'erreur : " + std::to_string(error)).c_str()) {};
};
Ca fait pas mal de code mais c'en est déjà moins qu'avant et c'est plus lisible et organisé.
Pour l'instant je pointe du doigt le dwFlags j'ai mit le meme qu'avant mais il ne me parait pas bien mais je vois pas lequel mettre.
aussi le pBssList que je contruis à la main avec une autre fonction, bref pour moi c'est un des deux.
Vous aurez noté que j'ouvre plusieurs handle par ils sont parfois "périmés", je ne sais pas pourquoi...
"La valeur n'attend point le nombre des années" Le Cid, Pierre Corneille, Don Rodrigue parlant au Comte
Les ligne 19 à 34 de "wifi.cpp" sont totalement inutiles.
Les lignes 9 et 10 de "wifi.cpp" peuvent être fusionnées.
Les "#pragma comment (lib,...)" bofbof, c'est mieux d'utiliser les propriétés du projet ou les mettre uniquement dans l'en-tête chapeau de votre module (cloisonnement des dépendances).
Il y a beaucoup trop d'include inutiles dans les fichiers d'en-tête. Ils doivent contenir le strict minimum pour qu'ils soient utilisables pour des déclarations, par pour des implémentations. Les en-tête nécessaire à l'implémentation doivent être inclus dans le fichier ".cpp" dans l'implémentation, pas dans le ".h".
Chacune de tes structures doit avoir son propre fichier d'en-tête. Si tu veux les regrouper, utilise un header "chapeau" qui inclus ces fichiers d'en-tête "spécifique" à la classe/structure.
Les types commençant par "_DOT11" sont des types de la bibliothèque que vous utilisez en interne, il serait préférable que l'utilisateur n'y est pas connaissance, ou tout du moins pas accès. Pour qu'il n'en ait pas connaissance, supprimez ces champs des structures "publiques". Pour qu'il n'y en ait pas l'accès, mettrez ces champs en "private" et uniquement "settable" via un constructeur "private" qu'une fonction statique de la structure/classe pourra utiliser (implémentation du Design Pattern "Factory", comme pour la classe "Profile").
"profil.h/cpp" => très rapidement renommer les fichiers pour qu'ils correspondent à la classe qu'ils contiennent (ou mieux, configurer votre IDE pour qu'il le fasse pour vous).
N'utiliser jamais de pointeurs nus dans du code C++ (jusqu'à ce que vous aillez le niveau pour contredire intelligemment ce dogme). Donc pas de paramètre "pointeur nus" pour le constructeur de "Profile".
La seule utilisation de pointeurs nus comme celui dans le constructeur de "Profile" peut largement expliquer les "INVALID_PARAMETER" à répétition que vous vous prenez dans les dents.
Vous ne gérez pas correctement la durée de vie (l'ownership) des variables, et l'utilisation de pointeurs nus dans ce cas est rédhibitoire.
Je vous conseille très chaudement de changer la signature de votre constructeur de la classe "Profile" par :
C'est l'utilisation du concept de "move sémantique" car le "ProfileInfos" que vous passez à ce constructeur n'est plus opérationnel après la constructeur. (ligne 48 de "profil.cpp" invalide l'handle stocké dans le ProfileInfos)
Des classes/structures avec des handle dedans ne devraient pas être "clonable", on parle de classe à sémantique d'"Entité".
Cela implique des contraintes sur la conception de ce type de classes comme pas de constructeur par copie, etc..., je te laisse voir avec notre ami Google les contraintes que tu devrais ajouter à cette classe ProfileInfos.
L'utilisation du "move sémantique" renforce l'usage correct de ce type de classe à sémantique d'"Entité".
Telle que ton implémentation est faites, le constructeur de "Profile" vampirise le ProfileInfos en paramètre, et c'est à cela que sert de "move sémantique" : officialiser cette vampirisation.
Je ne suis pas sûr que votre usage des handles de la librairie sous-jacente soit correct. Souvent, quand on récupère un handle (handle_récupéré) via une API qui demande un handle en entrée (handle_source), le fait de fermer l'handle_source rend inopérant le "handle_récupéré".
Comme les pointeurs nus, jamais de "new" dans du C++.
Votre code de gestion des erreurs / du résultat dans "dwResult" est extrêmement lourde.
Ce code est primordial pour le bon fonctionnement du système, mais il n'apporte rien en terme de "sémantique" de la fonction.
C'est du "bruit" dans le code. On cherche toujours à minimiser ce bruit "visuellement", pour rendre le code bien plus lisible.
Votre manière de faire est très lourde mais aussi très sujette à erreur, car un oubli de copier-coller (pour les cases, les noms de la méthode, etc...) et c'est le drame.
Vous pouvez très facilement factoriser tout ce code.
Lignes 15, 16, 42 à 44 de "Profil.cpp", toujours correctement initialiser les variables et encore plus quand on les passent à une API C système. (ZeroMempry, etc...., je crois qu'on a déjà largement évoqué le problème dans cette même file de message)
La classe Wlan contient un HANDLE, elle a donc une sémantique de classe "Entité", donc même remarque que pour la classe "Profile", la rendre non-clonable, etc...
Ligne 6 de "Wlan.cpp", vous êtes sûr que le passage de paramètres par copie à la place de références constantes se justifie ?
Ligne 8 et 9 de "Wlan.cpp", utilisez plutôt de "{}" que des "()" pour l'initialisation des variables, ça évite des fautes bêtes :
DWORD dwMaxClient{2};
DWORD dwCurVersion{0};
Attention à la génération d'exception dans un constructeur, généralement, il faut utiliser des idiosyncrasies particulières :
Dans tout le fichier "Wlan.cpp", l'initialisation des variables est très mal faites, à revoir complètement.
Dans du code C++, il n'y aucune justification pour faire des casts à la C. Donc supprimez tous ces casts ( ligne 52 "(DOT11_AUTH_ALGORITHM)" etc..., aucun cast de la forme "(T)").
Il y a plusieurs types de cast en C++, utilisez les à bon escient et les "reinterpret_cast" à éviter le plus possible.
Pas de "NULL" en C++, c'est "nullptr".
Ligne 55 de "Wlan.cpp", attention à vérifier la sémantique de l'opérateur "==" entre ces types. Est-ce une égalité sur les pointeurs mémoire ou sur le contenu des "chaines" ? (en attendant l'introduction de l'opérateur "spaceship" '<=>' à la JavaScript, en C++20 normalement).
Ligne 69 de "Wlan.cpp", pourquoi elle n'a pas de gestion d'erreur ??? En utilisant une MACRO et/ou une fonction Lippincott "inverse", ça serait plus visible, ce genre d'oubli.
>//alors ici je suis obligé d'initialiser ici
On n'est toujours obligé d'initialiser, et encore plus quand on interface une API C.
Attention à votre membre "m_handle" de la classe Wlan qui n'est pas toujours valide et même souvent invalide, tout au long du constructeur. Un membre, c'est pas une variable locale++.
C'est le genre de truc qui rend le code imbittable et super-buggué.
Ligne 19 de " la suite de Wlan.cpp", idem à ligne 69 de "Wlan.cpp", soyez rigoureux avec le traitement des erreurs.(Il n'y a pas que ces 2 lignes, revoyez tout le code)
Dans la suite du code, de nombreuses choses qui correspondent à des remarques que j'ai déjà faites.
La MACRO "L" à la ligne 138 de " la suite de Wlan.cpp" me fait remarquer que vous mélangez un peu les types de chaines de caractères, ce qui peut rendre le code difficile à comprendre et à maintenir.
Vous utilisez des primitives qui ne sont pas "marquées" avec un suffixe "A" (pour ASCII) ou "W" (WIDE => UNICODE).
Si ces primitives prennent des chaines de caractères en paramètre, vous deviez utiliser de TCHAR et pas de char ou des std::string.
Donc, quand le type de chaine de caractère n'est pas explicitement indiqué, pensez à utiliser systématiquement des TCHAR/PTSTR/la MACRO TEXT etc...
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
> Les ligne 19 à 34 de "wifi.cpp" sont totalement inutiles.
Les lignes 9 et 10 de "wifi.cpp" peuvent être fusionnées.
Corrigé.
>Les "#pragma comment (lib,...)" bofbof, c'est mieux d'utiliser les propriétés du projet ou les mettre uniquement dans l'en-tête chapeau de votre module (cloisonnement des dépendances).
Je ne comprend pas pourquoi, le chemin vers les libs est dans les propriétés mais sans ca marche pas, l'en tête chapeau j'ai toujours du mal à savoir quoi mettre dedans, toutes nos classes "publiques" c'est ca ?
>Il y a beaucoup trop d'include inutiles dans les fichiers d'en-tête. Ils doivent contenir le strict minimum pour qu'ils soient utilisables pour des déclarations, par pour des implémentations. Les en-tête nécessaire à l'implémentation doivent être inclus dans le fichier ".cpp" dans l'implémentation, pas dans le ".h".
Chacune de tes structures doit avoir son propre fichier d'en-tête. Si tu veux les regrouper, utilise un header "chapeau" qui inclus ces fichiers d'en-tête "spécifique" à la classe/structure.
Ok j'ai corrigé, j'ai mis les #pragma comment(lib,..) dedans en plus.
>Les types commençant par "_DOT11" sont des types de la bibliothèque que vous utilisez en interne, il serait préférable que l'utilisateur n'y est pas connaissance, ou tout du moins pas accès. Pour qu'il n'en ait pas connaissance, supprimez ces champs des structures "publiques". Pour qu'il n'y en ait pas l'accès, mettrez ces champs en "private" et uniquement "settable" via un constructeur "private" qu'une fonction statique de la structure/classe pourra utiliser (implémentation du Design Pattern "Factory", comme pour la classe "Profile").
Vu que l'utilisateur doit y avoir acces je peux aussi faire un
typedef _DOT11_CIPHER_ALGORITHM CipherAlgo;
et changer dans la definition de mes structures, qu'en pensez vous ?
>"profil.h/cpp" => très rapidement renommer les fichiers pour qu'ils correspondent à la classe qu'ils contiennent (ou mieux, configurer votre IDE pour qu'il le fasse pour vous).
Rajouter le "e" ? fait !
Pour les pointeurs nus je fais comment du coup ?
Je dois passer une valeur null à certains arguments vu que je les recupère après.
> Vous ne gérez pas correctement la durée de vie (l'ownership) des variables, et l'utilisation de pointeurs nus dans ce cas est rédhibitoire.
Ah bon ? Que dois-je faire en plus ?
Je change la signature de profile.
Je me suis renseigné sur les classes à sémantique d'Entité et je me suis posé une question, doit elle etre swappable ?
Je n'y vois pas inconvénient, je dois juste mettre un constructeur privé avec notre méthode avec unique_ptr, un constructeur de copie privé et un opérateur = privé.
>Telle que ton implémentation est faites, le constructeur de "Profile" vampirise le ProfileInfos en paramètre, et c'est à cela que sert de "move sémantique" : officialiser cette vampirisation.
Vampirise ? C'est à dire ?
> Je ne suis pas sûr que votre usage des handles de la librairie sous-jacente soit correct. Souvent, quand on récupère un handle (handle_récupéré) via une API qui demande un handle en entrée (handle_source), le fait de fermer l'handle_source rend inopérant le "handle_récupéré".
Là j'ai pas compris, en théorie je suis censé avoir un seul handle, mais quand vous dites "handle", on parle bien d'une variable de type handle ?
J'aime bien la technique du Lippincott, couplé avec la macro SUCCESS, c'est vrai que c'est bien mieux et léger.
>Ligne 6 de "Wlan.cpp", vous êtes sûr que le passage de paramètres par copie à la place de références constantes se justifie ?
Absolument pas !
>Ligne 8 et 9 de "Wlan.cpp", utilisez plutôt de "{}" que des "()" pour l'initialisation des variables, ça évite des fautes bêtes
Ok, je le fais partout ?
> Attention à la génération d'exception dans un constructeur, généralement, il faut utiliser des idiosyncrasies particulières :
J'a lu le lien et me suis renseigné mais ca s'applique au constructeur par copie ça non ?
> Dans tout le fichier "Wlan.cpp", l'initialisation des variables est très mal faites, à revoir complètement.
Je rajoute des ZeroMemory et essaye de faire des aggrgate initializations, c'est bien ce qu'il faut faire ?
>Dans du code C++, il n'y aucune justification pour faire des casts à la C. Donc supprimez tous ces casts ( ligne 52 "(DOT11_AUTH_ALGORITHM)" etc..., aucun cast de la forme "(T)").
Il y a plusieurs types de cast en C++, utilisez les à bon escient et les "reinterpret_cast" à éviter le plus possible.
Oui mais que faire pour faire passer nullptr en DOT11_AUTH_ALGORITHM ? Je suppose que je dois pas le faire
>Ligne 55 de "Wlan.cpp", attention à vérifier la sémantique de l'opérateur "==" entre ces types. Est-ce une égalité sur les pointeurs mémoire ou sur le contenu des "chaines" ? (en attendant l'introduction de l'opérateur "spaceship" '<=>' à la JavaScript, en C++20 normalement).
C'est censé comparer les valeurs mais ca m'tonnerais pas que il y ai une merde sur cette ligne
> Ligne 69 de "Wlan.cpp", pourquoi elle n'a pas de gestion d'erreur ??? En utilisant une MACRO et/ou une fonction Lippincott "inverse", ça serait plus visible, ce genre d'oubli.
Ah oui, en effet, je vais ajouter ma fonction de suite.
> Attention à votre membre "m_handle" de la classe Wlan qui n'est pas toujours valide et même souvent invalide, tout au long du constructeur. Un membre, c'est pas une variable locale++.
justement je ne comprend pas pourquoi c'est pas valide, j'ai cru voir une réponse plus haut mais je n'ai pas compris (c'est écrit)
> Ligne 19 de " la suite de Wlan.cpp", idem à ligne 69 de "Wlan.cpp", soyez rigoureux avec le traitement des erreurs.(Il n'y a pas que ces 2 lignes, revoyez tout le code)
En effet, je vais y ajouter ma petite gestion des erreurs.
Pour la suite :
Je dois donc utiliser uniquement des TCHAR par exemple ? Des fois je n'ai pas le choix, il est imposé par l'API.
J'enverrais mon code un peu plus tard (dès que j'aurais fini de le retoucher, d'ou l'abscence de réponse à certains de vos commentaires, je le fais).
"La valeur n'attend point le nombre des années" Le Cid, Pierre Corneille, Don Rodrigue parlant au Comte
>Je ne comprend pas pourquoi, le chemin vers les libs est dans les propriétés mais sans ca marche pas,
Vraisemblablement dans la mauvaise "propriété" alors.
C'est toujours mieux que l'utilisateur puisse indiquer où sont les lib plutôt que de l'obliger à les copier à un endroit qu'il ne lui convient pas forcement.
> l'en tête chapeau j'ai toujours du mal à savoir quoi mettre dedans, toutes nos classes "publiques" c'est ca ?
Si par "mettre dedans", tu veux dire un "#include" des .h associés à ces classes, oui alors.
Avec un en-tête chapeau, l'utilisateur l'inclus et il n'a pas à se prendre la tête comment sont organisés les fichiers d'en-tête de la librairie qu'il veut utiliser. Les "#pragma comment (lib,...)" dans ce type d'en-tête, ça permet d'indiquer clairement à celui qui veut recompiler qu'il doit faire le nécessaire pour que l'éditeur de lien les choppent.
>Ok j'ai corrigé, j'ai mis les #pragma comment(lib,..) dedans en plus.
Pour en faire un vrai chapeau, il reste à inclure les .h des classes publiques (et aussi supprimer les "#pragma comment(lib,..)" en corrigeant les paramètres du projet).
>Vu que l'utilisateur doit y avoir acces je peux aussi faire un
Pourquoi l'utilisateur doit-il y avoir accès ?
Vous devez encapsuler la couche C car l'utilisateur ne devrait pas la connaitre. En plus, c'est une structure C bien pérave. S'il à besoin des informations contenues dans cette structure, wrappez la dans un "vrai" objet C++, pratique et facile d'utilisation (rendre facile la bonne utilisation et difficile la mauvaise utilisation).
>et changer dans la definition de mes structures, qu'en pensez vous ?
Changez la définition de vos structures pour qu'elles contiennent des objets faciles d'utilisation.(ou pas d'objet si ça sert à rien).
>Pour les pointeurs nus je fais comment du coup ?
C'est fonction de ce que l'on veut faire. C'est pour ça que les pointeurs nus c'est pourri, ça fait tout, très très mal.
>Je dois passer une valeur null à certains arguments vu que je les recupère après.
Pourquoi ?
Il suffit que cela soit la valeur de retour ou un composant de la valeur de retour.
Avec ce type de pointeur en paramètre, c'est qui qui est en charge de libérer le machin de pointeur nus ?
etc...
Analysez l'usage et vous tomberez quasi systématiquement sur un truc mieux que le pointeur nu.
>Ah bon ? Que dois-je faire en plus ?
Pourquoi en plus ? Il faut juste prendre le bon outil en fonction de votre intention.
> doit elle etre swappable ?
Qu'entendez-vous par "swappable" ???
>Vampirise ? C'est à dire ?
Quand vous utilisez le "move sémantique", l'objet en paramètre est considéré par l'appelant comme "perdu" et vous ne devez pas vous en servir dans le code après l'appel. Quand on implémente une méthode qui prend en paramètre un "T&&", mais qu'on veut garder les données qu'il contient, on ne copie par ses champs, on transfère la propriété (l'ownership) de ses champs vers un autre objet. Comme l'objet appelant a perdu la propriété de ses champs, c'est comme si le code de la méthode l'avait vampirisé car il ne possède plus la propriété des champs qu'il avait en entré de la méthode.
>Là j'ai pas compris, en théorie je suis censé avoir un seul handle
Alors qu'en théorie, parce que des handles, vous en créez un peu partout dans votre code. Il faut être consciencieux avec ce type d'objet.
>mais quand vous dites "handle", on parle bien d'une variable de type handle ?
"variable", ça veut rien dire ou tout dire. J'espère que je n'utilise pas ce terme.
Si je parle de "handle" (donc en minuscule), c'est que je parle de l'identifiant, qui lui est mis à toutes les sauces dans votre code : variable locale, champ d'une classe, etc... . Si je parle du type c'est HANDLE, le C++ est case sensitive.
>Absolument pas !
Alors utilisez le type de passage de paramètre qu'il convient, il ne faut pas en prendre un au pif.
>Ok, je le fais partout ?
Vaut mieux, oui.
>J'a lu le lien et me suis renseigné mais ca s'applique au constructeur par copie ça non ?
Non, à tout type de constructeur.
>Je rajoute des ZeroMemory et essaye de faire des aggrgate initializations, c'est bien ce qu'il faut faire ?
Oui, mais attention aux "aggrgate initializations" qui peuvent ne pas remplir correctement les structures C.
>Oui mais que faire pour faire passer nullptr en DOT11_AUTH_ALGORITHM ?
Bin non, "DOT11_AUTH_ALGORITHM" est un enum, pas un pointeur, et votre cast ne fait que mettre un "NULL" donc un "0" dans cet enum. Vous avez donc forcé une valeur interdite, 0, dans un champ de type "DOT11_AUTH_ALGORITHM" qui ne devrait pas accepter. Vous avez donc bien défoncé toute la structure avec des données complètement au zef, c'est tout le pouvoir des cast à la C, foutre le bordel sans s'en rendre compte. Comme je ne vois pas l'utilité de mettre le champ "authAlgo" dans cette structure, je ne peux vous conseiller une méthode, mais clairement, foutre de force un 0/NULL dedans, ça sent mauvais.
>C'est censé comparer les valeurs mais ca m'tonnerais pas que il y ai une merde sur cette ligne
Vous devez savoir ce que doit faire les méthodes/opérateurs que vous utilisez, sinon c'est la fin des haricots.
>justement je ne comprend pas pourquoi c'est pas valide
Ligne 56 de 'la suite de Wlan.cpp", vous pensez qu'il est dans quel état m_handle après un appel à "WlanCloseHandle" ?
>Je dois donc utiliser uniquement des TCHAR par exemple ?
TCHAR quand le type de chaine de caractère n'est pas spécifié.
>Des fois je n'ai pas le choix, il est imposé par l'API.
Alors utilisez le type de chaine de caractère imposé, mais uniquement dans le cadre de l'API et de manière explicite et systématique.
Mais assez rare qu'une API impose un type de chaine de caractère.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
Mais du coup il me signale que std::make_unique essaye d’accéder à un membre privé (ici mon constructeur) donc il faudrait que std::make_unique soit amie avec Profile mais je n'arrive pas à le faire.
Je vous conseille de créer un nouveau sujet sur ce problème précis, car vous êtes tombé dans un "trou" de Visual C++.
Avec un nouveau sujet, vous aurez des personnes successibles de vous répondre sur ce problème précis d'implémentation du DP Factory en C++. Moi, je n'ai que des solutions que j'estime être du bricolage. Personne ne continue à lire un thread de message de plusieurs centaines de message autre que ceux qui "dialoguent".
Avec des personnes plus au fait des template C++ comme @jo_link_noir, sur ce forum, vous êtes sûr d'avoir une réponse "state of the art".
Sur le papier, vous n'êtes pas obligé de "friendliser" le template mais juste sa spécialisation :
Mais VS semble toujours avoir un problème avec l'instantiation des templates dans ce cas d'usage.
Il n'y a toujours des solutions à base new ou l'usage d'un namespace pour contourner ces problèmes d'instanciation mais je vous invite chaudement à poser la question sur le forum pour avoir l'avis des "spécialistes".
Courage.
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.