ShellExecute a focus okna

0

od kilku dni walcze z dziwnym problemem z funkcja ShellExecute i juz skonczyly mi sie pomysly..
rzecz dotyczy aplikacji dzialajacej w tle - jedno okienko do obslugi komunikatow - nigdy nie wyswietlane.
po przechwyceniu okreslonego komunikatu ma wywolac ShellExecute() i robi to calkiem sprawnie, ze jednym zastrzezeniem - okna aplikacji czy folderow otwierane przez ta funkcje nie staja sie pierwszoplanowe i nie dostaja focusa (laduja gdzies w srodku z-order).
'podnoszenie' ich przez enumeracje istniejacych okien i porownanie uchwytow procesu raczej nie wchodzi w gre.

ktos ma pomysl co z tym zrobic?

0

ostatni parametr dla shellexecute okresla tryb wyswietlenia
http://msdn2.microsoft.com/en-us/library/ms647732.aspx
powinno wystarczyc SW_SHOWNORMAL, ale jesli tego uzywales i nadal jest tak samo - to chyba zostaje tylko przegladanie wyzstkich okien procesu i 'reczny' focus..

0

Nie wiem czy dobrze zrozumiałem, ale jak coś to masz jeszcze jedno wyjście. Wywołaj
ShellExecute(0, "open", "cmd.exe", parametry, "", 0);

gdzie parametry to
"/C "sciezka pliku" /D"

Mi otwiera wtedy okno jako pierwszo planowe. Sprawdź.

0

quetzalcoatl, wyprobowalem juz chyba wszelkie mozliwe kombinacje flag w tym parametrze - ni huhu.

RR, heheh.. nieco brutalne;) niestety u mnie nie zalatwi sprawy, poniewaz do jako argument do ShellExecute z zalozenia moze trafic wszystko od aplikacji po katalog, a z tym cmd sobie juz nie poradzi.

z tego samego powodu raczej nie da sie zalatwic tego 'recznie' przegladajac okienka (w koncu dla np. explorer.exe uchwytow znajdzie kilka sztuk;)

potraktowalem disassemblerem aplikacje, ktora robi podobna robote, ale omawiany problem w niej nie wystepuje - moze nie jestem mistrzem assemblera, ale nie wyglada na to, by po wywolaniu ShellExecute dzialo sie jescze cos ciekawego, wiec juz zupelnie nie wiem czego sie czepic...

w desperacji nawet przepisalem kod pod delphi i gcc4 - bez zmian.

0

A sprawdziłeś mój sposób? Takie coś miałem wpisane i normalnie działało (dlatego że różne rozszerzenia mi ładnie interpretowało i nie tylko). Nie miałem problemu z uruchomianiem niczego, nawet jak były spacje w nazwie. Poza tym okno cmd, które powinno się pojawiać, nie pojawia się (nawet nie miga) bo jest ukryte. To dobry sposób i prosty, no chyba że ci nie zadziała (w co mocno wątpię). Ja spróbujesz to daj znać.

0

RR, dziala na pliki, katalogow nie otwiera w ogole.
odnosnie uruchamiania plikow znalazlem inne obejscie - jezeli moja aplikacja nie jest bezposrednio uruchamiana przez explorera, to osiagam mniej wiecej zamierzony efekt - to tez nie rozwiazuje problemu katalogow, ale moze bedzie dla kogos jakas wskazowka...

0

ha! udalo sie:D
takie cos przed wywolaniem ShellExecute zalatwia sprawe:

SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);

(zmienia HKEY_CURRENT_USER\Control Panel\Desktop\ForegroundLockTimeout; wartosc domyslna dla xp: 0x030D40)

oczywiscie warto po operacji przywrocic stara wartosc;)

0

