2009-01-12 6 views
2

Je suis portage d'une application (principalement) multi-plateforme existante à WinCE 4.2. Le point d'entrée actuel de la fonction estMain principale à WinCE principal

int main(int argc, char *argv[]){} 

je voudrais garder cette partie en l'état, et ont le point d'entrée de WinCE appeler simplement. Je crois que quelque chose comme ce qui suit devrait fonctionner:

int WINAPI WinMain(HINSTANCE hInstance, 
        HINSTANCE hPrevInstance, 
        LPTSTR lpCmdLine, 
        int  nCmdShow) 
{ 
    int argc = _tcslen(lpCmdLine); 
    char *argv = new char[argc]; 
    wcstombs(argv,lpCmdLine,1024); 
    argc = main(argc,&argv); 
    delete [] argv; 
    return argc; 
} 

Il compile et devrait fonctionner une fois que je comprendre pourquoi l'éditeur de liens est de lancer, mais est-il juste?

+0

Juste un point mineur; devrait être 'delete [] argv;' – Henk

+0

Ou utiliser alloca, ou le faire sur place (lpCmdLine est non-const!) – MSalters

Répondre

2

Merci à vous deux pour vos réponses utiles. J'ai écrit ce qui suit, qui fonctionne aussi bien que nous en avons besoin pour le moment. Seul notre code appellera cet exécutable, et jamais avec des guillemets, bien que cela ne soit pas trop difficile à ajouter. En outre, il peut ne pas bien fonctionner s'il y a plus d'un espace entre les arguments, mais encore une fois, nous n'avons pas à nous soucier des autres personnes qui utilisent ce programme, c'est juste à des fins académiques. Si vous pensez que des améliorations sont nécessaires, modifiez ce post et justifiez-le dans votre commentaire.

int WINAPI WinMain(HINSTANCE hInstance, 
        HINSTANCE hPrevInstance, 
        LPTSTR lpCmdLine, 
        int  nCmdShow) { 
    assert(lpCmdLine != NULL); 

    int argc = 1, ret = 0; 
    std::vector<char*> args; 

    // Copy the entire array to a regular cstr 
    int cmdLineLen = _tcslen(lpCmdLine); 
    char *argv = new char[cmdLineLen]; 
    wcstombs(argv,lpCmdLine,cmdLineLen); 
    args.push_back(&argv[0]); 

    // Replace spaces with nulls to effectively create array of cstr 
    for(int i=0; i<cmdLineLen; i++){ 
    if(argv[i] == ' '){ 
     argv[i] = '\0'; 
     args.push_back(&argv[i+1]); // Keep track of the first char in each word 
     argc++; 
    } 
    } 

    // argv[argc] should be NULL. 
    args.push_back(NULL); 

    try{ // Run the program 
    ret = main(argc,&args[0]); 
    } 
    catch(...){ 
    // TODO: Report error here. Commented code works OK for WinCE .NET 
    // delete argv; 
    // throw; 
    ret = -1; 
    } 
    delete argv; 
    return ret; 
} 

En outre, pour les personnes intéressées, l'exécution de ce à la ligne de commande

>myprogam.exe -a shortargument -b -c 

mettra les éléments suivants dans lpCmdLine

"-a shortargument -b -c" 

Aussi, ma première supposition est que argv devait être delete [] 'd (parce que j'ai new char []' d), mais quand j'ai fait cela, le programme a eu une erreur fatale. Quand je suis passé à ce qui précède, cela a fonctionné. Cela ne viole-t-il pas la règle new-> delete/new [] -> delete []?

+0

J'ai remarqué un avertissement C4297 lors de la compilation de cette fonction WinMain. Apparemment, aucune fonction n'est autorisée à sortir de WinMain. L'instruction 'throw;' devrait donc probablement être supprimée. –

+0

Merci, j'ai changé le code. Je n'ai plus accès au compilateur, donc je ne peux pas m'assurer que cette modification fonctionne. –

2

Votre idée générale est correcte mais votre conversion de lpCmdLine est susceptible de vous causer des problèmes. Considérez ce qui suit:

$> myprogam.exe -a shortargument -b -c -d "longue discussion avec des espaces"

les arguments passés à votre fonction principale serait quelque chose comme ceci:

argc = 7; 
argv = { 
    "myprogram.exe", 
    "-a", 
    "shortargument", 
    "-b", 
    "-c", 
    "-d", 
    "long argument with spaces" 
}; 

WinMain sera toutefois recevoir une grande chaîne longue comme ceci:

