rex706/SAM

Question about auto-filling data in the Steam window

Closed this issue · 6 comments

Hello, please tell me how you implement the method of Entering data into the Steam window? How does he edit, etc., does he also enter everything automatically into Avast and Sandboxie Plus? the method just doesn't work - running through sandboxie
And could you give an example of working data entry into the Steam window?

Hello @mrranger,
SAM will read your loginusers.vdf file, which Steam creates and populates when you login, to try to find the SteamId associated with the entered username when that text box loses focus. This file is located in {your steam install directory}/config/loginusers.vdf. So the first part of this functionality will only work if you have logged into that account previously. If it finds a SteamId for that username it then makes an API call to get the rest of the info, so an API key is required for that functionality to work. This is configured in the Steam tab of the settings window for SAM. Avast and Sandboxie run in an environment isolated from the rest of computer files (I think?), so it may not be able to read your loginusers.vdf file to auto-populate the data. I personally don't know enough about Avast or Sandboxie to be certain if there are settings you can enable/disable to get this feature to work correctly.

I hope this helps. Let me know if you have any other questions.

I'm interested in the process of entering data into the Steam window, I also tried to do it in Python, it seems to work, but somehow slowly, but it turns out that the window does not have time to appear; he already enters the credentials very quickly. I enabled the Sandboxie feature, but Sam still wouldn't launch Steam in Sandboxie. sorry for my English, I am writing through a translator

Oh my mistake, I thought you meant the profile info window.

I am using this automation library to target input elements in the login window and enter data: https://github.com/FlaUI/FlaUI
There are various ways to detect what state the steam login window is in, based on the number of inputs or text in the window, so you can know when the window is ready for input.

This functionality is implemented in this file for SAM: https://github.com/rex706/SAM/blob/master/Core/WindowUtils.cs

I am also investigating the issues with Avast and Sandboxie tied to #188

Now everything is clear, thanks for the valuable information!

Hello, sorry again for bothering you, can you help me find the field to enter guard, I somehow managed to make a username password, but I can’t determine guard

image

