Ouvrir une application depuis une autre, puis lui adresser des instances d'objets

Bonjour,



Je pense que c'est tout bête, mais je ne trouve pas.



Mon idée serait :

- je lance une application depuis une autre avec
<br />
[[NSWorkspace sharedWorkspace] launchApplication:@&quot;MonAppli.app&quot;];<br />




- puis je lui envoie des instances d'objet déjà  créés

(une instance d'un plug AudioUnit et un entier "int" en l'occurrence, mais peu importe, des objets)



Quelque chose sur le modèle
<br />
- (BOOL)application:(NSApplication *)application openFile:(NSString *)filename<br />




Ce doit être évident mais les notifications sont internes à  l'application et je ne trouve rien d'autre dans la doc.



(J'ai besoin de conserver la méthode
<br />
- (BOOL)application:(NSApplication *)application openFile:(NSString *)filename<br />


en l'état...)

Réponses

  • AliGatorAliGator Membre, Modérateur
    Tu maitrises l'autre application (celle à  qui tu veux envoyer des données) ? C'est toi qui fait son code aussi ?

    Si oui, tu peux regarder du côté des Distributed Objects (Programming Guide ici)

    Si non, tu peux regarder du côté d'AppleScript pour piloter une application tierce.
  • Dans le cas d'application maitrisé des deux coté, le défaut des objet distribué c'est qu'ils restent exécuté par l'application source, du RPC objet en somme... Si ce n'est pas ce qui est voulu (configurer l'état d'un objet dans A puis l'utiliser dans B par exemple) il faudrait réfléchir à  sérialiser l'objet puis le communiquer à  l'autre application avec XPC par exemple.
  • Si non, tu peux regarder du côté d'AppleScript pour piloter une application tierce.
    C'est une bonne solution de secours, sauf qu'à  part les grands éditeurs (Apple, Adobe, ...) presque plus personne ne rend scriptable ses applications et il ne reste alors que les commandes mises en place par l'AppKit frameWork: 'oapp' open application, 'rapp' reopen, 'odoc' open documents, 'pdoc' print documents, 'ocon' open contents, 'quit' quit application. C'est vachement limité!
  • Merci à  tous pour vos réponses. J'écris en effet les deux codes, sauf que l'un d'eux est celui d'un plug-in utilisé dans une application tierce. Cela devrait marcher toutefois, puisque c'est son instance ("self") qui sera l'objet.



    Merci pour le lien de la doc que je n'avais effectivement pas trouvé. Je l'épluche et je vous tiens au courant.
  • HerveHerve Membre
    Bonjour,



    Je reviens vers vous suite à  ce problème de communication inter-applications.



    Voilà  ce que je veux faire :

    Il y a

    - un plug-in Audio Unit

    - une application

    - un fichier data sur le HD



    Lorsque je lance l'application depuis le plug in, je veux que l'application utilise une partie du fichier data avec un index (int)



    Pour l'instant je fais :

    - dans le plug-in :
    <br />
    [[NSWorkspace sharedWorkspace] launchApplication:@&quot;Dazibao.app&quot;];<br />
    NSNumber *midPg = //etc.<br />
    NSConnection *theConnection;<br />
       <br />
        theConnection = [[NSConnection new] autorelease];<br />
        [theConnection registerName:  @&quot;PatchEditionFromDazibaoAU&quot;];<br />
        [theConnection setRootObject:midPg];<br />
       <br />
        if ([theConnection registerName:@&quot;PatchEditionFromDazibaoAU&quot;] == NO) {<br />
    	    printf(&quot;Dazibao app did not receive the message\n&quot;);<br />
        }<br />
    




    et dans l'appli ceci =
    <br />
    NSConnection *theConnection = [NSConnection connectionWithRegisteredName:@&quot;PatchEditionFromDazibaoAU&quot;<br />
    														  host:nil];<br />
        if (theConnection){ // etc. }<br />
    




    Pour l'instant, cela ne communique pas. (le message d'alerte s'affiche)



    J'ai essayé aussi avec NSSocketPort depuis le plug-in, mais là  ça a planté.



    Qu'est-ce que j'oublie, ou que je n'ai pas compris selon vous?
  • yoannyoann Membre
    L'idée c'est quoi en fait ? Passer un offset de seek à  ton appli indépendante pour reprendre là  où l'utilisateur en est ? Ou est-ce qu'il y a réellement besoin d'IPC ?



    Si c'est juste un seek tu peux faire passer ça par un fichier temporaire... Un plist de config avec chemin du fichier data et settings. Tu passe ce fichier à  ton application au lancement au lieux de l'autre.
  • HerveHerve Membre
    Dazibao et son plug-in sont un synthétiseur de musique.



    L'idée est que le fichier data sur le disque dur contient les paramètres du son du synthé. Je veux pouvoir éditer ces paramètres depuis l'application, qui réécrira le fichier. Il doit savoir quel ensemble de paramètres sur les 32 possibles il doit afficher et autoriser la réécriture. Puis l'appli avertira le plug que le travail est fini et qu'il faut recharger le fichier sur disque.



    J'ai renoncé à  employer le plug comme générateur dans l'appli, cela me semble très incertain. A moins que?
  • yoannyoann Membre
    'Herve' a écrit:


    Dazibao et son plug-in sont un synthétiseur de musique.



    L'idée est que le fichier data sur le disque dur contient les paramètres du son du synthé. Je veux pouvoir éditer ces paramètres depuis l'application, qui réécrira le fichier. Il doit savoir quel ensemble de paramètres sur les 32 possibles il doit afficher et autoriser la réécriture. Puis l'appli avertira le plug que le travail est fini et qu'il faut recharger le fichier sur disque.




    Si c'est juste lire et écrire un fichier ça peut se faire simplement avec du FSEvent ou bien des notification distribués.


    'Herve' a écrit:


    J'ai renoncé à  employer le plug comme générateur dans l'appli, cela me semble très incertain. A moins que?




    C'est à  dire ? En quoi utiliser ton plug-in dans ton app est-il compliqué ?
  • HerveHerve Membre
    Je pense qu'il faut mettre une NSInvocation dans l'appel de l'application en fait. J'ai du mal à  tout comprendre dans la doc.



    Merci Yoann.



    Il semble que FSEvent ne soit pas du Cocoa mais du ... ??

    J'ai pensé à  un moment intégrer le plug-in ouvert dans le host sequencer dans le AUGraph de l'appli, mais ce que je projette de faire est plus simple.
  • yoannyoann Membre
    Tu mélange beaucoup de chose. Un objet ne peux pas passer d'un contexte mémoire à  un autre ! Donc NSInvocation ne servira à  rien.



    FSEvent permet de surveiller les changements sur un fichier http://en.wikipedia.org/wiki/FSEvents, soit tu passe par ce type d'outil pour savoir quand le fichier est modifié soit tu utilise une notification inter app.
  • HerveHerve Membre
    Je me prends souvent la tête pour rien...



    Je cherche aussi du côté de NSWorkspace. Un truc aussi simple que
    <br />
    - (BOOL)application:(NSApplication *)application openFile:(NSString *)filename<br />
    
    avec un int à  la place du NSString serait parfait...
  • yoannyoann Membre
    launchApplicationAtURL:options:configuration:error: avec les options adéquates pour passer tes arguments en argv ?



    http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSWorkspace_Class/Reference/Reference.html
  • AliGatorAliGator Membre, Modérateur
    C'est une bonne idée yoann, mais si l'application est déjà  lancée lors de l'appel à  cette méthode, elle ne sera pas relancée, et il ne pourra pas récupérer les arguments dans argv.



    Par contre s'il est sûr que son système va lancer l'application, et quand l'application a fini et qu'elle rend la main à  son plugin, qu'elle va quitter dans la foulée, là  par contre oui ça devrait le faire. Quitte à  passer l'option pour lancer une nouvelle instance même si l'appli est déjà  lancée.
  • HerveHerve Membre
    Cela a l'air très bien en effet. Merci beaucoup.



    J'imagine que la fonction dans l'appli doit être quelque chose comme :
    <br />
    - (BOOL)application:launchApplication options:(NSWorkspaceLaunchOptions)options configuration:(NSDictionary *)configuration error:(NSError **)error<br />
    




    Je n'arrive plus à  trouver où est référencé
    <br />
    - (BOOL)application:(NSApplication *)application openFile:(NSString *)filename<br />
    


    dans la doc en fait... Je ne le trouve ni dans NSApplication ni dans NSWorkspace. La fonction à  implémenter doit être à  côté?



    J'essaie tout cela en tous les cas. Merci encore.
  • 'Herve' a écrit:


    Je n'arrive plus à  trouver où est référencé
    <br />
    - (BOOL)application:(NSApplication *)application openFile:(NSString *)filename<br />
    


    dans la doc en fait... Je ne le trouve ni dans NSApplication ni dans NSWorkspace. La fonction à  implémenter doit être à  côté?






    application openFile
  • HerveHerve Membre
    Merci mpergand, mais auriez-vous une idée de la fonction à  écrire dans l'appli qui réponde à  "launchApplicationAtURL:options:configuration:error:" ? Pour l'instant, rien ne marche.



    J'avais aussi trouvé il y a longtemps cette discussion :

    http://forum.cocoacafe.fr/topic/1710-communication-inter-app/page__p__16891__hl__nsconnection__fromsearch__1#entry16891



    Connaitriez-vous un bon exemple de code pour NSConnection et NSDistantObject? De toutes façons, pour le message retours, il faudra que je maà®trise les NSConnections...



    Merci...
  • HerveHerve Membre
    [font=arial,helvetica,sans-serif]Comme le dit yoann, une NSDistributedNotification semble plus adaptée à  mon besoin.



    Je sais utiliser les NSNotifications "intra application". Si j'ai bien compris, le NSDistributedNotificationCenter permet la transmission de notifications d'une appli à  l'autre à  l'intérieur d'un même ordinateur. [/font]



    [font=arial,helvetica,sans-serif]Si c'est bien cela, je dois logiquement ajouter une écoute de cettee notification dans le "add listener" de l'application cible :[/font]

    [font=arial,helvetica,sans-serif]
    <br />
    [[NSDistributedNotificationCenter defaultCenter]addObserver:self<br />
    													    selector:@selector(requeteDuPlug:)<br />
    														    name:@&quot;requeteDuPlug&quot;<br />
    														  object:nil];<br />
    
    [/font]



    [font=arial,helvetica,sans-serif]et envoyer la requête depuis le plug-in :[/font]

    [font=arial,helvetica,sans-serif]
    <br />
    NSDictionary *monMessage;<br />
    		    monMessage = [NSDictionary dictionaryWithObjects:(id *)midPg forKeys:dicoRef count:1];[/font][/size]<br />
    [size=4][font=arial,helvetica,sans-serif]NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];<br />
    		    [center postNotificationName:@&quot;requeteDuPlug&quot; object:nil userInfo:monMessage deliverImmediately:YES];<br />
    
    [/font]



    [font=arial,helvetica,sans-serif]Pour l'instant, la communication ne s'établit pas. Selon vous, où est la faute? (En particulier, je ne sais pas comment dire que l'objet de la notification est un .component. D'habitude, je donne le nom de l'instance de ma classe)[/font]
  • HerveHerve Membre
    Bon, c'est bon, j'ai trouvé : l'objet est le nom du bundle.



    Cela commence à  marcher. Il me faudrait retarder l'envoi de la notification et attendre que l'appli soit ouvert. Je devrais trouver cela dans NSApplication ou son délégué.



    Merci à  tous encore, je crois que je suis en train de trouver la bonne solution. Comme toujours avec Apple, c'est simple... lorsqu'on connaà®t le truc!
  • AliGatorAliGator Membre, Modérateur
    Tu peux lancer l'application, et que ton application elle-même émette une NSDistributedNotification pour prévenir ton plugin qu'elle est prête et lui demander qu'il lui envoie l'info.

    Et en retour, sur réception de cette NSDistributedNotification, le plugin va à  son tour envoyer une NSDistributedNotification à  l'application pour lui envoyer la ou les infos nécessaires.
  • HerveHerve Membre
    Merci Aligator.



    C'est effectivement ce que j'ai fait. Cela marche super.



    Sauf si j'utilise plusieurs instances de mon plug-in... Faut que j'améliore le truc. Mais je tiens le bon bout.



    Ai-je bien compris la doc sur les notifications si je dis que si une "NSDistributedNotification" elle est détruite par défaut? (il y a plusieurs modes de mise en pile des notifications, mais je ne suis pas certain d'avoir compris). De même, il faudrait que si un plug a reçu la notification, les autres l'ignorent.



    Je sais que c'est là  : la doc mais je ne suis pas certain de tout comprendre!
  • HerveHerve Membre
    Bizarre, bizarre!!



    Ce que j'ai fait marche très bien avec un seul plug-in ouvert, mais lorsque j'en ouvre deux, GarageBand ou LogicAudio plantent (crash) ... mais pas mon appli!!

    J'ai fait d'abord :

    le plug ouvre l'appli

    > l'appli ouverte envoie une NSDistributedNotification

    > suite à  cette notification le plug crée un NSDictionnary avec un NSNumber et sa clef

    > le plug envoie une NSDistributedNotification avec le dico

    > l'appli a déjà  chargé à  l'initialisation un fichier data et affiche le patch correspondant au NSNumber du dico

    > ce travail fait, l'appli envoie une NSDistributedNotification et ferme

    > le plug recharge le fichier data et joue le son modifié.



    Cela marche très bien avec le premier plug mais le second plante tout (le host, pas l'appli). Cela crash lors de la seconde ouverture de l'appli



    J'ai essayé de supprimer la première notification, l'utilisateur appuie sur un bouton pour envoyer la notification du plug. Cela crash lorsque l'appli demande aux plugs de recharger le data.



    Je mets là  le rapport, enfin le début :
    <br />
    //test avec GarageBand<br />
    Interval Since Last Report:		  15200 sec<br />
    Crashes Since Last Report:		   11<br />
    Per-App Interval Since Last Report:  1004 sec<br />
    Per-App Crashes Since Last Report:   11<br />
    Anonymous UUID:					  7E66BDB6-F368-47C4-B664-EB983A0B5845<br />
    Crashed Thread:  0  Dispatch queue: com.apple.main-thread<br />
    Exception Type:  EXC_BAD_ACCESS (SIGABRT)<br />
    Exception Codes: KERN_INVALID_ADDRESS at 0x000000003108e165<br />
    VM Regions Near 0x3108e165:<br />
        CoreServices		   0000000010fd1000-000000001119f000 [ 1848K] rw-/rwx SM=COW <br />
    --&gt;<br />
        __TEXT				 000000008fedd000-000000008ff10000 [  204K] r-x/rwx SM=COW  /usr/lib/dyld<br />
    Application Specific Information:<br />
    objc[234]: garbage collection is OFF<br />
    abort() called<br />
    Thread 0 Crashed:: Dispatch queue: com.apple.main-thread<br />
    0   libsystem_kernel.dylib		 0x904f19c6 __pthread_kill + 10<br />
    1   libsystem_c.dylib			  0x98020f78 pthread_kill + 106<br />
    2   libsystem_c.dylib			  0x98011ce3 __abort + 198<br />
    3   libsystem_c.dylib			  0x98011c1d abort + 231<br />
    




    Y'a un truc que je ne sais pas. J'aurais aimé que tous les plugs ouverts rechargent le fichier en particulier, est-ce là  mon erreur?



    Je fais :
    <br />
    NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];<br />
    	    [center postNotificationName:@&quot;rechargeLaBanque&quot;<br />
    							  object:@&quot;com.hervenoury.dazibao&quot;<br />
    						    userInfo:nil<br />
    				  deliverImmediately:YES];<br />
    


    Est-ce le "YES" qui pose problème?



    (toutes les notifications sont sur ce modèle)



    Si quelqu'un voit le "truc", je suis preneur... Merci d'avance!
  • HerveHerve Membre
    Bon, j'ai essayé différents trucs, sans succès : les notifications des plugs vers l'appli passent bien, mais si j'ouvre deux plugs ou plus, le host sequecner crash dès que l'appli envoie ses notifications au second plug.



    J'ai essayé :
    <br />
    [[NSNotificationQueue defaultQueue]dequeueNotificationsMatching:<br />
    		 [NSNotification notificationWithName:@&quot;rechargeLaBanque&quot; object:@&quot;com.hervenoury.dazibao&quot;]<br />
    														   coalesceMask: NSNotificationCoalescingOnSender];<br />
    <br />
    




    ou :
    <br />
    [[NSNotificationQueue defaultQueue]<br />
    		 enqueueNotification:[NSNotification notificationWithName:@&quot;rechargeLaBanque&quot; object:@&quot;com.hervenoury.dazibao&quot;]<br />
    		 postingStyle:NSPostWhenIdle<br />
    		 coalesceMask:NSNotificationCoalescingOnSender<br />
    		 forModes:nil];<br />
    




    pour nettoyer les notifications avant nouveau post, le "EXC_BAD_ACCESS (SIGABRT)" demeure.



    J'ai même essyé de reposter dans le plug la notification de l'appli si ce n'était pas à  lui de la traiter grâce à  un booléen (si oui, le plug la traite, si non il la renvoie) sans succès...



    Qu'est-ce que je n'ai pas compris dans les NSDistributedNotifications selon vous?
  • HerveHerve Membre
    Toujours pas de solution... Pour l'instant j'ai mis un message d'alerte expliquant le problème, mais bon, ce n'est pas terrible...



    De mon point de vue, le problème est que lorsque l'appli adresse ses notifications aux divers plug-ins ouvert, le premier concerné est choisi par le NSNotificationCenter comme le récepteur des NSDistributedNotification de l'appli. Les autres du coup sont ignorés.



    Mais pourquoi alors ceci :

    Exception Type: EXC_BAD_ACCESS (SIGABRT)

    Exception Codes: KERN_INVALID_ADDRESS at 0x000000003108e165



    Je n'arrive pas à  trouver dans la doc la source du problème. Auriez-vous une idée?



    Seulement une question par exemple : est-ce que les NSDistributedNotification peuvent être reçues par plusieurs applications? Ou est-ce qu'elles ne peuvent s'adresser qu'à  une seule?
  • AliGatorAliGator Membre, Modérateur
    Je n'ai pas de solution à  te donner (d'autant qu'en pratique je n'ai jamais utilisé les NSDistributedNotifications) mais peut-être peux-tu activer les NSZombies sur ton plugin ?



    En effet, EXC_BAD_ACCESS correspond à  l'utilisation d'un espace mémoire qui n'est plus alloué ou ne contient pas ce que tu attends.

    Tu utilises une zone mémoire qui n'est pas ou plus allouée, et là  où tu t'attends à  trouver le début d'un objet, tu tombes sans doute en plein milieu de nulle part.



    Or, une des raisons qui font que tu peux avoir cette exception est si tu utilises un objet qui en fait a été désalloué depuis (genre tu as fait un "release" sur l'objet, il a été "dealloc" et détruit, et tu continues à  l'utiliser et envoyer des messages à  son adresse mémoire après qu'il a été détruit). En activant NSZombiesEnabled, tu vas pouvoir déboguer ça en ne faisant que marquer chaque objet sensé être détruit d'un flag plutôt que de réellement le détruire, et le débogueur saura ensuite te dire "tiens tu essayes d'envoyer un message à  une zone mémoire qui contenait avant tel objet, mais qui maintenant n'est plus sensée contenir quoi que ce soit", tu sauras donc quel objet tu as "détruit trop tôt".
  • HerveHerve Membre
    Victoire!!



    Je suis allé dans ton sens, AliGator, mais un peu différemment. Au lieu de mettre les écouteurs automatiquement lors de l'initialisation du plug in, je ne les mets que lorsque j'appelle l'application depuis le plug (launchApp...). De même, je les "remove" lorsque l'application a envoyé sa notification de fin de travail.



    Et cette fois, cela ne plante plus!! (essayé avec deux, mais cela devrait marcher avec plus.)



    Ouf, et ben, cela a été dur!! image/huh.gif' class='bbc_emoticon' alt='???' /> image/xd-laugh.gif' class='bbc_emoticon' alt='xd' />
Connectez-vous ou Inscrivez-vous pour répondre.