Une autre Information qui pourrait servir, est de savoir si le Kext a été chargé par le système ou non au démarrage.
En effet, si votre extensions n’est pas chargé, cela peut dire qu’elle a été mal installée ou inutile.
Classes Abordées dans cette partie:
NSTask
NSPipe
NSFileHandle
NSImage
NSBundle
NSData
NSString
NSArray
Pour connaître les extensions chargées, il existe une commande terminal très simple:
kextstat
Si vous souhaitez savoir si une extension en particulier est chargée ou non, il fut indiquer à kextstat l’Identifier du kext, de cette manière:
kextstat -b org.netkas.HPETDevice
Vous pouvez faire le test avec un kext que vous possédez, le résultat devrait s’afficher sous cette forme:
Index Refs Address Size Wired Name (Version) <Linked Against>
34 0 0x46855000 0x2000 0x1000 org.netkas.HPETDevice (1) <13 7 4 3>
Vous allez me dire: et alors, qu’est -ce le terminal à a voir avec Objective-C?
Et bien messieurs, sachez qu’il est possible de lancer ce genre de commande dans Objective-C, grâce à la classe NSTask
Si lancer cette commande est une chose, il faut également être capable de la lire, et d’en traiter les résultats.
Pour cela, nous avons à disposition les classes NSPipe et NSFileHandle, qui respectivement permettent de créer un «tuyau» de communication entre kextstat et notre application, et de lire le résultat de la commande avec votre application.
Voilà , les bases sont posées, voyons maintenant comment nous allons procéder pour communiquer avec kextstat.
Comme vous savez maintenant le faire, il faudra créer une fonction dans MyController.m, et la déclarer dans MyController.h.
Voici la fonction:
- (void) ifLoaded
{
//initialisation
NSTask *kextStat=[[NSTask alloc] init];
NSPipe *pipe=[[NSPipe alloc] init];
// configuration
[kextStat setLaunchPath:@"/usr/sbin/kextstat"];
[kextStat setArguments:[NSArray arrayWithObjects:@"-l", @"-b", self.theIdentifier, nil]];
[kextStat setStandardOutput:pipe];
NSFileHandle *handle = [pipe fileHandleForReading];
[kextStat launch];
// notre code va ici
}
Initialisation:
Comme nous l’avons déjà vu, ici nous créons nos objets, afin de pouvoir les utiliser par la suite.
Configuration:
Ici, nous indiquons 3 choses à NSTask.
1) [kextStat setLaunchPath:@"/usr/sbin/kextstat"];
Le chemin vers l’application kextstat.
2) [kextStat setArguments:[NSArray arrayWithObjects:@"-l", @"-b", self.theIdentifier, nil]];
les arguments qui viennent après kextstat. Ici nous utilisons un Array, dans lequel nous stockons à la suite les instructions à donner à kextstat. Notez qu’un array que vous définissez dans votre code doit toujours se terminer par nil, qui permet de dire que l’Array se termine. Si nous devions écrire ces deux premiers points dans un terminal, cela ressemblerait à ça:
kextstat -l -b identifier-du-kext
Le -l nous permet de supprimer la ligne Index Refs Address..etc pour ne garder que le résultat du kextstat. Vous allez comprendre pourquoi un peu plus loin.
1) [kextStat setStandardOutput:pipe];
Nous disons à NSTask d'utiliser notre «tuyau» pour faire circuler les informations.
2) NSFileHandle *handle = [pipe fileHandleForReading];
Là , nous disons à NSFileHandler de lire les informations qui circulent dans notre tuyau.
3) [kextStat launch];
On exécute notre NSTask
Kextstat ne se préoccupe que des kexts chargés. Si vous lancez kextstat avec un identifier de kext qui n’est pas chargé par le système, alors rien ne s’affiche. Je vous invite à essayer.
Pour les possesseurs d’un carte graphique Nvidia, ceci ne retournera rien (on cherche un pilote ATI):
kextstat -l -b com.apple.kext.ATIFramebuffer
Pour les possesseurs d’une carte graphique ATI (on cherche un pilote Nvidia):
kextstat -l -b com.apple.NVDAResman
Bon, vous devez me voir venir avec mes gros sabots: maintenant que nous savons repérer si un kext est chargé ou non, il ne reste plus qu’à afficher dans notre application «kext chargé» si quelque chose est trouvé, ou «kext non chargé» si rien n’est trouvé.
Pour faire ça, nous allons faire ce que nous savons faire, c’est à dire créer NSString (que l’on nomme kextLoad) que l’on va «binder» à un Text Field dans l’interface.
Vous savez comment faire ça maintenant, alors voici la fonction dans sa totalité:
- (void) ifLoaded
{
//initialisation
NSTask *kextStat=[[NSTask alloc] init];
NSPipe *pipe=[[NSPipe alloc] init];
// configuration
[kextStat setLaunchPath:@"/usr/sbin/kextstat"];
[kextStat setArguments:[NSArray arrayWithObjects:@"-l",@"-b", self.theIdentifier,nil]];
[kextStat setStandardOutput:pipe];
NSFileHandle *handle = [pipe fileHandleForReading];
[kextStat launch];
// on stocke ce qui sort
NSData *outPut = [handle readDataToEndOfFile];
// on affiche selon le résultat
if ([outPut length]<1) {
self.kextLoad = @"kext non chargé";
}
else {
self.kextLoad = @"kext chargé";
}
}
Nous avons deux choses un peu nouvelles ici:
1) NSData *outPut = [handle readDataToEndOfFile];
Le résultat est sous la forme de data, donc on stocke ce résultat dans un NSData pour effectuer notre vérification par la suite
2)if ([outPut length] < 1) {
Nous avons vu qu’avec notre commande, si le kext n’est pas chargé, rien ne s’affiche. Alors nous vérifions avec notre if si outPut contient quelque chose, lenght correspondant aux nombres de données stockés. On utilise le même comparateur que dans la partie 2 du ce tutoriel, qui revient à dire «si la longueur de outPut est inférieure à 1, alors...»
Maintenant il faut appeler cette fonction dans la bonne partie du code de MyController.m
Vous avez deux possiblités:
- soit faire comme avec - (void) getInformations et appeler - (void) ifLoaded aux mêmes endroits,
- soit appeler - (void) ifLoaded directement dans - (void) getInformations
Je penche pour la deuxième solution, car on économise une ligne de code... On l'appellera ici:
self.theCount = [NSString stringWithFormat:@"%i %@", [filenames count], pluriel];
[self ifLoaded];
Voilà , vous n’avez plus qu’a créer votre Text Field dans Interface Builder et e binded avec self.kextload, et compiler pour tester le résultat!
Bon, je ne sais pas pour vous, mais je trouve qu’uniquement du texte, c'est pas très User-Friendly...
Je verrais bien des images qui illustrent le fait qu’un kext soit chargé ou non... alors je vous invite à faire de même :)
récupérez les images en pièces jointes. Se sont celles que j’utilise, mais vous pouvez utiliser celles de votre choix bien sur.
Pour ajouter des images à votre application, faites glissez vos images dans le dossier «Resources» de la fenêtre de votre projet Xcode, et cochez la case «copy items into destination group’s folder» de la boite de dialogue:

