PDA

Просмотр полной версии : Сворачивание/разворачивание окна exe (Zinc)


kotmaker
14.08.2007, 16:42
Имеется следующая проблема. Экзешник цинковый открывается на полный экран, путем прописывание в первый фрэйм:

mdm.Application.maximize();

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

windowList = mdm.System.getWindowList();
main_name = "Тесты ПДД";
file_open = 0;
zakr = false;
for (i=0; i<windowList.length; i++) {
if (windowList[i][0] == main_name) {
num = i;
file_open++;
zakr = true;
mdm.System.setWindowFocus(windowList[i][1]);
} else {
if (windowList[i][0] == "My Flash Window") {
file_open++;
if (file_open == 2) {
zakr = true;
mdm.System.setWindowFocus(windowList[i][1]);
}
}
}
}
if (zakr) {
mdm.Application.exit();
}
насчет двойного цусловия поясню - почему-то если окно развернуто, то оно в getWindowList() прописывается как My Flash Window, а если свернуто в таск бар - "Тесты по ПДД"

Так вот проблема возникает, в том случае, если одно окно свернуто в таскбар, а второе открывается. Второе окно, проверяя открытые файлы, находит уже открытый файл с именем "Тесты ПДД" и переводит на него фокус. А после закрывает себя. Так вот фокус вроде бы переводится, кнопка первого окна становится внизу нажатой, но само окно не отображается. Если кнопку внизу нажать, происходит стандартная анимация сворачивания виндоуз, и кнопка отжимается. И лишь потом, когда нажимаешь на кнопку - срабатывает разворачивание. В чем может быть проблема, подскажите, пожалуйста.

PS
Окно сворачивается нажатием на кнопку с кодом:
mdm.Application.minimize();

alexcon314
14.08.2007, 20:58
Попробуй так:

mdm.Application.doEvents();
mdm.Application.enableExitHandler();
mdm.Application.onAppExit = exit;
mdm.Forms.MainForm.title = "form";
hwnd = mdm.System.Registry.load("AppHwnd");
if (hwnd && hwnd != "none") {
// шлем WM_SYSCOMMAND с wParam = SC_RESTORE и lParam = 1
mdm.System.sendMessage(hwnd, 0x0112, 0xF120, 1);
// ставим фокус
mdm.System.setWindowFocus(hwnd);
flag = false;
exit();
} else {
var wList = mdm.System.getWindowList();
var i = 0;
while (wList[i][0] != "form") {
i++;
}
mdm.System.Registry.save("AppHwnd", wList[i][1]);
flag = true;
}
function exit() {
if (flag) {
mdm.System.Registry.save("AppHwnd", "none");
}
mdm.Application.exit();
}

При запуске прога пишет в реестр хэндл своего окна. Второй экземляр при запуске читает из реестра этот хэндл и шлет мессаги на ресторе и сетфокус первому экземпляру, а сам отваливает. Первый экземпляр при закрытии вытирает из реестра хэндл.
Да, еще. незачем две проверки делать при выяснении хэндла окна. достаточно одной на формтитле.
Конечно, сохранять хэндл необязательно в реестр, просто это в данной ситуации удобно.

kotmaker
15.08.2007, 11:00
Спасибо огромное. Помогло! Моё почтение.

И сразу возникает вопрос. Дело в том, что хэндл из реестра не удаляется. И последующее запускание окна не приводит ни к чему. Скрипт находит себе подобных в реестре и закрывается. Даже если больше такого окна нет открытого. Так вот вопрос - как удалять инфу из реестра? И, даже если получится удалить из реестра, что будет в случае критического завершения программы.. например перезагрузке системы. В реестре инфа ведь все равно останется?

alexcon314
15.08.2007, 14:07
о работе с реестром см.
http://flasher.ru/forum/showthread.php?t=81193&page=6 пост №60
Совершенно правильный вопрос.
Хэндл при завершении работы (штатном) самого первого экземпляра меняется на запись "none". Удалять ключ AppHwnd совсем не обязательно.
Для нештатных ситуаций такой способ не подходит.
Поэтому

