예제 #1
0
            private void WatchWindow()
            {
                IntPtr handle;

                try
                {
                    handle = process.MainWindowHandle;
                }
                catch (Exception e)
                {
                    Util.Logging.Log(e);
                    return;
                }

                Windows.FindWindow.TextComparer classCallback = new Windows.FindWindow.TextComparer(
                    delegate(string name, StringBuilder sb)
                {
                    if (sb.Length == EDIT_CLASSNAME.Length)
                    {
                        return(sb.ToString().Equals(EDIT_CLASSNAME));
                    }
                    return(false);
                });

                Windows.FindWindow.TextComparer textCallback = new Windows.FindWindow.TextComparer(
                    delegate(string name, StringBuilder sb)
                {
                    if (name != null && name.Equals(EDIT_CLASSNAME))
                    {
                        return(sb.Length > 500 && sb[0] == '*');
                    }

                    return(true);
                });

                StringBuilder buffer = new StringBuilder(DX_WINDOW_CLASSNAME.Length);
                int           length = 0;

                var wce     = new WindowChangedEventArgs();
                var _handle = IntPtr.Zero;

                //watched for windowed mode process exit with no handle -- likely an invisible crash due to outdated Local.dat

                do
                {
                    try
                    {
                        process.Refresh();
                        handle = process.MainWindowHandle;
                    }
                    catch (Exception e)
                    {
                        Util.Logging.Log(e);
                    }

                    try
                    {
                        if (this.process.HasExited)
                        {
                            if (handle == IntPtr.Zero && (IsAutomaticLogin(this.Account.Settings) || Util.Args.Contains(this.Args, "nopatchui")))
                            {
                                var elapsed = this.process.ExitTime.Subtract(this.process.StartTime).TotalSeconds;
                                if (elapsed < 60 && WindowCrashed != null)
                                {
                                    WindowCrashed(this, CrashReason.NoPatchUI);
                                }
                            }

                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        Util.Logging.Log(e);
                        return;
                    }

                    if (handle != IntPtr.Zero)
                    {
                        if (_handle != handle)
                        {
                            _handle    = handle;
                            wce.Handle = handle;

                            if (WindowChanged != null)
                            {
                                wce.Type = WindowChangedEventArgs.EventType.HandleChanged;
                                WindowChanged(this, wce);
                            }
                        }

                        buffer.Length = 0;
                        NativeMethods.GetClassName(handle, buffer, buffer.Capacity + 1);

                        int l;
                        if ((l = buffer.Length) != length)
                        {
                            length = l;

                            if (l > 0)
                            {
                                string className = buffer.ToString();
                                if (className.Equals(DX_WINDOW_CLASSNAME))
                                {
                                    if (WindowChanged != null)
                                    {
                                        wce.Type = WindowChangedEventArgs.EventType.DxWindowCreated;
                                        WindowChanged(this, wce);
                                    }

                                    try
                                    {
                                        var t = DateTime.UtcNow.AddSeconds(30);

                                        do
                                        {
                                            buffer.Length = 0;
                                            if (NativeMethods.GetWindowText(handle, buffer, 2) > 0 && buffer[0] != 'U') //window text is initially Untitled
                                            {
                                                if (WindowChanged != null)
                                                {
                                                    wce.Type = WindowChangedEventArgs.EventType.TitleChanged;
                                                    WindowChanged(this, wce);
                                                }

                                                break;
                                            }
                                        }while (DateTime.UtcNow < t && !process.WaitForExit(100));
                                    }
                                    catch (Exception e)
                                    {
                                        Util.Logging.Log(e);
                                    }

                                    using (var volumeControl = new Windows.Volume.VolumeControl(process.Id))
                                    {
                                        //already loaded if audio is initialized (only checks default playback device)
                                        var hasVolume = volumeControl.Query();

                                        if (hasVolume)
                                        {
                                            if (WindowChanged != null && !this.process.HasExited)
                                            {
                                                wce.Type = WindowChangedEventArgs.EventType.DxWindowReady;
                                                WindowChanged(this, wce);
                                            }

                                            return;
                                        }

                                        var nextCheck_Seconds = 3;
                                        var memoryUsage       = process.PeakWorkingSet64;
                                        var limit             = DateTime.UtcNow.AddMinutes(3);
                                        var nextCheck         = DateTime.UtcNow.AddSeconds(nextCheck_Seconds);
                                        var memoryChecks      = 0;
                                        //var verified = false;

                                        do
                                        {
                                            //the volume will be initialized first, then a child process (CoherentUI) will spawn
                                            if (hasVolume = volumeControl.Query() || HasChildProcess(process.Id))
                                            {
                                                break;
                                            }

                                            //watching for changes in memory usage to check if it's still doing something
                                            //bypassing the launching can cause it to get stuck on authentication if either the credentials are wrong or the network isn't authorized
                                            if (watchAutologin && DateTime.UtcNow > nextCheck)
                                            {
                                                process.Refresh();

                                                var memoryChange = process.PeakWorkingSet64 - memoryUsage;
                                                memoryUsage += memoryChange;

                                                if (memoryChange < 1000000)
                                                {
                                                    if (++memoryChecks == 3)
                                                    {
                                                        //this account may be stuck trying to authenticate

                                                        var account = this.Account.Settings;
                                                        if (account.HasCredentials && account.NetworkAuthorizationState != Settings.NetworkAuthorizationState.Disabled && Settings.NetworkAuthorization.HasValue)
                                                        {
                                                            if (account.NetworkAuthorizationState == Settings.NetworkAuthorizationState.Unknown)
                                                            {
                                                                if (AuthenticationRequired != null)
                                                                {
                                                                    AuthenticationRequired(this, null);
                                                                }

                                                                return;
                                                            }
                                                            else
                                                            {
                                                                Tools.ArenaAccount session;
                                                                switch (NetworkAuthorization.Verify(account, true, null, out session))
                                                                {
                                                                case NetworkAuthorization.VerifyResult.Completed:
                                                                case NetworkAuthorization.VerifyResult.Required:

                                                                    if (AuthenticationRequired != null)
                                                                    {
                                                                        AuthenticationRequired(this, session);
                                                                    }

                                                                    return;

                                                                case NetworkAuthorization.VerifyResult.OK:

                                                                    //authentication was ok - assuming it's a slow load
                                                                    nextCheck_Seconds = 10;
                                                                    //verified = true;

                                                                    break;

                                                                case NetworkAuthorization.VerifyResult.None:
                                                                default:

                                                                    //authentication isn't being tracked - assuming it's stuck
                                                                    nextCheck_Seconds = 10;

                                                                    break;
                                                                }
                                                            }
                                                        }
                                                        else
                                                        {
                                                            //authentication isn't enabled
                                                            nextCheck_Seconds = 10;
                                                        }
                                                    }
                                                    else if (memoryChecks > 6)
                                                    {
                                                        if (AuthenticationRequired != null)
                                                        {
                                                            AuthenticationRequired(this, null);
                                                        }

                                                        return;
                                                    }
                                                }
                                                else
                                                {
                                                    memoryChecks = 0;
                                                }

                                                nextCheck = DateTime.UtcNow.AddSeconds(nextCheck_Seconds);
                                            }
                                        }while (DateTime.UtcNow < limit && !this.process.WaitForExit(500));

                                        if (WindowChanged != null && !this.process.HasExited)
                                        {
                                            wce.Type = WindowChangedEventArgs.EventType.DxWindowReady;
                                            WindowChanged(this, wce);
                                        }

                                        return;
                                    }
                                }
                                else if (className[0] == '#')
                                {
                                    var result = Find(handle, classCallback, textCallback);
                                    if (result != null)
                                    {
                                        CrashReason reason = CrashReason.Unknown;

                                        string text = result.Text;
                                        int    i    = text.IndexOf("Assertion:", 0, 100);
                                        if (i != -1)
                                        {
                                            int j = text.IndexOf('\n', i);
                                            if (text.IndexOf("Is your archive up to date?", i, j - i, StringComparison.OrdinalIgnoreCase) != -1 ||
                                                text.IndexOf("Client needs to be patched", i, j - i, StringComparison.OrdinalIgnoreCase) != -1)
                                            {
                                                reason = CrashReason.PatchRequired;
                                            }
                                        }

                                        if (WindowCrashed != null)
                                        {
                                            WindowCrashed(this, reason);
                                        }
                                    }
                                    return;
                                }
                                else if (className.Equals(LAUNCHER_WINDOW_CLASSNAME))
                                {
                                    if (WindowChanged != null)
                                    {
                                        wce.Type = WindowChangedEventArgs.EventType.TitleChanged;
                                        WindowChanged(this, wce);
                                    }
                                }
                            }
                        }
                    }
                }while (!process.WaitForExit(500) && this.watcher != null);
            }
예제 #2
0
            private void WatchWindow()
            {
                IntPtr handle;

                try
                {
                    handle = process.MainWindowHandle;
                }
                catch (Exception e)
                {
                    Util.Logging.Log(e);
                    return;
                }

                Windows.FindWindow.TextComparer classCallback = new Windows.FindWindow.TextComparer(
                    delegate(string name, StringBuilder sb)
                {
                    if (sb.Length == EDIT_CLASSNAME.Length)
                    {
                        return(sb.ToString().Equals(EDIT_CLASSNAME));
                    }
                    return(false);
                });

                Windows.FindWindow.TextComparer textCallback = new Windows.FindWindow.TextComparer(
                    delegate(string name, StringBuilder sb)
                {
                    if (name != null && name.Equals(EDIT_CLASSNAME))
                    {
                        return(sb.Length > 500 && sb[0] == '*');
                    }

                    return(true);
                });

                StringBuilder buffer = new StringBuilder(DX_WINDOW_CLASSNAME.Length);
                int           length = 0;

                var wce     = new WindowChangedEventArgs();
                var _handle = IntPtr.Zero;

                do
                {
                    try
                    {
                        do
                        {
                            process.Refresh();
                            handle = process.MainWindowHandle;

                            if (handle == IntPtr.Zero)
                            {
                                if (!process.WaitForExit(10))
                                {
                                    process.WaitForInputIdle();
                                }
                            }
                            else
                            {
                                break;
                            }
                        }while (!process.HasExited);
                    }
                    catch (Exception e)
                    {
                        Util.Logging.Log(e);
                    }

                    try
                    {
                        if (this.process.HasExited)
                        {
                            //no longer applicable - nopatchui exiting without creating a window likely meant the client wasn't up to date

                            //if (handle == IntPtr.Zero && (IsAutomaticLogin(this.Account.Settings) || Util.Args.Contains(this.Args, "nopatchui")))
                            //{
                            //    var elapsed = this.process.ExitTime.Subtract(this.process.StartTime).TotalSeconds;
                            //    if (elapsed < 60 && WindowCrashed != null)
                            //        WindowCrashed(this, CrashReason.NoPatchUI);
                            //}
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        Util.Logging.Log(e);
                        return;
                    }

                    if (handle != IntPtr.Zero)
                    {
                        if (_handle != handle)
                        {
                            _handle    = handle;
                            wce.Handle = handle;

                            if (WindowChanged != null)
                            {
                                wce.Type = WindowChangedEventArgs.EventType.HandleChanged;
                                WindowChanged(this, wce);
                            }
                        }

                        buffer.Length = 0;
                        NativeMethods.GetClassName(handle, buffer, buffer.Capacity + 1);

                        int l;
                        if ((l = buffer.Length) != length)
                        {
                            length = l;

                            if (l > 0)
                            {
                                string className = buffer.ToString();
                                if (className.Equals(DX_WINDOW_CLASSNAME))
                                {
                                    if (WindowChanged != null)
                                    {
                                        wce.Type = WindowChangedEventArgs.EventType.DxWindowCreated;
                                        WindowChanged(this, wce);
                                    }

                                    //window initialization order:
                                    //title change > volume (window is ready) > coherentui

                                    int      pidChild  = 0;
                                    bool     hasVolume = false;
                                    DateTime limit;

                                    using (var volumeControl = new Windows.Volume.VolumeControl(process.Id))
                                    {
                                        if (processWasAlreadyStarted && ((hasVolume = volumeControl.Query()) || (pidChild = GetChildProcess(process.Id)) > 0))
                                        {
                                            //window is already loaded

                                            if (WindowChanged != null)
                                            {
                                                wce.Type = WindowChangedEventArgs.EventType.TitleChanged;
                                                WindowChanged(this, wce);
                                            }

                                            limit = DateTime.UtcNow.AddMinutes(1);
                                        }
                                        else
                                        {
                                            try
                                            {
                                                limit = DateTime.UtcNow.AddSeconds(30);
                                                var ws1 = IntPtr.Zero;

                                                do
                                                {
                                                    //window style changes when loading into fullscreen mode
                                                    var ws2 = NativeMethods.GetWindowLongPtr(handle, (int)GWL.GWL_STYLE);
                                                    if (ws2 != ws1)
                                                    {
                                                        if (ws1 != IntPtr.Zero && WindowChanged != null)
                                                        {
                                                            wce.Type = WindowChangedEventArgs.EventType.DxWindowStyleChanged;
                                                            WindowChanged(this, wce);
                                                        }

                                                        ws1 = ws2;
                                                    }

                                                    buffer.Length = 0;
                                                    if (NativeMethods.GetWindowText(handle, buffer, 2) > 0 && buffer[0] != 'U') //window text is initially Untitled
                                                    {
                                                        if (WindowChanged != null)
                                                        {
                                                            wce.Type = WindowChangedEventArgs.EventType.TitleChanged;
                                                            WindowChanged(this, wce);
                                                        }

                                                        break;
                                                    }
                                                }while (DateTime.UtcNow < limit && !process.WaitForExit(100));
                                            }
                                            catch (Exception e)
                                            {
                                                Util.Logging.Log(e);
                                            }

                                            var nextCheck_Seconds = 3;
                                            var memoryUsage       = process.PeakWorkingSet64;
                                            var nextCheck         = DateTime.UtcNow.AddSeconds(nextCheck_Seconds);
                                            var memoryChecks      = 0;
                                            //var verified = false;

                                            limit = DateTime.UtcNow.AddMinutes(3);

                                            do
                                            {
                                                if ((hasVolume = volumeControl.Query()) || (pidChild = GetChildProcess(process.Id)) > 0)
                                                {
                                                    break;
                                                }

                                                #region -nopatchui activity check (obsolete)

                                                //watching for changes in memory usage to check if it's still doing something
                                                //bypassing the launcher (-nopatchui) can cause it to get stuck on authentication if either the credentials are wrong or the network isn't authorized
                                                if (!hasVolume && DateTime.UtcNow > nextCheck)
                                                {
                                                    process.Refresh();

                                                    var memoryChange = process.PeakWorkingSet64 - memoryUsage;
                                                    memoryUsage += memoryChange;

                                                    if (memoryChange < 1000000)
                                                    {
                                                        if (++memoryChecks == 3)
                                                        {
                                                            //this account may be stuck trying to authenticate

                                                            var account = this.Account.Settings;
                                                            if (account.HasCredentials && account.NetworkAuthorizationState != Settings.NetworkAuthorizationState.Disabled && Settings.NetworkAuthorization.HasValue)
                                                            {
                                                                if (account.NetworkAuthorizationState == Settings.NetworkAuthorizationState.Unknown)
                                                                {
                                                                    if (AuthenticationRequired != null)
                                                                    {
                                                                        AuthenticationRequired(this, null);
                                                                    }

                                                                    return;
                                                                }
                                                                else
                                                                {
                                                                    Tools.ArenaAccount session;
                                                                    switch (NetworkAuthorization.Verify(account, true, null, out session))
                                                                    {
                                                                    case NetworkAuthorization.VerifyResult.Completed:
                                                                    case NetworkAuthorization.VerifyResult.Required:

                                                                        if (AuthenticationRequired != null)
                                                                        {
                                                                            AuthenticationRequired(this, session);
                                                                        }

                                                                        return;

                                                                    case NetworkAuthorization.VerifyResult.OK:

                                                                        //authentication was ok - assuming it's a slow load
                                                                        nextCheck_Seconds = 10;
                                                                        //verified = true;

                                                                        break;

                                                                    case NetworkAuthorization.VerifyResult.None:
                                                                    default:

                                                                        //authentication isn't being tracked - assuming it's stuck
                                                                        nextCheck_Seconds = 10;

                                                                        break;
                                                                    }
                                                                }
                                                            }
                                                            else
                                                            {
                                                                //authentication isn't enabled
                                                                nextCheck_Seconds = 10;
                                                            }
                                                        }
                                                        else if (memoryChecks > 6)
                                                        {
                                                            if (AuthenticationRequired != null)
                                                            {
                                                                AuthenticationRequired(this, null);
                                                            }

                                                            return;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        memoryChecks = 0;
                                                    }

                                                    nextCheck = DateTime.UtcNow.AddSeconds(nextCheck_Seconds);
                                                }

                                                #endregion
                                            }while (DateTime.UtcNow < limit && !this.process.WaitForExit(500));
                                        }
                                    }

                                    if (WindowChanged != null && !this.process.HasExited)
                                    {
                                        wce.Type = WindowChangedEventArgs.EventType.DxWindowReady;
                                        WindowChanged(this, wce);
                                    }

                                    #region Find CoherentUI

                                    if (pidChild == 0)
                                    {
                                        do
                                        {
                                            if ((pidChild = GetChildProcess(process.Id)) > 0)
                                            {
                                                break;
                                            }
                                        }while (DateTime.UtcNow < limit && !this.process.WaitForExit(500));
                                    }

                                    if (pidChild > 0)
                                    {
                                        try
                                        {
                                            using (var child = Process.GetProcessById(pidChild))
                                            {
                                                limit = DateTime.UtcNow.AddSeconds(10);
                                                var pid = pidChild;

                                                do
                                                {
                                                    if ((pidChild = GetChildProcess(pid)) > 0)
                                                    {
                                                        break;
                                                    }
                                                }while (DateTime.UtcNow < limit && !child.WaitForExit(500));
                                            }

                                            if (pidChild > 0)
                                            {
                                                using (var child = Process.GetProcessById(pidChild))
                                                {
                                                    long mem     = 0;
                                                    byte counter = 0;
                                                    limit = DateTime.UtcNow.AddSeconds(60);

                                                    do
                                                    {
                                                        if (mem > 0)
                                                        {
                                                            child.Refresh();
                                                        }
                                                        var _mem = child.PeakWorkingSet64;
                                                        if (_mem > mem)
                                                        {
                                                            mem     = _mem;
                                                            counter = 0;
                                                        }
                                                        else if (++counter > 2)
                                                        {
                                                            break;
                                                        }
                                                    }while (DateTime.UtcNow < limit && !child.WaitForExit(100));
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            Util.Logging.Log(ex);
                                        }
                                    }

                                    #endregion

                                    if (WindowChanged != null && !this.process.HasExited)
                                    {
                                        wce.Type = WindowChangedEventArgs.EventType.InGameCoherentUIReady;
                                        WindowChanged(this, wce);
                                    }

                                    return;
                                }
                                else if (className[0] == '#')
                                {
                                    var result = Find(handle, classCallback, textCallback);
                                    if (result != null)
                                    {
                                        CrashReason reason = CrashReason.Unknown;

                                        string text = result.Text;
                                        int    i    = text.IndexOf("Assertion:", 0, 100);
                                        if (i != -1)
                                        {
                                            int j = text.IndexOf('\n', i);
                                            if (text.IndexOf("Is your archive up to date?", i, j - i, StringComparison.OrdinalIgnoreCase) != -1 ||
                                                text.IndexOf("Client needs to be patched", i, j - i, StringComparison.OrdinalIgnoreCase) != -1)
                                            {
                                                reason = CrashReason.PatchRequired;
                                            }
                                        }

                                        if (WindowCrashed != null)
                                        {
                                            WindowCrashed(this, reason);
                                        }
                                    }
                                    return;
                                }
                                else if (className.Equals(LAUNCHER_WINDOW_CLASSNAME))
                                {
                                    if (WindowChanged != null)
                                    {
                                        wce.Type = WindowChangedEventArgs.EventType.TitleChanged;
                                        WindowChanged(this, wce);
                                    }

                                    #region Find CoherentUI

                                    var pidChild = 0;
                                    var limit    = DateTime.UtcNow.AddSeconds(30);

                                    do
                                    {
                                        if ((pidChild = GetChildProcess(process.Id)) > 0)
                                        {
                                            break;
                                        }

                                        this.process.Refresh();
                                        if (_handle != this.process.MainWindowHandle)
                                        {
                                            break;
                                        }
                                    }while (DateTime.UtcNow < limit && !this.process.WaitForExit(500));

                                    if (pidChild > 0)
                                    {
                                        try
                                        {
                                            using (var child = Process.GetProcessById(pidChild))
                                            {
                                                limit = DateTime.UtcNow.AddSeconds(10);
                                                var pid = pidChild;

                                                do
                                                {
                                                    if ((pidChild = GetChildProcess(pid)) > 0)
                                                    {
                                                        break;
                                                    }

                                                    this.process.Refresh();
                                                    if (_handle != this.process.MainWindowHandle)
                                                    {
                                                        break;
                                                    }
                                                }while (DateTime.UtcNow < limit && !child.WaitForExit(500));
                                            }

                                            if (pidChild > 0)
                                            {
                                                using (var child = Process.GetProcessById(pidChild))
                                                {
                                                    long mem     = 0;
                                                    byte counter = 0;
                                                    limit = DateTime.UtcNow.AddSeconds(60);

                                                    do
                                                    {
                                                        if (mem > 0)
                                                        {
                                                            child.Refresh();
                                                        }
                                                        var _mem = child.PeakWorkingSet64;
                                                        if (_mem > mem)
                                                        {
                                                            mem     = _mem;
                                                            counter = 0;
                                                        }
                                                        else if (++counter > 2)
                                                        {
                                                            break;
                                                        }
                                                    }while (DateTime.UtcNow < limit && !child.WaitForExit(100));

                                                    if (WindowChanged != null)
                                                    {
                                                        wce.Type = WindowChangedEventArgs.EventType.LauncherCoherentUIReady;
                                                        WindowChanged(this, wce);
                                                    }
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            Util.Logging.Log(ex);
                                        }
                                    }

                                    #endregion
                                }
                            }
                        }
                    }
                }while (!process.WaitForExit(500) && this.watcher != null);
            }