Jump to content
Sign in to follow this  
FortRoss

Вопросы по созданию приборов на С++

Recommended Posts

pelement = (PELEMENT_STATIC_IMAGE)(pgauge->elements_list[0]);

hdc = pelement->hdc;

 

но это ты доступишься до нижнего элемента в дереве, а вот будет-ли он полной картинкой - вопрос двадцать пятый. ещё одно замечание: hdc вроде можно достать только у тех, кто декларирован с флагом IMAGE_CREATE_DIBSECTION. возможно после декларации твои нули исчезнуть и появится буфер.

Edited by icebear
  • Upvote 1

Share this post


Link to post
Share on other sites

GAUGESLINKAGE * pAdr;

HINSTANCE hDLL;

 

hDLL = LoadLibrary("pnk_154m_3_024.gau");

pAdr = (GAUGESLINKAGE *)GetProcAddress(hDLL, "Linkage");

HBITMAP hb = LoadBitmap(hDLL,MAKEINTRESOURCE(4976));

DeleteObject(hb);

FreeLibrary(hDLL);

 

Но это когда мы точно знали что номер битмапа 4976. А как узнать этот номер? Наиболее быстрый способ это подсмотреть в отладчике в таком коде (перебирает все элементы)

 

GAUGESLINKAGE * pAdr;

HINSTANCE hDLL;

hDLL = LoadLibrary("pnk_154m_3_024.gau");

pAdr = (GAUGESLINKAGE *)GetProcAddress(hDLL, "Linkage");

PELEMENT_HEADER el_list;

 

int i=0;

while (pAdr->gauge_header_ptr!=NULL)

{

el_list = *pAdr->gauge_header_ptr->elements_list;

while (el_list!=NULL)

{

if (el_list->next_element!=NULL)

el_list = *el_list->next_element;

else

el_list = NULL;

}

 

i++;

 

}

Share this post


Link to post
Share on other sites

Не-не, дело не в том, что бы достать ресурс из длл, а в том, как получить моментальную картинку гауги. Например снять копию текущего состояние какого-нибудь MFD.

Share this post


Link to post
Share on other sites

Не-не, дело не в том, что бы достать ресурс из длл, а в том, как получить моментальную картинку гауги. Например снять копию текущего состояние какого-нибудь MFD.

Именно так!

 

Спасибо за подсказку про IMAGE_CREATE_DIBSECTION! Получил "pelement->hdc;" и прочие указатели, щас пытаюсь вытащить оттуда картинку.

Share this post


Link to post
Share on other sites

Не знаю, может быть кому пригодиться.

 

Проблема:

Если прописать прибор и в ВК и в 2D кабине, то после того, как побывали хоть раз в ВК и хоть раз открыли 2D окно, в котором он прописан в 2D кабине - CallBack прибора с service_id == PANEL_SERVICE_PRE_UPDATE будет вызываться дважды. Это очень плохо. Собственно то, что некоторые программисты могут не учитывать этот факт, приводит к тому, что прибор нельзя прописать и в 2D кабине и в ВК, когда в PRE_UPDATE, например, что-нибудь инкрементируется (т.е. когда в вычислениях есть рекурсия по данным). Понятно, что в таком случае, инкрементироваться все будет дважды.

 

Если я ничего не упустил, то выйти из того положения можно таким вот образом:

MODULE_VAR main_module_tick18 = { TICK18 };
FLOAT64 get_tick18() { return main_module_tick18.var_value.n; }
FLOAT64 main_module_tick18_prev = 0;
...

// Update уровня логики
void FSAPI logic_level_update(PGAUGEHDR pgauge, SINT32 service_id, UINT32 extra_data)
{
// Используем только PANEL_SERVICE_PRE_UPDATE
// (инициализация и деинициализация в module_init и module_deinit)
if (service_id != PANEL_SERVICE_PRE_UPDATE)
	return;
// Выполняем код уровня логики один раз каждый тик.
// Вне зависимости от того прописан ли прибор уровня логики и в ВК и в 2D кабине.
lookup_var(&main_module_tick18);
if (main_module_tick18.var_value.n == main_module_tick18_prev)
	return;

// to do
// ...

// Обязательно запоминаем номер текущего тика
main_module_tick18_prev = main_module_tick18.var_value.n;
}

 

Собственно в

// to do

// ...

и крутим всю логику. Запускаться будет она один раз каждую 1/18 секунды, так как, если TICK18 у нас не изменился, то значит мы сейчас сидим в CallBack-е второго экземпляра прибора, а в этом случае мы CallBack-функцию прибора покидаем.

 

Это могут быть просто некоторые короткие вычисления, необходимые для данного прибора.