mdm.Application.doEvents();
formTitle = mdm.Forms.MainForm.title = "form";
appTitle = mdm.Application.title = "app";
var wList = mdm.System.getWindowList();
var appList:Array = new Array();
var i = 0;
while (wList[i][1]) {
if (wList[i][0] == formTitle || wList[i][0] == appTitle) {
appList.push(wList[i][1]);
}
i++;
}
hwnd = appList[1];
if (hwnd) {
mdm.System.sendMessage(hwnd, 0x0112, 0xF120, 1);
mdm.System.setWindowFocus(hwnd);
mdm.Application.exit();
}
Здесь все основано на том факте, что в списке окон wList окно второго экземпляра приложения находится выше чем окно ранее запущенного экземпляра. и при добавлении в массив appList хэндл уже запущенного окна (если таковое присутствует) оказывается под номером 1, а хэндл второго под номером 0. Действительно, должен признать, что в этом случае нужно проверять наличие в списке wList и титла на кнопке приложения в таскбаре: когда оно свернуто принудительно только так его можно найти. Поэтому присутствует строчка mdm.Application.title="...", где устанавливается титл на этой кнопке.
Должно работать. В принципе, это твой исходный вариант, только переработанный.
FormTitle и ApplicationTitle можно указать статически в самом компиляторе. Но в этом случае к ним не получишь доступ так просто. И придется писать в условии сравнения титлов сам титл. Не поручусь, что это всегда работает, особенно когда титл русский или необычные символы там есть. Поэтому, лучше назначать их динамически в коде.

kotmaker
15.08.2007, 16:24
Последний вариант срабатывал только в случае, если первое окно развернуто (не в таскбаре). Оказывается фишка в том, что если окно свернуто, то в getWindowList() оно отображается как "My Flash Application", а если развернуто - "form" (то есть так, как мы задали ему в mdm.Forms.MainForm.title = "form"). А решилось это просто. Добавил строчку

mdm.Application.title = "form";

и стало теперь и окно так называться, и кнопка внизу в таскбаре. И все встало на свои места. Спасибо тебе за помощь.

alexcon314
15.08.2007, 17:28
Вроде все то же и я писал, и код рабочий вроде...
Чего-то я не понял твой последний пост...
Кроме последних двух предложений :)

kotmaker
16.08.2007, 00:03
Какой-то я невнимательный, действительно. Сейчас читаю, что написал, и получается что глупо. Твой код действительно правильный :) Еще раз спасибо.

chingachgoog
25.03.2008, 19:22
Не понимаю, что эта строчка делает:

mdm.Application.doEvents();

?

alexcon314
26.03.2008, 12:20
если вы о примерах в этом топике, то как их автор должен признаться, что причина вставки этой строчки в код мной уже забыта :). помню что где-то без этой строчки чего-то не работало, а как включил - заработало. косяк был вобщем. речь шла об обработке системных сообщений посылаемых окну дочерней формы. точнее не вспомню сейчас. но с тех пор я не гнушаюсь вставлять эту строчку, если собираюсь работать с окном через send/postMessage. пардон за сбивчивые объяснения. если вспомню конкретный пример - выложу.

эта строчка судя по мануалу "заставляет" окно приложения обрабатывать любые сообщения из системной очереди.

вариант: выяснить запущен ли уже в данный момент экземпляр приложения можно при помощи LocalConnection

chingachgoog
26.03.2008, 14:52
Ну да, можно было бы что-то типа такого сделать


myData=new Date()
myData.getTime()
lc = new LocalConnection();
lc.send("lc_name", "methodToExecute", myData);

lc.methodToExecute = function(USL) {
if (String(myData)==String(USL)){
clearTimeout(TO)
}
};

lc.connect("lc_name");

lc.onStatus = function(infoObject) {
if (infoObject.level=='status'){
TO=setTimeout(function(){
fscommand("quit") // собственно любая функция закрытия
},50)
}
}


Но мне кажется это менее надежно чем код выше.

add:
хотя как знать...
оставил тут включенным цинк и запустил отдельно экзешник - он вырубился этим кодом! Т.к. цинк внутри себя (!) прокручивает флешку и она оказалась первой.