ExitWindowsEx i Metro App

0

Witam,

Walczę z MetroUI. Ponieważ, jak wielu, nie mogę się przyzwyczaić do nowego sposobu wyłączania Windows 8, postanowiłem napisać sobie program dla Metro, który po włączeniu będzie miał trzy przyciski: "Wyłącz", "Restartuj", "Uśpij". W życiu nie podejrzewałem, że będzie to takie trudne...
Z powodu wszelakich ograniczeń jakie M$ zastosował do metro (paranoja...) stwierdziłem, że aby tego dokonać najłatwiej będzie zrobić nową zwykłą C#-ową DLL, która będzie wywoływać ExitWindowsEx i wywołać ją z aplikacji Metro.
Dowiedziawszy się, że nie może to być po prostu dołączona nowa referencja, a musi być to DLL załączony do projektu, z właściwością Build Action: Content i potem jakoś magicznie wywołany, po kolejnym namyśle stwierdziłem, że najłatwiej będzie zastosować reflection (wtedy jeszcze nie wiedziałem, że zaszły tam takie zmiany...).
Do sedna - spłodziłem genialną DLL:

public static class Library
{
    [DllImport("User32.dll")]
    public static extern int ExitWindowsEx(int uFlags, int dwReason);

    [DllImport("Kernel32.dll")]
    public static extern int GetLastError();    

    public static string MsgBox()
    {
        return "Dupa";
    }

    public static int TurnOff()
    {
        return ExitWindowsEx(2, 0);
    }

    public static int Error()
    {
        return GetLastError();
    }
}

Jej wywołanie w Metro wygląda następująco:

            AssemblyName name = new AssemblyName("TurnOffLibrary");
            Assembly ass = Assembly.Load(name);
            TypeInfo ti = ass.DefinedTypes.ElementAt(0);

            MethodInfo msgbox = ti.GetDeclaredMethod("MsgBox");
            object dupa = msgbox.Invoke(ti, null);

            if (dupa is string)
            {
                pageTitle.Text = (dupa as string);
            }

            MethodInfo turnoff = ti.GetDeclaredMethod("TurnOff");
            int return1 = (int)turnoff.Invoke(ti, null);

            MethodInfo error = ti.GetDeclaredMethod("Error");
            int return2 = (int)error.Invoke(ti, null);

I teraz:
return1 posiada wartość 0 (słownie: zero)
return2 posiada wartość 5 (słownie: pięć) - Access Denied

pageTitle otrzymuje napis "Dupa" bez problemu, więc DLL się wykonuje, ale nie ma żadnej reakcji na ExitWindowsEx. Mogę ją wywoływać z różnymi parametrami i nic się nie stanie.

Przed napisaniem tej library próbowałem bezpośredniego Invoka w MetroApp bez używania zew. DLL, ale efekt był ten sam. Po prostu to wygląda tak jak by M$ się zawziął i wyciął wszelkie sposoby na wyłączenie Windows z menu start... pfuuuu z MetroUI.

Czy da się to zrobić jakoś inaczej?

0

Bardzo prosta sprawa - kwestia zabezpieczeń. Powiedziałbym, że to bardzo dobrze, że się nic nie dzieje, bo próbowałeś oszukać zabezpieczenie :).

Stwórz WinRT Component DLL w C++/CX (dzięki tym rozszerzeniom oraz nowym metadanom nie musisz po stronie C# bawić się w żadne interopy). Możesz w nich zrobić co się podoba (a na co użytkownik lokalny ma uprawnienia). Po to wprowadzono to rozróżnienie, bo zmienia się kwestia dystrybucji aplikacji z tego typu komponentami.

0

Sporo poczytałem o WinRT. Nie trzeba tworzyć WinRT Component DLL, żeby mieć dostęp do metod WinRT. Są spokojnie dostępne w MetroApp. Jednak niestety wygląda na to, że WinRT nie potrafi wyłączyć, zrestartować czy nawet wylogować użytkownika... A szkoda. Za bardzo wiążą ręce programistom.

0

Nie wiem jak jest w Win8, ale twój kod nie zadziałałby nawet pod xp, też z powodu braku uprawnień, niewazne z jakiego użytkownika działasz. Powinieneś najpierw użyć AdjustTokenPrivileges i ustawić odpowiednie uprawnienia dla twojego procesu, inaczej zawsze dostaniesz Acces Denied w każdym windowsie z serii nt i nowszym.

Tu masz przykład jak prawidłowo użyć ExitWindowsEx:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa376871%28v=vs.85%29.aspx

Według mnie to może byc problemem, a nie WinRT.

0

Obok miałem WinForms App na której równolegle testowałem dll i w niej działało OK.
Mimo wszystko poszedłem za radą i zmodyfikowałem klasę. Zwrot z GetLastError po modyfikacji dostałem 0. A więc jak by pomogło w tym względzie, ale dalej brak reakcji ze strony PC. Na szybko użyłem też tej metody: http://stackoverflow.com/questions/4841654/c-sharp-shutdown-hibernate-sleep
Wywołanie funkcji z WinForms pięknie wyłączyło mi PC. Wywołanie z metro skutkuje System.Reflection.TargetInvocationException - Exception has been thrown by the target of an invocation. Inner Exception: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)":null
Cały kod w funkcji był zamknięty w Try-Catch wew. dll i tam nie został złapany żaden wyjątek.

Moim zdaniem nie da się i już. MS założył, że metro ma wyglądać ślicznie, służyć do wyświetlania pogody, programów telewizyjnych i innych informacji i to wszystko na co pozwala programistom.

0

Spróbuj napisać temat o tym na forum codeguru.pl. Oni tam siedzą dużo w samym .net i niekiedy jak tutaj nie udało mi się znaleźć porady to tam ją znajdywałem.

1

Najwięcej wiedzą na cytowanym już przez ciebie stackowerflow, ja bym pytał tam (oczywiście jeśli znasz angielski). Sam pytałem tam nie raz o tak "niepopularne" rzeczy, że nawet tutaj znalazłyby się może ze 2-3 osoby, które się zetknęły z tym samym problemem albo w ogóle mieli podobne zadanie przed sobą - nigdy nie zdarzyło mi się nie uzyskać co najmniej kilku wartościowych odpowiedzi.

Napisanie na forum msdn, czyli u źródła (oczywiście także po angielsku) też nie jest złym pomysłem - w końcu to tam siedzą spece od technologii MS, a nieraz i sami programiści MS zaglądają.

Licząc na same polskojęzyczne fora ograniczasz mniej więcej o 95%, warto o tym pamiętać - to tak samo jak szukanie materiałów w google tylko po polsku.

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