lpCmdLine = "-a shortargument -b -c -d "long argument with spaces""; 

donc, si vous avez une analyse des options de ligne de commande en cours, vous allez probablement le casser. L'approche la plus polyvalente serait de parcourir lpCmdLine en plaçant tous les espaces blancs (en dehors des guillemets correspondants bien sûr) au caractère null (ie '0' ou simplement 0) et garder une trace des pointeurs vers le premier caractère valide après un séquence de caractères nuls.

Addition: Si je me souviens bien du temps où je faisais le développement WinCE me semble me rappeler quelque chose lpCmdLine juste être là pour la compatibilité avec win32 donc il est toujours vide. Pour obtenir la ligne de commande, je pense que vous devez utiliser GetCommandLine.

+0

le quitteriez-vous si l'application ne sera appelée que par notre code, jamais déployée vers les clients , et des arguments qui ne deviennent pas plus compliqués que "-i in -o out Clayers = 15 Corder = LRCP"? –

+0

cela dépend de la façon dont vous analysez vos options de ligne de commande si vous utilisiez quoi que ce soit le long des fonctions getopt d'unix, cela casserait votre code. Sans voir comment vous analysez votre ligne de commande, il vous suffit de l'essayer et de le découvrir. –

+0

lpCmdLine n'est pas null, mais GetCommandLine() est (au moins avec ma version de WinCE, 4.2) –

1

Non, ça ne va pas marcher.

int WINAPI WinMain(HINSTANCE hInstance, 
       HINSTANCE hPrevInstance, 
       LPTSTR lpCmdLine, 
       int  nCmdShow) 
{ 
    // argc: This is the number of arguments NOT the strlen 
    int argc = _tcslen(lpCmdLine); 

    // argv: Is an array of char* NOT an array of char. 
    char *argv = new char[argc]; 
    wcstombs(argv,lpCmdLine,1024); 

    // The argument passed as argc is not valid here. 
    argc = main(argc,&argv); 
    delete argv; 

    // You are returning the result of main that is correct. 
    // But re-using argc like this is smelly. Declare a new 
    // variable and let the compiler optimise away the extra use 
    // the compiler is VERY good at that. 
    return argc; 
} 

OK. Pas un expert avec WinCE. Si je faisais cela, j'utiliser std :: vecteur vous pouvez modifier pour travailler

int WINAPI WinMain(HINSTANCE hInstance, 
       HINSTANCE hPrevInstance, 
       LPTSTR lpCmdLine, 
       int  nCmdShow) 
{ 
    std::vector<char*> args; 

    // Split lpCmdLine by space. 
    // Remember to watch for quotes when splitting (From 'Kevin Loney') 
    // For each argument do 
    args.push_back(<SOMTHING>) 


    // The last argv[argc] should be NULL. 
    args.push_back(NULL); 

    int result; 
    try 
    { 
     // argc does not include the last NULL so do a -1 
     result = main(args.size()-1,&args[0]); 
    } 
    catch(...) 
    { 
     // If <SOMTHING> includes dynamically allocating memory 
     // Then you should delete it here. 

     throw; // Re-Throw the exception to get the same behavior. 
    } 

    return result; 
} 
+0

Je suis curieux de savoir argv [argc] == NULL, je n'ai jamais vu cela mentionné dans tout ce que j'ai jamais lu l'analyse de ligne de commande en C. Je peux voir que cela ne ferait certainement pas de mal mais est-ce que c'est défini dans la spécification C quelque part? –

+0

Oui. Mais je ne peux pas citer le chapitre et le verset. Voir le livre K & R. –

+0

Un google rapide: http://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html (Bien que je ne prétende pas que cette page est canon). –

5

La manière la plus simple de faire cela est simplement de changer le point d'entrée de l'éditeur de liens pour votre projet et d'utiliser la fonction principale (...).

Ouvrez le projet boîte de dialogue Propriétés puis allez à « Linker-> Advancedd » et définissez la valeur « Point d'entrée » basée sur les points suivants:

si votre point d'entrée est la suivante:

int main(int argc, char *argv[]) 

puis définissez le point d'entrée à mainACRTStartup

Mais si vous commencez avec:

int _tmain(int argc, TCHAR *argv[]) 

puis le point d'entrée est mainWCRTStartup

+0

Cela semble vraiment chouette. Si j'avais encore le compilateur, je l'essayerais. –

+0

Brillant! Notez que dans EVC++ 4 vous allez à * Paramètres-> Lieur-> Sortie * – Nick

Questions connexes