Нормальный основной на основной WinCE - PullRequest
2 голосов
/ 12 января 2009

Я портирую существующее (в основном) кроссплатформенное приложение на WinCE 4.2. Текущая точка входа для функции

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

Я бы хотел оставить эту часть как есть, и чтобы точка входа WinCE просто вызывала ее. Я считаю, что что-то вроде следующего должно работать:

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;
}

Он компилируется и должен запускаться, когда я выясняю, почему компоновщик выдает, но так ли это?

Ответы [ 4 ]

5 голосов
/ 19 октября 2010

Действительно простой способ сделать это - просто изменить точку входа компоновщика для вашего проекта и использовать функцию main (...).

Откройте диалоговое окно свойств проекта, затем перейдите к «Linker-> Advancedd» и установите значение «Точка входа» на основе следующего:

если ваша точка входа это:

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

затем установите точку входа на mainACRTStartup

Но если вы начинаете с:

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

тогда точка входа будет mainWCRTStartup

2 голосов
/ 13 января 2009

Спасибо вам обоим за полезные ответы. Я написал следующее, которое работает так, как нам нужно сейчас. Только наш код будет вызывать этот исполняемый файл без кавычек, хотя добавить его будет несложно. Кроме того, это может не сработать, если между аргументами будет больше одного пробела, но опять же, нам не нужно беспокоиться о других людях, использующих эту программу, она предназначена только для академических целей. Если вы считаете, что улучшения необходимы, отредактируйте этот пост и обоснуйте его в своем комментарии.

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;
}

Кроме того, для тех, кто заинтересован, запускать это в командной строке

>myprogam.exe -a shortargument -b -c

поместит следующее в lpCmdLine

"-a shortargument -b -c"

Кроме того, мое первое предположение состояло в том, что argv нужно было удалить [] 'd (потому что я новый символ []' d), но когда я это сделал, в программе произошла фатальная ошибка. Когда я переключился на выше, это работало. Разве это не нарушает правило new-> delete / new [] -> delete []?

2 голосов
/ 12 января 2009

Ваша общая идея верна, однако ваше преобразование lpCmdLine может вызвать у вас некоторые проблемы. Учтите следующее:

$> myprogam.exe -a короткий аргумент -b -c -d "длинный аргумент с пробелами"

аргументы, передаваемые вашей главной функции, будут выглядеть примерно так:

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

Однако WinMain получит большую длинную строку, подобную этой:

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

Так что, если у вас есть какой-либо синтаксический анализ параметров командной строки, вы, вероятно, сломаете его. Наиболее универсальный подход заключается в циклическом переборе lpCmdLine с установкой всего пробела (за исключением, конечно, соответствующих кавычек) нулевого символа (т. Е. «\ 0» или просто 0) и отслеживании указателей на первый действительный символ после последовательность нулевых символов.

Добавление: Если я правильно помню, когда я занимался разработкой, мне кажется, что я кое-что вспомнил о lpCmdLine, который просто был там для совместимости с win32, поэтому он всегда пуст. Чтобы получить командную строку, я думаю, что вы должны использовать GetCommandLine .

1 голос
/ 12 января 2009

Нет, это не сработает.

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. Не эксперт с WinCE. Если бы я делал это, я бы использовал std :: vector, который вы можете изменить для работы

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;
}
...