To dziwne. Jak na mój gust robisz coś po prostu źle i nie ma wyjścia :(.
SW_SHOWDEFAULT spróbuj tak. U mnie działa. Przykład pełnej składni to
ShellExecute(0, "open", "c:\", NULL, NULL,SW_SHOWDEFAULT);
Na wszelki wypadek hwnd podaj 0
Druga sprawa to sprawdź co się stanie jeśli wykonasz to polecenie zaraz po utworzeniu okna i w paru innych miejscach. Poza tym jak przechwytujesz klawiaturę? haki? Jeśli tak, to postaraj się w odpowiedni sposób usuwać komunikaty. A najlepiej to wyświetl sobie to okienko i przetestuj na otwartym.

0

Powtórzę to co napisałem wyżej. Musiałeś coś źle zrobić. U mnie shellexecute takie jak wyżej działało bez problemu.
a cmd faktycznie. W mojej wersji folderów nie musiałem otwierać.

0

Po co powtarzasz 2 razy, skoro napisal, ze sobie z tym poradzil?

0

Nie słyszałeś o rzeczach, które się robi po to aby wyjaśnić, a nie zostawiać? Szkoda. Dlatego powtórzyłem. Ciebie nie dziwi jakaś taka kombinacja? Mnie dziwi. Przed chwilą nawet uruchomiłe swoją aplikację z hakami, która też opierała się na klawiaturze i tego problemu nie miałem. Gdyby nie to, że w mojej aplikacji jest straszny burdel, bo była to aplikacja testowa, to bym ją zamieścił ze źródłami.

PS. ten problem można było rozwiązać na 100 innych sposobów np. napisać EXE który uruchomi to co przyszło w parametrze. Ale chyba nie o to chodzi.

0

RR, noo.. z samym ShellExecute probowalem juz naprawde szalonych rzeczy. jako uchwyt przekazywalem uchwyt pulpitu, okna mojej aplikacji, 0... wszystko sie ladnie uruchamialo, ale nie w foregroundzie.
no, chyba, ze bylo wyswietlone i aktywne okno mojej aplikacji.

a rozwiazanie znalazlem walkujac microsoftowska dokumentacje SetForegroundWindow
http://msdn2.microsoft.com/en-us/library/ms633539.aspx
w sekcji Remarks.
[quote]
(...)an application cannot force a window to the foreground while the user is working with another window. Instead, Foreground and Background Windows will activate the window (see SetActiveWindow) and call the function to notify the user.
(...)To have SetForegroundWindow behave the same as it did on Windows 95 and Microsoft Windows NT 4.0, change the foreground lock timeout value when the application is installed.
[/quote]

0
RR napisał(a)

Nie słyszałeś o rzeczach, które się robi po to aby wyjaśnić, a nie zostawiać? Szkoda.

Slyszalem. Ale jesli chodzi o mnie to wystarczy raz powiedziec - ludzie sa zazwyczaj na tyle kumaci, ze zrozumieja ;) Nie trzeba mowic 10 razy, az ktos powie, ze zrozumial ;)

0

A czy ktoś mówi o nie zrozumieniu johny_bravo. Rownie dobrze ustalenie przyczyny mogłoby mi się kiedyś przydać, prawda? Nie będę się spierał, ale równie dobrze ktoś mógłby napisać że zwraca wskaźnik do zmiennej lokalnej, bo mu tak działa. Też byś wtedy milczał? Albo modyfikuje coś poza tablicą i mówi że działa. Ustalenie przyczyny dlaczego koledze to nie chodzi ma znaczenie nie tylko dla niego, ale również dla innych. Rozwiązanie takie jak kolega zaprezentował może jest dobre, ale dość daleko idące. Warto ustalić dlaczego tak jest, bo jestem przekonany że nie wiele osób tak robi i nie wiele ma z tym problem. Ja np. nigdy się z tym niespotkałem.

mpk zamieść tutaj okrojony kod, taki który jest mały i nie działa ci poprawnie. Podaj jaki kompilator. Zobaczymy czy problem występuje tylko u ciebie. (oczywiście jak masz ochotę brnąć w to dalej).

0

PS. jony_bravo nie jestem zarejestrowany więc nie mogę edytować swoich postów (i rejestrować się na razie nie zamierzam), a więc jak napisałem jakiś post to mogłem nie widzieć co się pojawiło w temacie podczas pisania i dlatego potem dodałem jeszcze jeden (to tak na marginesie)

0

proponuje zebyscie skonczyli sie klocic albo poszli na IRC'a lub GG, a moderator zeby skompresowal ten watek - lacznie z moim postem..

0

hmm, imho rowniez dyskusji nie powinno konczyc samo znikniecie problemu, lecz wyeliminowanie przyczyny - pozniej sie siedzi dwa dni na googlarce i kupe znajduje;)

co do kodu, to mniej wiecej tak:

globalnie:

void * Hook;
UINT IPCmsg;

