#define STRICT
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define NOMINMAX
#define WINVER 0x0600
#define _WIN32_WINNT WINVER
#include <Windows.h>
#include <process.h>
extern "C"
{
#include "luaconf.h"
#include "lua.h"
#include "lauxlib.h"
}
#pragma comment(lib, "lua5.1.lib")
// здесь будет храниться ссылка на стейт нового потока.
// глобальная переменная - плохое решение, но для демки сойдет,
// более интересные варианты только добавят ненужной здесь сложности
static int tref = LUA_NOREF;
// это "полезная" функция, выполняемая в новом потоке
static void some_useful_function(lua_State * s)
{
// показываем сообщение о запуске
lua_getglobal(s, "message");
lua_pushliteral(s, "Эта функция выполняется в новом потоке. Выполняется, выполняется...");
lua_call(s, 1, 0);
// три секунды имитируем бурную деятельность
::Sleep(3000);
// показываем сообщение об остановке
lua_getglobal(s, "message");
lua_pushliteral(s, " ...кончила выполняться.");
lua_call(s, 1, 0);
}
// это стартовая функция для нашего нового потока
static unsigned int __stdcall thrd(void * pvoid)
{
// сохраняем переданный стейт.
// обратите внимание, что в этом потоке мы работаем только со стейтом,
// созданным специально для этого потока. мы никогда не трогаем стейты
// других потоков и другие потоки не должны трогать наш стейт
lua_State * n = static_cast<lua_State *>(pvoid);
// вызываем "полезную" функцию, передавая ей свой стейт
::some_useful_function(n);
// освобождаем ссылку на свой стейт, чтобы коллектор мог его прибить. если
// этого не сделать, стейт доживет до закрытия квика даже после остановки
// запустившего нас [в огород] скрипта (т.е. будет утечка памяти)
luaL_unref(n, LUA_REGISTRYINDEX, ::tref);
::tref = LUA_NOREF;
// с этого момента коллектор имеет право прибить наш стейт когда хочет, т.е.
// для нас его уже не существует, хотя, возможно, где-то в дебрях квика он
// еще будет болтаться некоторое время
n = nullptr;
// сейчас мы вернем управление и поток будет прибит. это приведет к тому, что
// хэндл потока, на котором ждет наш main, перейдет в состояние signaled,
// функция WaitForSingleObject вернет управление и main будет разблокирован
return 0;
}
// это main для квика (внезапно сишный)
static int qmain(lua_State * s)
{
// создаем новый стейт для потока.
// стейт также появится на вершине стека s
lua_State * n = lua_newthread(s);
// создаем ссылку на стейт, чтобы коллектор случайно не прибил его раньше времени.
// функция также выдернет стейт n с вершины стека s, вернув стек s в состояние,
// в котором он был до вызова lua_newthread
::tref = luaL_ref(s, LUA_REGISTRYINDEX);
// создаем нативный поток и передаем ему созданный стейт n
unsigned int tid;
HANDLE h = reinterpret_cast<HANDLE>(::_beginthreadex(NULL, 0, ::thrd, n, CREATE_SUSPENDED, &tid));
if(NULL == h)
{
// в случае ошибки поток не создан, поэтому не забываем прибить ссылку на новый стейт,
// иначе он останется в памяти до завершения квика (утечка памяти)
luaL_unref(s, LUA_REGISTRYINDEX, ::tref);
::tref = LUA_NOREF;
luaL_error(s, "_beginthreadex failed");
}
// обратите внимание, что в текущем потоке трогать стейт n больше нельзя, у него теперь новый хозяин,
// который позаботится также и о его освобождении. поэтому мы сразу же обнуляем указатель на стейт,
// чтобы случайные попытки туда влезть вызывали крэш
n = nullptr;
// запускаем новый поток на выполнение
::ResumeThread(h);
// здесь main может делать что-то другое, второй поток работает параллельно. но
// перед тем, как из мейна выйти, нужно убедиться, что все дополнительные потоки уже завершены.
// по-хорошему им сначала надо как-то посигналить "все бросай и на выход бегом", а уже потом ждать, но
// мы не будем лезть в дебри в рамках простой демки. поскольку нам в main особо делать нечего, мы сразу
// переходим к ожиданию завершения второго потока. попробуйте закомментировать следующую строку, если
// хотите посмотреть, как через три секунды к квику придет внезапный полярный зверек
::WaitForSingleObject(h, INFINITE);
// не забываем закрыть хэндл потока, иначе он доживет до закрытия квика (утечка хэндла)
::CloseHandle(h);
return 0;
}
extern "C" __declspec(dllexport) int qtest(lua_State * s)
{
// мы хотим, чтобы в качестве колбека main работала наша сишная qmain
lua_pushcclosure(s, qmain, 0);
lua_setglobal(s, "main");
return 0;
}
MikhaZz написал: но не подумал о том чтобы по простому там имя подправить
Там имя в каждом экспорте дублируется, руками править тяжко, проще заново сгенерировать .lib из переименованной длл. Пишете простой батничек
Код
@echo off
setlocal enabledelayedexpansion
for /f "tokens=1-4" %%1 in ('dumpbin /exports %1') do (
set /a ordinal=%%1 2>nul
set /a hint=0x%%2 2>nul
set /a rva=0x%%3 2>nul
if !ordinal! equ %%1 if !hint! equ 0x%%2 if !rva! equ 0x%%3 set exports=!exports! /export:%%4
)
for /f %%i in ("%1") do set dllpath=%%~dpni
start lib /out:%dllpath%.lib /machine:x64 /def: %exports%
и запускаете под visual studio command prompt (x64) с именем нужной либы. Генерируется .lib и .exp, второй можно сразу в корзину бросать.
Цитата
MikhaZz написал: лучше брать правильные .lib файлы
Конечно желательно. Вон тут недавно вопрос был про длл от стокшарпа, глянул в нее, а она к qlua.dll прилинкована. А этого нельзя делать, только к lua5.1.dll. В свое время написал небольшой хост, тксть недоквик для бедных, чтобы свои длл туда грузить и гонять под отладчиком, так вот если его линковать с квиковской qlua.dll, хост не завершается нормально, висит чего-то ждет, а с квиковской же lua5.1.dll все нормально. При том, что вторая таки подгружает первую и еще несколько квиковских длл.
Sergey Gorokhov написал: Ошибка описанная в данной ветке форума еще не исправлена, при выходе исправления здесь будет соответствующее уведомление.
Это понятно, но вот поведение-то изменилось волшебным образом, на это и хотел обратить внимание. Впрочем, до 8.5 уже недолго осталось, а там поглядим, как оно все будет.
MikhaZz написал: Выяснил, что когда собираются модули, то они линкуются к имени библиотеки
Цитата
MikhaZz написал: Для линковки использовал эти библиотеки
На самом деле для линковки сама по себе длл вообще не нужна. Нужна соответствующая .lib, а в ней по сути только имя длл и секция EXPORTS без конкретных адресов. Поэтому у вас прокатывает фокус: линкуете с длл из луа, а в рантайме подгружается длл из квика. Можете сами посмотреть дампбином, адреса функций в них разные, а оно работает. Но лучше выдрать все же .lib из квиковской длл и линковать с ней.
Добавлю, как просто найти папку AppData текущего пользователя. В адресной строке проводника наберите %APPDATA% и нажмите Enter, проводник сам ее отыщет. А уж дальше придется самим.
Боюсь, искали буквально ) <username> это ваше имя пользователя, <appname> это имя папки, в которую установлен квик в Program Files, C:\Users в русской винде может выглядеть как C:\Пользователи.
В Program Files устанавливаются 64-битные программы, в Program Files(x86) - 32-битные. Насильно перемещать их не стоит, хотя и возможно теоретически. А конкретно квик лучше установить в C:\QUIK, или как-нибудь по-другому папку назвать, по имени брокера, например. В Program Files он нормально работать не будет.
Имена и пароли будут действовать, видимо. Я не помню, честно говоря, как там в демке с этим дела обстоят, имена-пароли намекают, что как-то не так, как в боевом. По идее, ничего случиться не должно. Просто не сносите пока первый вариант, а поставьте заново в другую папку (как выше предлагал, непосредственно в корень диска), если все заработает, снесете старый.
Владимир написал: Папки QUIK\dmp. в установленной программе не нашёл.
Если квик установлен в Program Files и работает без повышения прав, он не сможет под себя написать, в этом случае винда делает финт ушами и все, что программы пишут под себя, перенаправляет в папку c:\Users\<username>\AppData\VirtualStore\Program Files\<appname>\, вот собственно попробуйте там поискать. Кстати говоря, установка в Program Files как раз и может быть причиной этого самого исключения, такая вот рекурсия забавная.
Михаил Е написал: в нём особо ничего нет, он фактическиобращается к dll'ке
Это как раз должно вас пугать, а не успокаивать. А конкретно эта дллка дотнетная еще впридачу, это и ответ на вопрос. Дотнет-то лучше знает, что кому нужно, вот квику, говорит дотнет, до смерти не хватает dpi awareness, и пофиг ему, что квик такого в манифесте не заявлял.
Впрочем, можете квик не насиловать, она даже под консольным луа падает на тестовом скрипте из поставки, откуда очевидно, что дело не в квике. Доходит вот докуда
Скрытый текст
Дальше мне рыть лень, это уже работа какая-то получается )
Определенно, некоторые работы были проведены. Теперь (8.3.2.4) и ошибка в мейне приводит к утечке. Скрипт:
Код
message("Before body")
t = newproxy(true)
mt = getmetatable(t)
mt["__gc"] = function(self) message("Garbage collector") end
function OnInit()
message("OnInit")
end
function main()
message("main")
error "Error in main()"
end
Ожидание: Before body - OnInit - main - Garbage collector. Если ошибку закомментировать, так и будет. Если оставить, то Реальность: Before body - OnInit - main - ??? Повторный запуск: Garbage collector - Before body - OnInit - main - ???
С нетерпением ждем новой версии луа, там ведь сразу уже нормально все будет, правда?
Я б для начала посмотрел в система - соединения, одинаковые ли адреса и порты в обоих квиках? Виндовый файрвол как настроен, разрешены ли исходящие подключения, не соответствующие ни одному правилу? Если нет, есть ли разрешающее правило для нового квика? А вообще вы б хоть написали, что вам квик говорит, он может "не соединиться" тысячей и одним способом, и все по разным причинам.
Коля Маржин написал: while status == nil sleep (10)end
Так он не может, а сто процентов зациклится. Статус же не обновляется сам по себе. Но и речь не о подписке в цикле, а о получении данных. Вот в соседней ветке образец есть, и счетчик там используется, его можно приспособить и для защиты от зависания навечно.
Коля Маржин написал: Subscribe_Level_II_Quotes("SPBFUT", "SiH0") я правильно использовал
Вроде правильно. Только подождать надо после подписки, не сразу getQuoteLevel2 дергать, а то заказанное еще не приехало скорей всего. Или в цикле со слипами подергать, пока не приедет, или в колбек OnQuote засунуть, там уж точно что-то приехало, раз колбек дернули.
Nikolay написал: Я не смотрел в код. Надо посмотреть значит, да.
Заодно и в мейкфайл посмотрите, там кое-что генерируется из луа с помощью luac, получается *.lo, а потом с помощью bin2c из него получается *.loh. Так вот в мастере luacom5.lo уже лежит готовый. Очевидно, мейкфайл его пропустит (оставит как есть), а как есть он, сдается мне, 32-битный.
Nikolay написал: плюс что-то с кодировкой символов
А чем компилировали? Нынче по стандарту сишные-плюсовые файлы должны быть в utf-8, соответственно gcc, например, строки так и воспринимает, а под квик надо в 1251. По-хорошему в utf-16 надо конечно, но тут луа со своими однобайтовыми строками выбора не оставляет.
Кстати говоря, когда приложение падает без дампа и без сообщения, тупо оп и нету, это обычно повреждение стека. С учетом, что без длл квик не падает, можно поглядеть на наличие/отсутствие __stdcall у чего-нибудь в либе. Это если отбросить уже совсем очевидные вещи типа бесконечной рекурсии и убитого стека "небезопасной" строковой функцией (а в либе ворнинги о них выключены, то есть по-видимому используются только так).
Чтобы "закрылся" скрипт, надо чтобы закончился мейн. Чтобы закончился мейн, надо выйти из цикла, в котором он вертится. Чтобы выйти из цикла, надо в нем проверить is_run и если там false, то и выйти. Вы ж проверяете только свое EnterInPos, соответственно ваш мейн плюет на ваше же пожелание "пора выходить", выраженное установкой is_run в false. Уж я не знаю, как еще подробнее объяснить.
Забавно, что раньше такого не было, линия спокойно себе уезжала за границу окна. Кому-то помешало, попросили улучшить. Как говорится, бойтесь своих желаний.
Устанавливаете в своей функции is_run и потом нигде ее не проверяете, поэтому и не работает. Ваша задача как-то мейну сообщить, что надо выйти из цикла, а не волшебное слово is_run упомянуть.
Закомментированная часть так, как написана, работать не будет по простой причине: в первом условии, если время больше 13:05, выполнилась первая ветка, дошла до return и на этом все. Если время меньше 13:05, оно заведомо меньше и 13:55 из условия второй ветки, поэтому вторая ветка не выполнится никогда. А если бы выполнилась, подвесила бы скрипт на 10 минут, так не стоит делать, хотя и не смертный грех.
Алексей написал: (1 Создает новый поток, толкает его в стек и возвращает указатель на lua_State, который представляет этот новый поток.
Таки нет, оно вообще никакой поток не создает. Оно создает стейт для нового потока, и вы когда с ним вызываете lua_pcall, вы выполняете вызываемую функцию в том же самом потоке, только в другом стейте. Вам надо этот стейт передать теперь новому нативному потоку (а не основной стейт, как у вас было). Основной стейт из нового потока вообще трогать нельзя.
Если задачей было сократить поголовье сишников, то задача решена успешно, половину свезли в дурку, вторую в кардиологию. Код у вас "не всегда находит нужную функцию", потому что никакой синхронизации нет, эти ваши while это мертвому припарка. В частности, пока вы в своем while ждете чудес, основной поток мог уже вообще завершиться, не находите? Квик ваши луа-конструкции при этом зачистит, а нативный поток так и останется тарахтеть в фоне до второго пришествия, точнее, пока не случится access violation и обвалит весь квик. По идее, надо lua_newthread вызвать в главном потоке, заполнить ему стек чем вам там нужно, и уже потом отдать созданный стек новому сишному потоку. И в основном потоке перед завершением (основного потока) дожидаться всех вторичных, а не просто detach() и живи как хочешь. Затем, вы делаете lua_xmove в цикле, который выполнится неизвестно сколько раз. Сколько значений вы выдернули в итоге из основного стека в новый? При этом основной поток продолжает работать параллельно и что-то там пихает в свой стек, а вы у него из-под носа это выдергиваете. И т.д. и т.п.
Уведомление о необходимости обновления торговых терминалов в связи с изменениями на срочном рынке Московской биржи, Список проблем при работе устаревших версий QUIK после обновления торговой системы срочного рынка МБ
Тейк-профит квиковский трейлить пытается, а стоп просто выкидывает заявку как ее ввели. Просто надо ставить защитный спред, чтобы заявка сразу по рынку исполнилась, но, с другой стороны, не скользнула слишком уж далеко в неудачном случае. А так даже если там лимитник бы стоял, никто не гарантирует, что его бы залили, даже если цена на этом уровне была, там мог поверх айсберг стоять, например.
Уведомление о необходимости обновления торговых терминалов в связи с изменениями на срочном рынке Московской биржи, Список проблем при работе устаревших версий QUIK после обновления торговой системы срочного рынка МБ
Уведомление о необходимости обновления торговых терминалов в связи с изменениями на срочном рынке Московской биржи, Список проблем при работе устаревших версий QUIK после обновления торговой системы срочного рынка МБ
Дмитрий написал: небольшое обновление для последней 6 версии
уже выпущено и называется 8.3.2.4. Шутки шутками, но проблема шестой версии, как выше (почти) прямо написано, не в том, что она отправляет номера в даблах, а в том, что она их принимает в даблах, а это в рамках версии никак не исправить. И отсюда же следует, что
Цитата
Максим написал: вообще даже правой кнопкой мыши не снимется
Андрей написал: Например: купили дну акцию за 20р, затем вторую за 30р - среднее 25.Продали одну акцию. Какое теперь среднее?
Не надо среднее считать вообще. Когда продали одну акцию, выбыла по ФИФО первая, купленная за 20. Разница цены продажи и 20 пошла в налогооблагаемую базу. Продали второй раз - выбыла вторая акция, купленная за 30, разница цены продажи и 30 пошла в налогооблагаемую базу. В том числе, если в убыток продали, уменьшила ее. А когда срок подошел, от текущей налогооблагаемой базы сосчитали 13%, это ваш налог. Это если "в целях понимания" в лоб по фифо считать. На практике все бэк-офис брокера делает (не квик) задним числом по отчетам, либо вы сами, если юрик.
Проще на примере. Купили сто литров солярки, вылили в бочку. Потом еще купили сто литров в другом месте и по другой цене, вылили в ту же бочку. Как бочка помнит, какой литр по какой цене куплен? Никак, в ней 200 литров и все. То же самое здесь. Купили 100 акций - записали на счет депо. Купили еще сто акций - добавили на тот же счет депо. Теперь там 200 акций и это вся объективная информация. Цены покупки, средние по ним и прочее - теперь это исключительно мысленные конструкции. Налоговая имеет свое мнение, как надо эти конструкции конструировать, и говорит: думайте ФИФО в целях налогообложения. А для себя можете думать как угодно.
А система в этом никак и не разбирается, акции абсолютно одинаковые, за сколько бы вы их ни купили. При расчете налога учитываете бумаги способом FIFO и все.
Latrop написал: Можно просто пробежать по всем метаданным открытых таблиц тиков
А по тиковым графикам? А по заказавшим скриптам? А по экспорту тиков во что там осталось еще, в велс и амиброкер? А у этих перечисленных вообще какая-то метадата есть ли? Да и у таблиц-то есть ли такая метадата? Квику ж за двадцатку лет уже, кто тогда думал о каких-то там фильтрах, это ж все поверх налеплено аццким усилием мысли.
Latrop написал: надежно определить, есть ли бумага в листинге текущей сессии или нет.
Если бумага возвращена из getClassSecurities, она есть в листинге сегодня, разве нет?
Цитата
Latrop написал: зачем приходится разбирать нутро dat-файлов квика?
Для общего развития в основном. Практического применения этому не может быть, при работающем боевом квике в его файлах ковыряться не есть хорошо, а при неработающем можно просто файлы в архив скопировать, потом подкладываем их квику и открываем. Все уже сделано аркой, и парсинг, и отображение, и экспорт куда угодно.
Цитата
Latrop написал: И можно где-то раздобыть уже готовые парсеры этих dat-файлов, на C# напр ?
Не слыхал о таких.
Цитата
Latrop написал: ежедневные копии квиков за кучу лет
А что из них вытаскивать? ТВС? Дык вон оно все на финаме лежит даром, качать не перекачать.
Latrop написал: Добавить возможность отключения это автоматики "для домохозяек" :)
Им брокер должен отключать (невключать) на своей стороне, если у него на пару лишних стоек денег нет. Вот идею ограничить фильтры уровнем классов я поддерживаю всеми руками, а мешать домохозяйкам использовать покупные/заказные скрипты - идея плохая, они завалят и разработчика скрипта, и этот форум вопросами "куда все пропало".
Цитата
Latrop написал: Зачем еще дополнительные нагромождения логики автоматики и явных настроек?
Это единственная альтернатива счетчику ссылок у каждой галки. Либо так, либо как есть, либо переделывать весь функционал с нуля, на что арка вряд ли пойдет.
Latrop написал: Там же в Квик приходит и тот же SECTYPESTATIC
Вот в этом я не уверен, мне неизвестно соответствующее поле в sec.dat. Как насчет вывести тип бумаги из имеющихся параметров от getSecurityInfo? Наличие базового актива -> дериватив, наличие страйка -> опцион и т.д.
Александр М написал: Зачем его в double переводить?
Значит, я исходный посыл не так понял. Конечно не нужно переводить. Главное, как выше написали, как-нибудь неожиданно для себя не перевести:
Цитата
In a conversion from integer to float, if the integer value has an exact representation as a float, that is the result. Otherwise, the conversion gets the nearest higher or the nearest lower representable value. This kind of conversion never fails
Latrop написал: Т.е. полный список инструментов в терминале заказывается и обновляется всегда? Независимо от каких-либо настроек параметров?
Там внутри бумаги по индексу в sec.dat идентифицируются (возможно, не везде, но кое-где точно). То есть свежий sec.dat по-любому надо в начале сессии тащить целиком, иначе ничего не будет толком работать. Соответственно, что в нем приехало, оно уже приехало, а там как раз вот это вот все, возвращаемое getClassSecurities. Кстати говоря, в моем поделии, работающем с биржей напрямую, тоже пришлось весь листинг тащить, прежде чем что-то другое делать. И я на квик как образец для подражания не смотрел, так оно само вышло и, видимо, иначе никак.
Александр М написал: вещественные числа двойной точности (double 64-bit)
Только там под мантиссу 52 бита оставлено, откуда и все нынешние проблемы. Там еще старший бит неявный, подразумевается всегда единица, а если это не так, получается денормализованное число и т.д. и т.п., в общем в даблы 64 бита не влезают хоть тресни. Более того, никакие ухищрения вроде *reinterpret_cast<unsigned long long *>(&dbl) = 0xFFFFFFFFFFFFFFFFULL надежными не будут, дабл всегда может заехать в сопроцессор без уведомления, а тот его "подправит" под ожидаемый формат, да и сишный рантайм тоже ожидает дабл в виде дабла и может что-нибудь с ним сделать под ковром.
Вообще-то я тоже не признал бы такое поведение ошибочным с точки зрения луа: бумага не заказана, заказ запрещен фильтром, луа тыкается в строку, строки нет, заказывать нельзя, ок, держите нил. Логично. С точки зрения видимой таблицы разве что, да и то скорей "особенность поведения", это же вью, а не модель. Вот что луа часто от "модели" уклоняется в угоду то ли "упрощению", то ли сокрытию внутренней кухни, это вот хуже ящитаю.
Александр М написал: 2. Тип полей во всех текущих функциях, которые в качестве параметров требуют ввода номера заявки или сделки или возвращают номер заявки или сделки, НЕ поменяется.
По-моему, весь смысл перехода на 5.3 в том, чтообы тип этих полей поменялся. В NUMBER больше 51 бита не впереть даже на 5.3.
Latrop написал: Делать догадки, что проблема тут в синхронизации настроек заказа сделок и открытых окон не буду, для простоты описания.
А там и гадать нечего, настройки фильтров лежат в info.ini, можно на них посмотреть. Просто список установленных галок по каждому классу, а если выбраны все из класса, то ALL. Никакого счетчика ссылок у галки нет, следовательно, квик физически не может знать, сколько разных подписчиков эту галку "взвели" и был ли среди них юзер через диалог, или только автоматика. Соответственно, сбрасывать ее при отписке - это гарантия глюков при более чем одном подписчике.
Цитата
1. Предлагается оставить только настройки получения тиков по классам, без фильтров по инструментам.Настройки эти задаются явно в диалоге заказа данных.
Полностью поддерживаю. Технически это будет выглядеть, как CLASS=ALL или CLASS=<пусто> в info.ini, без детальных списков, т.е. изменения минимальные. Ну, в диалоге галки лишние поубирать еще.
Цитата
Никаких автоматических заказов тиков по открытым таблицам или графикам быть не должно.Если очень хочется сделать красиво, то надо просто фильтровать доступные настройки таблиц и графиков исходя из настроек заказа данных по тикам.
Тут не поддерживаю. Вы не учитываете, что подписчиком может быть луа-скрипт, ему "красиво" не покажешь. Либо надо будет добавлять в луа кучку функций для прямой работы с фильтрами, хотя бы чтобы спросить "а по этому инструменту мы зафильтрованы или нет?", либо таки автоматически поднимать галку при подписке (но никогда не сбрасывать потом).
Andrey Bezrukov написал: Правильно понимаем, что ожидается автоматическая очистка списка инструментов для заказа обезличенных сделок при отсутствии таблиц обезличенных сделок и тиковых графиков?
Против такого функционала. В теме, на которую выше ссылался, как раз предлагалось запретить понижение фильтров ТВС при закрытиях/отписках, и это правильно. Если трафик начнет напрягать, юзер всегда может пересмотреть свои настройки фильтров, а вот если что-то перестало ехать, он этого может не заметить вовремя, особенно если ехало не на экран, а в скрипт. Если же у него все закрыто, ничего и так не едет, стоят ли галки в фильтрах или нет. То есть, резюмируя, если какая-то галка поставилась (вручную или автоматически), то она должна оставаться установленной до тех пор, пока юзер сам руками ее не сбросит через диалог.