# Passage de paramètres sous Mac



## elendhil (3 Juin 2008)

Je réalise le portage d'une application qui fonctionne sous Linux et windows.
C'est une application écrite en c++ , qui utilise ogre3D(moteur graphique 3D) et des librairies comme boost.

Je rencontre un problème pour ouvrir cette application avec un fichier 
depuis un double clic sur un fichier au format de mon application.
L'application se lance correctement mais sans charger le fichier.

Sous linux , tout ce passe en ligne de commande (le prog a été developpé sur linux en premier), donc pas de soucis , argc et argv correspondent au paramètres passés au programme sur la ligne de commande.

Sous windows , sans passer par une ligne de commande il faut utiliser winMain() , mais sous MacOS je ne vois pas comment faire.

Le logiciel , utilise l'api carbon et non cocoa, es que quelqu'un serait comment récupérer les paramètres sous MacOS ?

Pour l'instant dans argc et argv j'ai : 
- argc = 2
- argv[0] = path/nomduProgramme
- argv[1] = -psn_0...... (un nombre généré , correspondant au process serial number)

Faut t'il utiliser ce psn pour récupérer les paramètres ou alors utiliser une fonction équivalente à winMain dans L'api Carbon ?

Je lutte un peu sur ce problème , je vous remercie d'avance pour vos réponses.


----------



## tatouille (3 Juin 2008)

elendhil a dit:


> Je réalise le portage d'une application qui fonctionne sous Linux et windows.
> C'est une application écrite en c++ , qui utilise ogre3D(moteur graphique 3D) et des librairies comme boost.
> 
> Je rencontre un problème pour ouvrir cette application avec un fichier
> ...



si c'est un bundle ? comment veux tu passer des params? le psn n'existe plus dans un env launchd

MAIN.c

STUB.c

/app.app/Contents/MacOS/TOTO --ftiti


----------



## elendhil (4 Juin 2008)

Pas vraiment compris ta réponse.

C'est un .app (je suppose qu'on nomme ça un bundle) , il y a donc dans ce bundle , des ressources , des librairies, l'icône de l'application , le fichier plist , et l'exécutable .

Quand on double clic sur le bundle, l'application se lance , idem sur un fichier associé à mon programme. Donc le système sait ou trouver l'exécutable à lancer dans le bundle.
Donc pour moi je me disais , le système devrait de lui même lui passer le nom du fichier .

Mais ce n'est pas le cas dans les paramètres du main , je recupère le nom et le chemin de l'exécutable , et un argument qui se greffe qui est bien -psn_0......



> si c'est un bundle ?


oui



> comment veux tu passer des params?



C'est bien justement ma question, je ne sais absolument pas. Plus qu'un simple paramètre à passer à mon exécutable , c 'est le nom du fichier sur lequel l'utilisateur a clické que je veux que mon exécutable récupère ? Comment fait on cela ?
Par exemple textEdit s'ouvre avec le contenu du ficher aprés un double click sur un fichier text ? Comment faire la même chose ?



> le psn n'existe plus dans un env launchd


Peut-être , je comprend pas vraiment ce que tu veux dire. Tout ce que je suis sur c'est que ce truc -psn ce greffe dans les arguments au lancement de mon programme.
Je fais le portage sous un mac ppc(iBook g4) sous MacOSX 10.4.11 tiger.



> MAIN.c
> 
> STUB.c
> 
> /app.app/Contents/MacOS/TOTO --ftiti


Je vais regardement plus attentivement mais pourquoi tout commence par python ?

Si tu voulais bien me donner un petit coup de main , ce serait vraiment sympa , j'essaie de trouver une solution depuis le début de la semaine , et je ne trouve pas de documentation sur le sujet.


----------



## ntx (4 Juin 2008)

Si ça marche de manière similaire à Cocoa, l'application connaît le type de fichier qu'elle sait gérer, et l'OS sait lors d'un double-clic quelle application par défaut il faut lancer pour ouvrir tel ou tel type de fichier. Tout est automatique, il n'y a pas de paramètres à passer. Toutes les infos sont dans le fichier info.plist

Si tu veux lancer ton application dans un terminal à la façon "UNIX", utilise la commande open.


----------



## tatouille (4 Juin 2008)

BundleAnatomy.html


Info.plist

CFBundleDocumentTypes

*Je vais regardement plus attentivement mais pourquoi tout commence par python ?

*on s'en fou...

c'est pas le sujet


```
if( (ok = PYASCoreUtilIsStringStartsWith(PYASSTR(argv[1]), "-psn", 0)) )
    PYASTRACE("+ PythonApplicationStub:\n\t+ -- Current psn %s \n", argv[1]);
```
et il n'y a aucun traitement d'autre parametre pourtant les applis ouvrent des fichiers CQFD

c'est juste que c'est similaire a


```
int main(int argc, char *argv[])
{
    return NSApplicationMain(argc,  (const char **) argv);
}
```


```
int main(int argc, const char * argv[]) 
{
    return PythonApplicationStubMain(argc, (const char **) argv);
}
```


----------



## elendhil (4 Juin 2008)

> Si ça marche de manière similaire à Cocoa, l'application connaît le type de fichier qu'elle sait gérer, et l'OS sait lors d'un double-clic quelle application par défaut il faut lancer pour ouvrir tel ou tel type de fichier. Tout est automatique, il n'y a pas de paramètres à passer. Toutes les infos sont dans le fichier info.plist
> 
> Si tu veux lancer ton application dans un terminal à la façon "UNIX", utilise la commande open.