Или это может быть вызов из невидимого прибора (который прописываем и в ВК и в 2D кабине) основной функции (метода) всей страшно сложной логики, страшно сложных систем, какого-нибудь приборного комплекса.

 

...

(В ВК, если не ошибаюсь, нет никакой разницы, куда прописать невидимый прибор логики ([VcockpitXX]), CallBack всегда будет вызываться симом. В 2D, прибор, который будет крутить весь уровень логики необходимо прописать в окно, которое обязательно открывается автоматом при входе в 2D кабину. Как правило это окно с ident=MAIN_PANEL)

Edited by serg_p
  • Upvote 1

Share this post


Link to post
Share on other sites

Серег, ты забыл одну маленькую вещь: это тяжелое наследие FS2004. В FSX это решается простым вынесением логики в in-process .dll

Share this post


Link to post
Share on other sites

Во первых - это очень простой вариант, который будет работать и в FS9. Хотя в FS9 можно конечно сделать свой модуль и подсесть на системное событие, которое срабатывает вместе с PANEL_SERVICE_PRE_UPDATE. Но для чего городить огород, если все можно дешево и сердито реализовать в виде приборов.

 

Во вторых.

Как я понял, для FSX, ты имеешь в виду случай, когда dll прописывается в DLL.xml, что бы она загружалась вместе с симом. Но здесь мне приходит на ум только один вариант. С помощью функции SimConnect-а - SimConnect_SubscribeToSystemEvent, подписаться на системное событие "6Hz". Но! Хоть, как говорит MS, джой читается именно с этой частотой (This is the same rate that joystick movement events are transmitted) и тут для отработки ввода от джоя вроде бы больше и не надо, этой частоты обновления скорее всего не хватит для реализации собственных ПИД регуляторов, фильтров, следящих систем и т.д. 18 герц уже может и нормально, но 6 герц для своей навороченной логики - это маловато.

 

Ну и вообще, мне кажется, что лепить свою dll, которая будет висеть в памяти, пока сим загружен - как-то не ахти. Причем тут ведь не важно, используешь ли ты модель в данный момент, для которой ты прилепил к симу дополнительную dll или не используешь, dll будет висеть в памяти. Тут конечно можно, наверное, определить загружен ли самолет или нет, и в зависимости от этого уже создавать/убивать необходимые для работы структуры данных, но, по моему мнению все это гемор.

 

По моему мнению гораздо проще и надежней все реализовывать в виде приборов. Тут и обновление логики четко синхронизировано с отображением и частота обновления (18Гц) вполне приемлема для реализации всяких своих фишек и dll, в которой реализуются приборы, загружается и выгружается вместе с самолетом.

Edited by serg_p

Share this post


Link to post
Share on other sites

Два вопроса: в симе действительно принудительно крутиться цикл неактивного элемента? Т.е. по сути нельзя находится одновременно в ВК и в 2Д, но можно в ВК открыть какую-либо панель, на которой юзается прибор, находящийся в ВК. Но это частный случай я бы сказал, а вот в нормальном состоянии неужели два цикла? Сергей, при каких условиях ты наткнулся на это? Второй вопрос: разве ВК обновляется так же с "частотой 18Гц"?

Edited by icebear

Share this post


Link to post
Share on other sites

Почему два цикла?

Цикл один.

В каждой итерации пробегаются по очереди все приборы, прописанные в Panel.cfg, начиная с [Window00] и заканчивая последней [VcockpitXX]. Соответственно, если, например, у тебя прибор прописан в двух 2D окнах, плюс еще в какой-нибудь [VcockpitXX] - его CallBack будет вызываться три раза, если ты зашел в ВК и плюс к этому хоть по одному разу отобразил оба 2D окна. Т.е. сим начинает крутить CallBack прибора только, если он его должен визуализировать. Причем, после того, как сим визуализировал экземпляр прибора, его Callback будет всегда вызываться симом, вплоть до окончания полета, вне зависимости от того будет ли еще отображаться этот экземпляр или нет.

 

CallBack-и приборов с одним STATIC, с флагом HIDDEN, тоже крутятся, несмотря на то, что битмап прибора не отрисовывается.

 

Все это можно легко проверить в отладчике.

Edited by serg_p

Share this post


Link to post
Share on other sites

господи. опять. Ребят, это классическая задача по реализации модели "Model-View-Container". И в симе она решается на раз. Одинажды развязав логику из прибора во внешние модули (они даже не обязаны быть в виде DLL, достаточно реализовать их как синлтоны), лишь бы структуры, отвечающие за логику находились ВНЕ блока GAUGE, и все проблемы 2d/VC и двойного вызова UPDATE решаются разом. Да пусть у вас будет хоть десяток приборов-представлений, модель будет считатся единожды.

 

