Программирование на Symbian C++. Некоторые вопросы и ответы
Это вопросы, которые возникли у меня (да и у многих других) во время освоения Symbian C++ и ответы на них, полученные в результате поисков на форумах или методом проб и ошибок. --------------- Q: Можно ли без SDK собрать готовый проект? ---- A: Нет. --------------- Q: Можно ли скомпилить готовые исходники, не имея IDE? ---- A: Конечно! Вначале надо создать abld.bat и пачку make'ов вызовом bldmake bldfiles из той папки, где лежит файл *.inf, затем запускать abld build <платформа> udeb/urel. Подробности - в SDK и в help'е консольных утилит bldmake, makmake, abld и др. --------------- Q: Программа на JAVA из SDK требует какую-то старую виртуальную машину. У меня более новая - и ничего не запускается... ---- A: Вариант 1, топорный. Записываем, какая версия нужна. В ветке реестра HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\ есть раздел с имеющейся версией - создаём точно такой же, но с нужным номером версии. Можно ещё проделать то же самое с остальными разделами ветки HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft. Теперь программа должна запуститься. Но при этом в ней может ничего не работать. Что ясно доказывает - совместимость JAVA - это не более, чем маркетинговый ход. Вариант 2, правильный. СНОСИМ имеющуюся JAVA-машину, заходим по адресу http://java.sun.com/products/archive/ и качаем нужную машину. Виртуальные машины, в названии которых есть SDK, содержат библиотеки для разработчиков, и для наших целей не нужны. --------------- Q: Где документацию брать? ---- A: Программисты под Windows привыкли, что у них есть MSDN, программеры на JAVA привыкли к тому, что к любой библиотеке приложен javadoc. Здесь хуже - документация достаточно слабая, примеры обычно представляют собой готовые проекты, где, кроме собственно примера есть ещё с десяток файлов. Приходится активно использовать поиск текста в заголовочных файлах в папке %EPOCROOT%\\Epoc32\\Include и, конечно же, поиск в Web, благо, сайтов с инфой много. Отправная точка поисков, как правило forum.nokia.com, разделы Discussion Boards и Symbian/C++ Code and Examples. Кроме того, symbian.com и newlc.com. Довольно интересно пишет вот этот финский товарищ: http://www.cs.helsinki.fi/u/mraento/symbian/ Русской документации не существует, единственная попавшаяся мне в руки книга Горнакова С.В. - ниже плинтуса. Из неё становится ясным только одно - автор может поставить CodeWarrior на компьютер :-) Если есть большие проблемы с техническим английским - займитесь лучше чем-то другим. --------------- Q: Как меня задолбали эти длинные пути, эти коммандные строки... A: В FAR есть пользовательское меню F2 (не путать с жалкой пародией, которая вылазит по Ctrl+D в Total!). Вот туда нужно добавить соответствующие строки. Добавляется это в визуальном режиме по кнопке Insert или вставкой команд в текстовый файл (нажмите Alt+F4 в пользовательском меню) У меня это оформлено в виде подменю "Команды Symbian". Благодаря использованию переменной EPOCROOT вместо жёсткого задания путей, это будет работать и в другом Far'е, однако накладывает ограничение: меню работает, только если текущая папка фара находится на том же диске, где установлен Symbian SDK. Чтобы это всё работало в вашем FAR - должен быть установлен стандартный плагин Far Commands (а он устанавливается по умолчанию вместе с FAR)
s: Команды Symbian { F1: SDK Help %EPOCROOT%\\Series60Doc\\start.chm f: Синтаксис файлов: { s: Синтаксис sis-файла edit:m: Синтаксис mmp-файла edit:} -: s: Создать sis-файл macro:post ShiftAlt6 "*.pkg" Esc CtrlIns "makesis -v " ShiftIns Enter g: Сборка стандартного проекта для мобилы (armi) cd !?Корневая папка проекта?(!\\)!\\install del /Q *.sis CD ..\\group abld build armi urel CD ..\\install macro:post ShiftAlt6 "*.pkg" Esc CtrlIns "makesis -v " ShiftIns Enter a: Создать abld bldmake bldfiles m: Мобильная сборка (c выводом лога) edit:v: Создать проект для VC !?Папка group?(!\\)!\\abld.bat makefile vc6 -: p: Папка с проектами CD %EPOCROOT%\\Epoc32\\BUILD\\ r: Папка с релизами armi CD %EPOCROOT%\\Epoc32\\Release\\armi\\urel 1: Диски { с: Диск С CD %EPOCROOT%\\Series60\\Epoc32\\Wins\\c d: Диск D CD %EPOCROOT%\\Series60\\Epoc32\\Wins\\d z: Диск Z CD %EPOCROOT%\\Epoc32\\Release\\wins\\udeb\\z } }
--------------- Q: Ошибка компиляции - unresolved external symbol _chkstk (также может быть __aullshr, __allshl ...). Ошибка происходит при сборке под WINS, сборка для ARMI или THUMB происходит без ошибок. Что делать? ---- A: В mmp-файле необходимо написать строки: START WINS WIN32_LIBRARY msvcrt.lib END --------------- Q: Ошибка компиляции при сборке для телефона: 'MyApplication.app' has initialised data. Под эмулятором - всё хорошо. Что бы это значило? ---- A: Это значит, что тебе пора отвыкать использовать глобальные переменные. Глобальная переменная в app может быть только одна - UID приложения. Ищи все глобальные переменные и засовывай их внутрь классов. --------------- Q: Блин! Но у меня в проекте 110 файлов уже! И с сотню глобальных переменных. Что, всё это переписывать? ---- A: Ага! Глобальные переменные могут быть только при создании EXE. --------------- Q: EXE и APP - в чём разница? ---- A: О, во многом. Но, как правило, EXE - это консольное приложение, и оно запускается с коммандной строки. Так что разница примерно такая же, как между консольным и оконным приложением в Windows --------------- Q: Что-то не совсем понял, как тут DLL-ки работают? Где аналог GetProcAddress? ---- A: Тут нет аналога GetProcAddress - всё интереснее. Принцип такой: 1. В приложении объявляется класс с виртуальными функциями. Например: class CDllClass { CDllClass(); ~CDllClass(); virtual bool GetBoolean(){return false;} // virtual virtual int GetNumber(int start)=0; // pure virtual }; 2. В DLL-ке объявляется класс, отнаследованный от этого класса, виртуальные функции переопределяются. Например: class CDllClass1 : public CDllClass { CDllClass(){} ~CDllClass(){} //------------------- bool GetBoolean() { return true; } //------------------- int GetNumber(int start) { return start+1; } }; 3. DLL должна экспортировать функции только такого типа: typedef TInt (*TLibraryFunction)(); Т.е. все экспортируемые функции не имеют параметров и возвращают целые числа. В такой функции создаём экземпляр отнаследованного класса и возвращаем указатель на него: TInt DllStart() { CDllClass1 * pDllClass = new CDllClass1; return (TInt)pDllClass; } 4. В приложении нужно вызвать эту функцию: RLibrary lib; lib.Load(_L("c:\\dlls\\mydll.dll")); TLibraryFunction func = lib.Lookup(1); // Вызываем функцию по смещению 1 CDllClass * pDllClass = lib.func(); int number = pDllClass->GetNumber(100); // number = 101 --------------- Q: Клёво! А я хочу ещё из dll-ки вызвать функцию моего приложения. ---- A: Тут в точности, как в WinAPI. 1. В заголовочном файле, подключаемом и к проекту приложения и к проекту dll, объявляем указатель на функцию, например: typedef bool (*SET_INFO)(int hoster, const TDesC &text); 2. В проекте приложения пишем код функции. bool SetInfo(int hoster, const TDesC &text) { CMyWindow * win = (CMyWindow*) hoster; win->SetTextL(text); }
3. Указатель на функцию inf передаём в dll-ку (вызовом какой-то из функций класса). Например:
В app: class CDllClass { //..... virtual void SetFuncHandle(int hoster,int handle)=0; //..... } //..... //.....
CDllClass * pDllClass; //... SET_INFO inf = SetInfo; pDllClass->SetFuncHandle((int)this,inf); --------------- Q: Скан коды клавиш, где их взять? И почему они иногда разные? ---- A: ХЗ. Я использую такую таблицу: //------ #define SC_KEY_ENTER 167 // OK #define SC_KEY_GREEN 196 // green phone #define SC_KEY_RED 197 // red phone #define SC_KEY_MENU 180 #define SC_KEY_PREV 164 // Левая софт-клавиша #define SC_KEY_NEXT 165 // Правая софт-клавиша #define SC_KEY_MULTI 133 // * #define SC_KEY_MULTI1 42 // Второй сканкод для звёздочки #define SC_KEY_NUM 127 // # #define SC_KEY_PENSIL 19 // ABC #define SC_KEY_PENSIL1 18 // Второй сканкод для ABC #define SC_KEY_LEFT 14 #define SC_KEY_RIGHT 15 #define SC_KEY_UP 16 #define SC_KEY_DOWN 17 #define SC_KEY_0 48 #define SC_KEY_1 49 #define SC_KEY_2 50 #define SC_KEY_3 51 #define SC_KEY_4 52 #define SC_KEY_5 53 #define SC_KEY_6 54 #define SC_KEY_7 55 #define SC_KEY_8 56 #define SC_KEY_9 57 #define SC_KEY_BS 1 // C //------ Как видно из таблицы - клавиши * и ABC имеют 2 сканкода. Объяснить это не могу, просто опытным путём было вычислено, что на некоторых моделях и даже в разных эмуляторах сканкоды этих клавиш могут быть такими. --------------- Q: В программе используются комбинации клавиш. Как сделать так, чтобы эти комбинации можно было в эмуляторе нажимать? ---- A: Правкой epoc.ini (%EPOCROOT%\\Epoc32\\Data\\epoc.ini). В этом файле есть строки типа Keymap <вирт. код> <Имя клавиши> Сюда можно добавлять свои клавиши. У меня получилось повесить кнопки эмулятора на буквенные клавиши, на остальные клавиши эмулятор почему-то не реагировал. Виртуальный код клавиши A - 65, код клавиши Z - 90, остальные буквы находятся в этом диапазоне. Вот названия кнопок эмулятора: EOkKey EClearKey EApplicationKey ESendKey // Зелёная трубка EEndKey // Красная трубка ELeftSoftKey ERightSoftKey EShiftKey // Карандаш ELeftKey ERightKey EUpKey EDownKey ESideKey EGripOpen EGripClose E1Key E2Key E3Key E4Key E5Key E6Key E7Key E8Key E9Key E0Key E*Key E#Key Таким образом, чтобы повесить, например, кнопку ОК на клавишу Y, нужно написать Keymap 89 EOkKey, зелёную трубку на O - Keymap 79 ESendKey . Теперь, нажав одновременно O и Y - получаем в эмуляторе нажатие клавиши GREEN+OK --------------- Q: Хочу портировать программу! Что для этого нужно? ---- A: Консольные программы, написанные на C портируются достаточно легко - в поставке SDK есть порт библиотеки libc (%EPOCROOT%\\Epoc32\\include\\libc). Полное описание можно прочитать в топике Porting справки SDK (наберите это слово в поисковике справки). Всего остального в стандартной поставке нет - так что не мечтайте написать в заголовке #include и получить безошибочную компиляцию. Тем, кто хочет занимается портированием, рекомендуется полазить по sourceforge.net и поискать ещё какие-то порты программ под симбиан - вдруг повезёт, и окажется, что кто-то сделал за вас большой кусок дурной и нудной работы!