J'ai du mal mexpliquer, oui j'ai modifié le fichier info.plist contenu dans le bundle du répertoire contents. Ce qui fait que l'association marche bien, et quand je double clic sur un fichier au format de l'application elle se lance correctement, mais sans ouvrir le fichier. Dû au fait que le programme a été développé en premier pour être lancé par ligne de commande.

Mais sur Mac ou windows nous avons besoin que l'application se lance par un double clic sur un fichier car c'est une application destinée au grand public. Comme le programme pour l'instant ne peut ouvrir un fichier que sil est contenu dans argv, il faut que j'adapte le code à la plate forme Apple.  ET j'aimerais donc récupérer le nom du fichier ainsi que le chemin sur lequel l'utilisateur a cliqué, c'est tout.
(Je précise ce fichier sera téléchargé depuis internet par l'utilisateur, et ensuite pour l'ouvrir il devra juste double cliqué dessus)

Mais comment le récupère-t-on ?


```
int main(int argc, char *argv[])
{
    return NSApplicationMain(argc,  (const char **) argv);
}
```
 
Quand je vois ce bout de code , il y a deux solutions  soit :

1 ) chez moi ca merde pour une raison inconnu et dans argv il devrait avoir le nom du fichier contenu dans le tableau.

2) NSApplicationMain à partir du -psn_* récupère le nom du fichier au prés du système.

Je ne vois pas le rapport avec le code des fichiers Main.c Stub.c  pour résoudre mon problème.


----------



## ntx (4 Juin 2008)

Il faut clairement séparer l'intégration de l'application dans l'OS, avec du code spécifique Windows ou Mac, et les traitements qui eux peuvent être du code commun. 
Crée dans Xcode un projet Carbon ou Cocoa (au vu des nouvelles du jour, j'éviterais Carbon ) d'une application basée sur un document. Tu auras le squelette de ton application avec la gestion des types de documents, et la-dessus greffe le code du traitement. Idem du côté Windows. Le contrôleur de document te fournira toutes les informations sur le document ouvert.

Quand tu travailles avec un framework, il faut correctement et complètement implémenter tes objets sinon ça ne marche pas. Là j'ai l'impression que tu ne fais que la moitié du travail.


----------



## tatouille (4 Juin 2008)

il faut que tu bridges avec carbon, t'as besoin d'un main carbon



```
static OSStatus
AppEventHandler( EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon )
{
...
  AEDescList docs;
  if (AEGetParamDesc(&MyEvent, keyDirectObject, typeAEList, &docs) == noErr) {

...
```

google, il doit y avoir quelques exemples qui trainent


----------



## elendhil (5 Juin 2008)

J'ai beau chercher , je ne trouve pas d'exemples de code , qui corresponde à mon problème.

En gros je voudrais un exemple du type :

Je double clic sur mon fichier toto.txt , l'appli associé se lance avec juste une fenêtre et dedans on  voit écrit : l'application a été ouverte suite à un double clic sur "/Users/elendhil/Desktop/Toto.txt".

Avec un exemple du type , je pourrais facilement l'adapter à notre programme. 

Parce que la je sais pas du tout comment fonctionne les AppleEvents, tout les exemples que je trouve correspondent au clic dans le menu en haut associé aux applications( style fichier -> ouvrir un fichier).

Mais tout notre interface utilisateur est déjà codé , et utilise des librairies multi-plateformes comme CEGUI ou OIS.

Si vous auriez un bout de code qui corresponde a peu près à l'exemple que je décris , de préférence en Carbon  mais si il y  a pas en Cocoa , j'adapterais , ce serait le bonheur.

Je vous remercie pour votre patience , et j'espère que vous aurez un bout de code enfouie sur votre Mac qui corresponde.


----------



## tatouille (5 Juin 2008)

```
#include <Carbon/Carbon.h>

static OSStatus AppEventHandler(
    EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon ) 
// handler des events quand j'en recois un je 
// determine lequel et agis en conscequence generalement 
// en appelant une autre fonction par exemple
{
    OSStatus result = eventNotHandledErr;
    
    switch( GetEventClass(inEvent) )
    {
            // ton code .....
    }
    
    return result;
}

int main(
    int argc, char* argv[])
{
    OSStatus err;
    
    static const EventTypeSpec  kAppEvents[] =
    {
        { kEventClassCommand, kEventCommandProcess, .... } 
// tableau des events a observer et acceptable par l'app
    };
    
// preparation du ForEver say: bind these events please and use as worker AppEventHandler function
    InstallApplicationEventHandler( 
        NewEventHandlerUPP( AppEventHandler ), 
            GetEventTypeCount( kAppEvents ), kAppEvents, 0, NULL);
    
 // ton code .....
   
// demarrage du ForEver
      RunApplicationEventLoop();

// nothing happends here till sigquit or worst

    return err;
}
```


```
open /System/Library/Frameworks/Carbon.framework/Versions/Current/Frameworks/HIToolbox.framework/Versions/A/Headers/
```
bienvenue dans un env multi-thread ce genre d'info n'a rien a faire dans le vector arg
que ce passerait t-il a chaque fois que tu double clique sur un fichier ou le drag sur l'icon de l'app ?

ca fonctionne comme tous les toolkits descends qui existent

//tableau des events
quand tu auras trouve l'event a binder 

//worker
tu le testeras, tu en tireras une aelist afin de gerer le one ou multi files 
dans l'objet file que tu receveras il y aura l'info qui te permetteras de retrouver le path pour ton 
forward sur ta fonction OpenDocument

pas de raison de paniquer, et je confirme il y a des exemples, plus, des cross-platform frameworks comme qt ou wx
 utilisent Carbon stricto de facto de la meme facon

Carbon Application Document based


----------