сколько я уже для сим не пишу? года три? или больше? решили эти задачи еще лет 6-7 назад, объясняли и разжевывали неоднократно, как сделать, а воз и ныне там :/

Share this post


Link to post
Share on other sites

Ага, здорово!

 

Спасибо за Singleton.

 

Тока можно вопросик?

View у нас сидит в штатных приборах и собственно тут CallBack уже для прибора часто может быть не нужет,может вполне быть так, что потребуются лишь CallBack-и визуальных элементов.

 

Но!

 

Логику крутить от своего таймера (ну ли в отдельном, своем потоке делать sleep в цикле потока)?

Или подписаться через SimConnect на системное событие "6Hz"?

Но тут, может не хватить частоты.

 

Ну и еще один вопросик.

Все же "Model-view-controller" для одиночного приборчика, который должен решить ряд задачь может слишком расточительная штука?

Вот сейчас передо мной стоит конкретная задача. Сделать код для Konsni, который будет реализовывать ряд задачь, типа записи значений из L:переменных в Simulation Variables топливных баков. Городить все выше описанное, как то слишком сложновато для таких задачь.

Edited by serg_p

Share this post


Link to post
Share on other sites

там накладных расходов-то - пара дополнительных вызовов. Даже для небольшого приборчика (но уже с кастомной логикой) оправдано. Тем более, что даже если по каким-то причинам у сим у вас запросит повторную загрузку прибора - то получит он тот же экзепляр уже загруженной DLL (а gau есть DLL по определению), с проинициализированными данными.

 

простейших реализаций паттерна "синглтон" (он же "одиночка") в сети чуть менее чем дофига...

Share this post


Link to post
Share on other sites

Отлично, Денис!

Большое спасибо!

Вы всегда задаете правильное направление.

Попробую решить задачку именно так.

Edited by serg_p

Share this post


Link to post
Share on other sites

На всякий случай. Мож пригодиться кому.

Сейчас откопал в инете классную книгу:

Андрей Александреску, Современное проектирование на C++

 

Там много чего полезного, в том числе и про Singletone.

 

 

 

P.S.

Подытожу.

Основная задача - вывести логику систем из дефолтной цепочки. Здесь мы можем сделать фейковый прибор (невидимый прибор, в котором не будет дефолтного CallBack) и разметим его, где-нибудь в Panel.cfg. Тут уже неважно где. Если из dll (gau) прописан в Panel.cfg хоть один прибор - dll (gau) будет загружена и обязательно будет вызваны DllMain и module_init при загрузке и module_deinit при выгрузке. А в module_init мы можем замутить все, что угодно. Собственно об этом и говорил Денис (FortRoss) в первом посте этой ветки. К тому же, делая фейковый прибор, мы автоматически получаем все, что нам предоставляет gauges.h. Естественно в FSX ничего нам не мешает сюда подрубить еще и SimConnect.

 

А если использовать Singletone, то нам и module_init может не понадобиться для инициализации уровня логики. Тут вообще получается, что наш фейковый прибор нам потребуется исключительно для того, что бы загружалась наша dll (gau) вместе с самолетом. Конечно же здесь же, в этой dll, мы можем забабахать и уровень представления. Но он будет связан с уровнем логикой только через вызовы функций (методов), осуществляющие обмен даными между этими уровнями.

 

 

Вопрос - чем крутить нашу логику?

 

Мне сейчас приходят на ум два варианта:

1 можно сделать свой поток и Sleep-ом внутри цикла потока задать частоту запуска нашей логики;

2. можем просто использовать собственный таймер.

Edited by serg_p

Share this post


Link to post
Share on other sites

Серег, ну не Sleep'ом точно. Сейчас вот смотрю в сторону timer queues. И еще непонятно,а не выгрузит ли сим .dllку гауги, если не найдет Linkage?

Edited by gosha-z

Share this post


Link to post
Share on other sites

Серёга, стой. Не туда тебя несёт, какой слип? У вас там вроде есть такая штука как DispatchProc, разве не оно? И ещё, фейковый прибор в десятке?! Зачем, если в девятке уже можно писать без?

 

Денис, а как в стандартной девятке отвязать логику (ну без использования chain_insert)?

Edited by icebear

Share this post


Link to post
Share on other sites

Денис, а как в стандартной девятке отвязать логику (ну без использования chain_insert)?

Так Серега же сказал - запускаться не из gauge callback, а из DllMain

Share this post


Link to post
Share on other sites

Серёга, стой. Не туда тебя несёт, какой слип? У вас там вроде есть такая штука как DispatchProc, разве не оно? ...