Retournez à votre fonction - (void) ifLoaded
Dans «Initialisation», ajoutez deux lignes comme ceci:
//initialisation
NSTask *kextStat=[[NSTask alloc] init];
NSPipe *pipe=[[NSPipe alloc] init];
NSString *loaded = [[NSBundle mainBundle] pathForResource:@"info" ofType:@"png"];
NSString *notLoaded = [[NSBundle mainBundle] pathForResource:@"warning" ofType:@"png"];
On a crée deux strings qui contiennent les chemins vers vos images.
Maintenant, vous devez créer un NSImage qui sera «bindé». La technique est exactement la même que celle utilisé pour les NSString que nous avons fait précédemment, sauf qu’il faut remplacer NSString par NSImage.
il vous faudra donc ces 3 éléments à leurs places respectives:
NSImage *kextState;
@property (copy, nonatomic) NSImage *kextState;
@synthesize kextState;
Toujours dans la fonction - (void) ifLoaded, vous modifiez votre if / else comme ceci:
if ([outPut length]<1) {
self.kextLoad = @"kext non chargé";
self.kextState = [[NSImage alloc] initWithContentsOfFile:notLoaded];
}
else {
self.kextLoad = @"kext chargé";
self.kextState = [[NSImage alloc] initWithContentsOfFile:loaded];
}
Dernière étape, ajouter de quoi afficher l’image dans l’interface.
A partir de la Librarie d’Interface Builder, faites glisser une «Image Well» dans la fenêtre de l’application.
Ensuite, cliquez dessus et configurez l’onglet binding de l’Inspecteur de cette manière:

Voilà , sauvegardez le tout et compilez, votre application est terminée!! Enfin presque...
TP: Faire disparaitre le texte et l’image quand la liste est Vide
Et oui, nous sommes confrontés au même souci que dans la deuxième partie. Mais comme la solution a déjà été donnée, donc je vous laisse trouver tout seul modifier votre code.
Conclusion du Tutoriel:
Voilà , j’espère que vous aurez réussi à faire toutes les parties de ce tutoriel. Sinon, n’hésitez pas à relire plusieurs fois, fouiller un peu dans la documentation, expérimenter... le but n’était pas de vous apprendre Objective--C, mais plutôt de mettre un pied à l'étrier et voir si ça vous plait...
Mais vous avez du faire quand même de sacrés progrès: regardez votre code maintenant, et dite vous qu’avant d’avoir suivit ce tutoriel, tout ceci était du Chinois :)
Ainsi, considérez cette petite application que nous avons fait ensemble comme un point de départ: en effet, vous pouvez y ajouter de nombreuses fonctionnalités, améliorations, comme par exemple créer un indicateur d’activité, afficher si le kext est compatible 64bit, supprimer de la liste les kexts qui ne sont pas chargés, voir installer/ désinstaller des kexts qui se trouvent dans la liste... etc.
Pour ceux qui auront apporté des améliorations, je vous invite les poster, cela pourrait intéresser d’autres personnes, et pourquoi pas au final une application collective verra le jour....
Télécharger les icônes Télécharger le projet| Créer son application Cocoa: 2ème partie |
|---|



Commentaires
C'est le cas par exemple du kext suivant :
/Extra/Extensions/ElliottForceLeg acyRTC.kext
Ce Kext n'apparait pas dans kextstat et est donc considéré comme non chargé par l'application MyosxKexts.
En retirant ce kext du répertoire /Extra/Extensions, je me retrouve de nouveau avec un clear cmos de ma carte mère Gigabyte EP31-DS3L au reboot du système.
J'ai remis le kext /Extra/Extensions/ElliottForceLeg acyRTC.kext et tout fonctionne.
Ce Kext est donc indispensable mais ne reste pas chargé.
Un bonne occasion d'ailleurs de créer une condition pour ce kext pourquoi pas :)
J'ai téléchargé le zip (qui lui fonctionne) et comparé les attributs de la tableview (ainsi que ses descendants) mais je ne vois pas différence.
Si quelqu'un a une idée.
Encore une fois bravo pour ce tutoriel.