const int firstButton = 116;
const int secondButton = 57;

typedef struct {
int aType;
char path[255];
char params[255];
int PM_action;
} TButtonConfig;

typedef TButtonConfig TConfig[2];

//-------
przy starcie:

IPCmsg = RegisterWindowMessage(IPCmsgID); // IPCmsgID = "mpk_cswalkeralt_settingschanged"
Hook = SetWindowsHookEx(13, (HOOKPROC)HandleEvent, HInstance, 0); // 13 - WH_KEYBOARD_LL
ReadConfig(); // pobranie konfiguracji z rejestru - zadnych rewelacji.

//-------
obsluga Hook'a:

HOOKPROC HandleEvent(int iCode, WPARAM wParam, LPARAM lParam){
if(iCode < 0) return (HOOKPROC)CallNextHookEx(Hook, iCode, wParam, lParam);

EVENTMSG *pEvt = (EVENTMSG *)lParam;
if ( (pEvt->message == 255) && (pEvt->paramH == 129)){
if (pEvt->paramL == secondButton){
ButtonAction(1);
}else if (pEvt->paramL == firstButton){
ButtonAction(0);
}
}
return (HOOKPROC)CallNextHookEx (Hook, iCode, wParam, lParam);
}

//-----

void ButtonAction(int num){
//SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
switch (frmMain->config[num].aType){
case 0:
{
if (FileExists(frmMain->config[num].path)){
ShellExecute(0, "open", frmMain->config[num].path, frmMain->config[num].params, NULL, SW_SHOWNORMAL);
}
break;
}
// dalej obsluga innych typow akcji - nie interesuje nas;)

//SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0x30D40, (LPVOID)0, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
}

//----
no i ogsluga komunikatow:

void __fastcall TfrmMain::WndProc(TMessage &Message){
if (Message.Msg == IPCmsg)
ReadConfig();

TForm::WndProc(Message);
}

jak widac kod pod borlanda, ale bawilem sie tez DevCpp pod gcc4 - efekt ten sam - wywolane przez moja aplikacje okienka zostaja foreground tylko gdy moja aplikacja miala focus.

0

Aleś mnie zaintrygował. Zamiast pisać to co powinienem to się bawie :P

Faktycznie problem występuje. U mnie jednak nie występował dla okna ukrytego, ale nie ważne.

Wracam do cmd.exe :P To brutalne, ale świetnie się sprawdza i nie mów że się nie da :P Da się, ładnie chodzi.

ShellExecute(0, "open", "cmd.exe", parametry, NULL, 0);

jako parametry wpisz np.
/C start "" "ścieżka" /B

czyli po przeniesieniu wyjdzie:
"/C start /"/" /"ścieżka/" /B/"

U mnie działa, niezależnie od tego co otwieram.

Daj znać jak przetestujesz u siebie :)

0

Aha i jeszcze jedno. Zawsze możesz również dorzucić inne polecenia w cmd :P o czym pewnie wiesz, czyli np.
cmd.exe /C if exist "sciezka" start "" "sciezka" /B

Ale to już poza tematem i tak całkiem na marginesie :P cmd jest przydatne.
Zawsze byłem zdania że modyfikacja rejestru tam gdzie nie jest to konieczne jest błędem. A tutaj dało się inaczej więc to moim zdaniem lepszy sposób. Mam nadzieje że u ciebie zadziała.

0

znalazlem jeszcze jedno rozwiazanie - wydaje mi sie najleprze, gdyz nie miesza w rejestrze i nie angazuje dodatkowych procesow;)

  HWND currwin = GetForegroundWindow();
  DWORD myThreadID = GetCurrentThreadId();
  DWORD currThreadID = GetWindowThreadProcessId(currwin, NULL);
  AttachThreadInput(myThreadID, currThreadID, true);

  ShellExecute(/*...*/);

  AttachThreadInput(myThreadID, currThreadID, false);
0

No też tak można. Też o tym myślałem, ale wydało mi sie za dużo pisania :P A obce procesy w stylu cmd to chyba nie problem. cmd jest zawsze i zawsze powinno działać przy tak prymitywnych sprawach. Ogromnych opóźnień nie spowoduje bo i tak najwięcej opóźnień spowoduje program, który zacznie się uruchamiać np. jakieś większe środowisko graficzne.

W takim razie masz dwa rozwiązania :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1