Да, это может пригодиться в FSX, если через SimConnect подписаться на системное событие "6Hz" отрабатывать его в DispatchProc. Но ведь я выше так же говорил, что частоты 6Гц может не хватить. Тогда тут нужно крутить логику чем-то своим. Либо в отдельном потоке, делая таймауты межу итерациями главного цикла потока Sleep-ом, либо делать свой таймер и садиться не него. Может быть есть еще варианты. Но смысл втом, что мы логику не сажаем в дефолтный цикл сима. Его можно использовать для уровня представления, естесвенно. Но логику мы выносим из него. Собсвенно это касается и FS9. И как я понял, Денис про это, как раз и говорил в первом посте этой ветки.

 

По поводу фейкового прибора.

Тебе ведь надо, как минимум загрузить dll. Тут два варианта.

1. Порописать свою dll в DLL.xml. Но тут, на мой взгляд, елси dll не типа FSUPIC-а (т.е. когда dll предназначена для какой-то конкретной модели самолета), лепить ее в DLL.xml неразумно.

.. Ну и вообще, мне кажется, что лепить свою dll, которая будет висеть в памяти, пока сим загружен - как-то не ахти. Причем тут ведь не важно, используешь ли ты модель в данный момент, для которой ты прилепил к симу дополнительную dll или не используешь, dll будет висеть в памяти. ...

2. Фейковый прибор. Я же писал выше. Он позволит хотя бы загружать/выгружать dll вместе с самолетом. Одно это - уже большое удобство.

Edited by serg_p

Share this post


Link to post
Share on other sites
... И еще непонятно,а не выгрузит ли сим .dllку гауги, если не найдет Linkage?

Дык, Игорь. Делая фейковый прибор мы как раз и прописываем его штатно в Linkage. А в приборе у нас будет один STATIC и то с флагом HIDDEN. Думаю, что в случае фейкового прибора должно быть все пучком.

 

Серег, ну не Sleep'ом точно. ...

А почему?

Ведь здесь речь идет собственно не о Sleep-е, а о том, что мы гоняем нашу логику в цикле. А Sleep используем лишь затем, что бы поток периодически засыпал, что бы он не грузил постоянно в пустую проц (просто нужно высчитать для себя на сколько миллисекунд мы будем усыплять наш поток). Тут ведь нам не нужно выполнять код реального времени. Да и сидя в дефолтном цикле сима, мы ведь не получаем точно 18 Гц, если система сильно загружена. Попробуй забубенить в CalBack-е что-нибудь несуразное, так сразу и увидишь как у тебя просел FPS, когда заработает прибор с этим CallBack-ом.

Edited by serg_p

Share this post


Link to post
Share on other sites

в module_init влезть в цепочку/повесить на таймер/запустить отдельным потоком (остаются вопросы синхронизации с симом, но это другой вопрос). ничто ж не мешает. Если уж не охота разворачивать макросы - действительно забодяжить даммик, в котором вызвать один раз код инициализации.

 

говорю же, задача развязки логики и представления решена давным давно, и странно, что этот вопрос поднимается в начале 12-го года

  • Upvote 1

Share this post


Link to post
Share on other sites

говорю же, задача развязки логики и представления решена давным давно, и странно, что этот вопрос поднимается в начале 12-го года

 

ну не думай про нас так плохо :) здесь вопрос не в использовании/знании паттернов, а в знании структуры сима. я думаю в начале 12-го людей в этой теме намного меньше народу, нежели в началае 6-го.

small-logo.png

Share this post


Link to post
Share on other sites

в module_init влезть в цепочку

 

В цепочку сообщений винды и писать рефреш модуля по образу WndProc?

Т.е. что-то типа

 

module_init: PostMessage("Запускай")

module_deinit: PostMessage("Убейся")

 

а сам модуль писать по типу WndProc/DefWndProc? хорошая идея

Edited by icebear

Share this post


Link to post
Share on other sites

плохая :)

 

имея то, что ты имеешь на руках (ну ты понял, да), вешаешся на штатную 18-игерцовую цепочку обновлений сима и не ломаешь себе голову со всем остальным.

Share this post


Link to post
Share on other sites

плохая :)

 

имея то, что ты имеешь на руках (ну ты понял, да), вешаешся на штатную 18-игерцовую цепочку обновлений сима и не ломаешь себе голову со всем остальным.

 

Хм. Ну я представлял себе именно как возможность вывести всё своё в отдельную длл и крутить его в собсном потоке, разговаривая с симконнектом. А что бы знать, когда инициально родится и когда умереть в нужный момент, использовать систему сообщений винды.

small-logo.png

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...