`
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using FlaUI.Core.AutomationElements;
using FlaUI.Core.Definitions;
using FlaUI.UIA3;
using Microsoft.Win32;

namespace SteamAuthTEST
{
class Utils
{
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, IntPtr lParam);

    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true)]
    static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);

    [DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    [DllImport("kernel32.dll")]
    static extern uint GetCurrentThreadId();

    [DllImport("user32.dll")]
    static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool BringWindowToTop(IntPtr hWnd);

    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr SetFocus(IntPtr hWnd);

    public delegate bool EnumDelegate(IntPtr hWnd, int lParam);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsWindowVisible(IntPtr hWnd);

    [DllImport("user32.dll", EntryPoint = "GetWindowText", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpWindowText, int nMaxCount);

    [DllImport("user32.dll", EntryPoint = "EnumDesktopWindows", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    public static void Log(string message)
    {
        Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}");
    }

    public static string FindSteamExePath()
    {
        Log("Searching for Steam installation path...");
        RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\\Valve\\Steam");

        var installPathValue = registryKey.GetValue("InstallPath");
        if (installPathValue == null)
        {
            Log("Steam installation path not found in registry.");
            return "";
        }

        var installPath = installPathValue.ToString();
        var executablePath = Path.Combine(installPath, "Steam.exe");

        // Check file exist

        if (!File.Exists(executablePath))
        {
            Log($"Steam.exe not found at: {executablePath}");
            return "";
        }

        Log($"Steam.exe found at: {executablePath}");
        return executablePath;
    }

    public static void RunCommand(string fileName, string args)
    {
        Log($"Running command: {fileName} {args}");
        Process cmdProcess = new Process
        {
            StartInfo = new ProcessStartInfo
            {
                FileName = fileName,
                Arguments = args,
                UseShellExecute = false,
                CreateNoWindow = true
            }
        };

        cmdProcess.Start();
    }

    public static void LaunchSteam(string args)
    {
        if (!IsSteamRunning())
        {
            Log("Steam is not running. Launching Steam...");
            var steamPath = FindSteamExePath();
            Process steamProcess = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = steamPath,
                    Arguments = args,
                    UseShellExecute = false,
                    CreateNoWindow = false
                }
            };

            steamProcess.Start();
        }
        else
        {
            Log("Steam is already running. Using existing instance.");
        }
    }

    public static bool IsSteamRunning()
    {
        var steamMainWindow = TryGetSteamMainWindow();
        return steamMainWindow != IntPtr.Zero;
    }

    private static void AttachedThreadInputAction(Action action)
    {
        var foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
        var appThread = GetCurrentThreadId();
        bool threadsAttached = false;
        try
        {
            threadsAttached =
                foreThread == appThread ||
                AttachThreadInput(foreThread, appThread, true);
            if (threadsAttached) action();
            else throw new ThreadStateException("AttachThreadInput failed.");
        }
        finally
        {
            if (threadsAttached)
                AttachThreadInput(foreThread, appThread, false);
        }
    }

    public static void ForceWindowToForeground(IntPtr hwnd)
    {
        const int SW_SHOW = 5;
        if (hwnd != IntPtr.Zero)
        {
            // Bring the window to the foreground
            ShowWindow(hwnd, SW_SHOW);
            SetForegroundWindow(hwnd);
        }
    }


    public static IntPtr TryGetSteamLoginWindow()
    {
        IntPtr steamLoginWindow = IntPtr.Zero;
        EnumDelegate filter = delegate (IntPtr hWnd, int lParam)
        {
            StringBuilder strbTitle = new StringBuilder(255);
            int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
            string title = strbTitle.ToString();

            StringBuilder strbClassname = new StringBuilder(256);
            int nRet = GetClassName(hWnd, strbClassname, strbClassname.Capacity);
            string classname = strbClassname.ToString();

            if (IsWindowVisible(hWnd) &&
                !string.IsNullOrEmpty(title) &&
                !string.IsNullOrEmpty(classname) &&
                classname.Equals("SDL_app") &&
                title.Contains("Steam") &&
                title.Length > 5)
            {
                steamLoginWindow = hWnd;
                Log($"Found Steam login window: Title='{title}', Classname='{classname}'");
            }
            return true;
        };
        EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero);
        return steamLoginWindow;
    }

    public static IntPtr TryGetSteamMainWindow()
    {
        IntPtr steamMainWindow = IntPtr.Zero;
        EnumDelegate filter = delegate (IntPtr hWnd, int lParam)
        {
            StringBuilder strbTitle = new StringBuilder(255);
            int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
            string title = strbTitle.ToString();

            StringBuilder strbClassname = new StringBuilder(256);
            int nRet = GetClassName(hWnd, strbClassname, strbClassname.Capacity);
            string classname = strbClassname.ToString();

            if (!string.IsNullOrEmpty(title) &&
                !string.IsNullOrEmpty(classname) &&
                classname.Equals("vguiPopupWindow") &&
                title.Equals("Steam"))
            {
                steamMainWindow = hWnd;
                Log($"Found Steam main window: Title='{title}', Classname='{classname}'");
            }
            return true;
        };
        EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero);
        return steamMainWindow;
    }

    public static IntPtr WaitForWindow(int timeout, Func<IntPtr> TryGetWindow, CancellationToken token)
    {
        IntPtr window = TryGetWindow();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        while (window == IntPtr.Zero && sw.Elapsed < TimeSpan.FromSeconds(timeout) && !token.IsCancellationRequested)
        {
            window = TryGetWindow();
            Thread.Sleep(200);
        }
        return window;
    }

    public static bool SteamAutoLogin(string username, string password, string guardCode, bool remember, int timeout, CancellationToken token)
    {
        try
        {
            // Waiting for the Steam login window
            IntPtr steamLoginWindowHandle = Utils.WaitForWindow(timeout, Utils.TryGetSteamLoginWindow, token);
            Utils.Log("Waiting for Steam login window...");
            if (steamLoginWindowHandle == IntPtr.Zero)
            {
                Utils.Log("Steam login window not found.");
                return false;
            }

            using (var automation = new UIA3Automation())
            {
                AutomationElement window = automation.FromHandle(steamLoginWindowHandle);
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                while (!window.IsAvailable && !window.IsOffscreen)
                {
                    Thread.Sleep(200);
                }
                Utils.Log("Steam login window found and focused.");

                // Getting a Window Document
                AutomationElement document = window.FindFirstDescendant(e => e.ByControlType(ControlType.Document));
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                // Getting text fields from a document
                List<TextBox> textBoxes = document.FindAllChildren(e => e.ByControlType(ControlType.Edit)).Select(edit => edit.AsTextBox()).ToList();
                // If the Steam window is still not the login window
                while (textBoxes.Count != 2)
                {
                    Utils.ForceWindowToForeground(steamLoginWindowHandle);
                    var imageControlTypeCount = document.FindAllChildren(e => e.ByControlType(ControlType.Image)).Count();
                    var textControlTypeCount = document.FindAllChildren(e => e.ByControlType(ControlType.Text)).Count();
                    Utils.Log($"Password fields found: {textControlTypeCount}");
                    // If the new shitty update
                    if (imageControlTypeCount == 2 && textControlTypeCount == 1)
                    {
                        Button addAccountButton = document.FindAllChildren().Last().AsButton();
                        Utils.ForceWindowToForeground(steamLoginWindowHandle);
                        addAccountButton.Focus();
                        addAccountButton.WaitUntilEnabled();
                        addAccountButton.Invoke();
                        Thread.Sleep(30);
                    }
                    // Update text fields
                    textBoxes = document.FindAllChildren(e => e.ByControlType(ControlType.Edit)).Select(edit => edit.AsTextBox()).ToList();
                    Utils.Log($"Found text boxes: {textBoxes.Count}");
                    Thread.Sleep(50);
                }
                // Getting the remember password checkbox and its status
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                Button checkBox = document.FindFirstChild(e => e.ByControlType(ControlType.Group)).AsButton();
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                bool rememberPasswordState = checkBox.FindFirstChild(e => e.ByControlType(ControlType.Image)) != null;
                Utils.Log($"Remember password checkbox state: {rememberPasswordState}");

                // Login button
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                Button loginButton = document.FindFirstChild(e => e.ByControlType(ControlType.Button)).AsButton();
                Utils.Log("Attempting login...");

                // Writing a login
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                textBoxes[0].Focus();
                textBoxes[0].WaitUntilEnabled();
                textBoxes[0].Text = username;
                Utils.Log($"Entered username: {username}");

                // Writing a password
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                textBoxes[1].Focus();
                textBoxes[1].WaitUntilEnabled();
                textBoxes[1].Text = password;
                Utils.Log("Entered password");

                // Click on the remember password checkbox
                if (remember)
                {
                    Utils.ForceWindowToForeground(steamLoginWindowHandle);
                    checkBox.Focus();
                    checkBox.WaitUntilEnabled();
                    checkBox.Invoke();
                    Utils.Log("Checked 'Remember password'");
                }

                // Click the login button
                Utils.ForceWindowToForeground(steamLoginWindowHandle);
                loginButton.Focus();
                loginButton.WaitUntilEnabled();
                loginButton.Invoke();
                Utils.Log("Clicked 'Login' button");

                // Waiting for the Steam Guard window
                IntPtr steamGuardWindowHandle = Utils.WaitForWindow(timeout, Utils.TryGetSteamGuardWindow, token);
                if (steamGuardWindowHandle == IntPtr.Zero)
                {
                    Utils.Log("Steam Guard window not found");
                    return false;
                }
                Utils.Log("Steam Guard window found");

                window = automation.FromHandle(steamGuardWindowHandle);
                Utils.ForceWindowToForeground(steamGuardWindowHandle);

                // Getting the Steam Guard Window Document
                document = window.FindFirstDescendant(e => e.ByControlType(ControlType.Document));
                Utils.ForceWindowToForeground(steamGuardWindowHandle);
                textBoxes = document.FindAllChildren(e => e.ByControlType(ControlType.Edit)).Select(edit => edit.AsTextBox()).ToList();

                Utils.Log($"Found text boxes in Steam Guard window: {textBoxes.Count}");

                // Entering the Steam Guard code
                if (textBoxes.Count == 1)
                {
                    Utils.ForceWindowToForeground(steamGuardWindowHandle);
                    textBoxes[0].Focus();
                    textBoxes[0].WaitUntilEnabled();
                    textBoxes[0].Text = guardCode;
                    Utils.Log($"Entered Steam Guard code: {guardCode}");

                    // Click the "OK" or "Continue" button
                    Button continueButton = document.FindFirstChild(e => e.ByControlType(ControlType.Button)).AsButton();
                    Utils.ForceWindowToForeground(steamGuardWindowHandle);
                    continueButton.Focus();
                    continueButton.WaitUntilEnabled();
                    continueButton.Invoke();
                    Utils.Log("Clicked 'Continue' button in Steam Guard window");
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            Utils.Log($"Error occurred: {ex.Message}");
            return SteamAutoLogin(username, password, guardCode, remember, timeout, token);
        }
    }



    public static IntPtr TryGetSteamGuardWindow()
    {
        IntPtr steamLoginWindow = IntPtr.Zero;
        EnumDelegate filter = delegate (IntPtr hWnd, int lParam)
        {
            StringBuilder strbTitle = new StringBuilder(255);
            int nLength = GetWindowText(hWnd, strbTitle, strbTitle.Capacity + 1);
            string title = strbTitle.ToString();

            StringBuilder strbClassname = new StringBuilder(256);
            int nRet = GetClassName(hWnd, strbClassname, strbClassname.Capacity);
            string classname = strbClassname.ToString();

            // Adjust conditions based on actual Steam window properties
            if (IsWindowVisible(hWnd) &&
                !string.IsNullOrEmpty(title) &&
                !string.IsNullOrEmpty(classname) &&
                classname.Equals("SDL_app") &&
                title.Contains("Steam") &&
                title.Length > 5)
            {
                steamLoginWindow = hWnd;
                return false; // Stop enumeration once found
            }
            return true;
        };
        EnumDesktopWindows(IntPtr.Zero, filter, IntPtr.Zero);
        return steamLoginWindow;
    }
}

}
`

@mrranger

This is when I return the window state is Steam Guard

return LoginWindowState.Code;