Skip to content
Indieteur edited this page Dec 11, 2018 · 1 revision

Steam Apps Management Wiki

Please be advised that this Wiki only provides basic introduction to the library and how to use it. For more detailed use, please consider checking the Demo App provided in the repository.

Introduction

If you have already read the Readme.md file, you already know that there are two libraries included in the Solution. They are:

  • VDF Reader/Writer -- This library allows you to read and write Valve Data Format which is used to store Steam Configuration and Application Info stored in the local PC.
  • Steam Application Management API -- This library provides basic information about the Steam Applications installed on the local computer. It also allows you to launch an app as well as listen for events like if a Steam App is being launched and/or is being updated. The library can also capture the process associated with the application (by guessing. It isn't completely foolproof.)

Table of Contents

View

Table of contents generated with markdown-toc

VDF API

This library allows you to read and write Valve Data Format which is used to store Steam Configuration and Application Info stored in the local PC. Example of these files can be found on your [Steam Installation Folder]\steamapps. They are the files that have .acf and .vdf file extensions.

Setting Up

The first thing that you'll need to do is import/reference the library (Indieteur.VDFAPI). Once you have done this, you can use it straight away using the namespace Indieteur.VDFAPI

Now, there are multiple ways of instantiating a VDFData class. An example of this is by creating an empty VDF Data Structure which can be done like:

using Indieteur.VDFAPI;

namespace Demo
{
    static class Program
    {

        static void Main()
        {
            VDFData vdfData = new VDFData();
        }
    }
}

Or, you can load up a file:

using Indieteur.VDFAPI;

namespace Demo
{
    static class Program
    {

        static void Main()
        {
            VDFData vdfData = new VDFData("C:\test.vdf");
        }
    }
}

And, you can also just read a block of string directly by setting the dataIsPath argument to false:

using Indieteur.VDFAPI;

namespace Demo
{
    static class Program
    {

        static void Main()
        {
            string someBlockText = "ExampleOnly{\n}";
            VDFData vdfData = new VDFData(someBlockText, false);
        }
    }
}

VDFData Class

The VDFData class is the main class of the VDFAPI and it has the following fields and methods:

[Field] Nodes

A list of root nodes under the VDF Data structure.

[Method] LoadData

This method has four overloads and what it does is basically clear the Nodes list and load it up with a new data depending on the argument that was passed on.

[Method] SaveToFile

As the name of the method states, it saves the VDF Data Structure into a file.

[Method] ToString (Overrided)

This method returns the parsable equivalent string of the VDF Data Structure. (The one that is saved and read from a file)

Understanding the Structure of a VDF File

The library follows the documentation provided by Steam (as per WebAPI/VDF - Official TF2 Wiki):

It has 3 control characters '{', '}' and '"'. Names and values may be quoted or not. The quote '"' charater must not be used within name or values, only for quoting whole tokens. You may use escape sequences wile parsing and add within a quoted token a " to add quotes within your name or token. When using Escape Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ), which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'. So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens. An open bracket '{' after a key name indicates a list of subkeys which is finished with a closing bracket '}'. Subkeys use the same definitions recursively. Whitespaces are space, return, newline and tabulator. Allowed Escape sequences are \n, \t, \, \n and ". The number character '#' is used for macro purposes (eg #include), don't use it as first charater in key names.

There are basically two types of structure/data in a VDF File. They are Nodes and Keys.

Nodes

Nodes can contain keys and child nodes. They normally follow the format:

"NodeName"
{
    //More Nodes and Keys here.
}

Keys

Keys is normally paired with a value but its value can also be set to null. The name can also be set to null.

  • A normal key value pair looks like this "Name" "Value"

  • A key without a value must follow this convention "Name" ""

  • A key without a name and value on the otherhand looks like "" ""

Comments

As per WebAPI/VDF - Official TF2 Wiki:

C++-style commenting is supported as seen in the above example. Comments can appear at the end of the line or on a line by itself. All content between the opening forward slashes (//) and the line terminator should be ignored.

Implementation of Nodes and Keys on the Library

The library provides a class for both Nodes and Keys:

  • VDFNode is the implementation of the Node structure of a VDF Data. It has 5 fields: Name which is the name of the Node, Parent which pertains to the node parent of the node if it has one, Keys which is basically a list of keys under the Node, Nodes which is a list of Nodes under the Node, ParentVDFStructure which references the parent VDFData.
  • VDFKey is the implementation of the Key-Value pair of a VDF Data. It has 3 fields: Name which is the name of the Key, Parent which pertains to the parent node of the key and Value which is the value of the key.

Extension Methods

The Library also provides extension methods for a VDFNode, VDFKey and for an array/lists (IEnumerable) of VDFNode and VDFKey.

VDFKey extension methods

  • Duplicate - Returns a clone of the key.
  • Migrate - Moves the key under a new parent node and sets the Parent property of the key to the new parent while removing the key from the previous parent's children key list.
  • RemoveKeyFromNode - Removes the key from its parent node.

VDFNode extension methods

  • Duplicate - Creates a copy of the nodes and the elements (nodes/keys) under it.
  • Migrate - Moves the selected node to a new parent node/to the root.
  • RemoveNodeFromParent - Removes the node from its parent node nodes list or from the VDFData Structure if it is a root node.

VDFNode/VDFKey IEnumerable/List extension methods

  • FindeNode/FindKey - Finds a node/key in a node/key collection by it's name.
  • FindNodeIndex/FindKeyIndex - Finds a node/key in a node/key collection by it's name and returns its index on the collection.
  • CleanRemoveKey/CleanRemoveNode (For List<Key> or List<Nodes> only) - Finds a node/key in a node/key collection by it's name and removes it from the list while also setting the node/key's parent property to null.

Miscellaneous

The FindNode, FindKey, FindNodeIndex, CleanRemoveKey and CleanRemoveNode has an argument called throwErrorIfNotFound which indicates if the method will throw an exception called TokenNotFoundException if the element that it was searching for was not found.

Steam Application Management API Library

This library provides basic information about the Steam Applications installed on the local computer. It also allows you to launch an app as well as listen for events like if a Steam App is being launched and/or is being updated. The library can also capture the process associated with the application (by guessing. It isn't completely foolproof.)

Setting Up

The first that you'll need to do is to make sure that you have the VDFAPI library or a copy of it located at the same directory as the Steam API Library as it is dependent to it. Afterwards, you'll need to reference/import the Indieteur.SAMAPI library.

Once you have done this, you'll need to reference the Indieteur.SAMAPI namespace to be able to use the classes under the library.

In order to be able to take advantage of the functionality of the library, you'll need to instantiate a SteamAppsManager class and you can do it in two ways.

using Indieteur.SAMAPI;

namespace Demo
{
    static class Program
    {

        static void Main()
        {
            SteamAppsManager sam = new SteamAppsManager();
        }
    }
}

OR

using Indieteur.SAMAPI;

namespace Demo
{
    static class Program
    {

        static void Main()
        {
            SteamAppsManager sam = new SteamAppsManager("PathToSteamRootFolder");
        }
    }
}

In the first example, we tell the class to automatically locate the Steam folder by using the registry keys managed by the Steam Client itself. This method assumes that you have the Steam Client properly installed on the local machine. Otherwise, it wouldn't work.

In the second example, we manually tell the class the location of the Steam folder.

SteamAppsManager Class

This is the main class of the library and it provides read only basic information about the Steam Applications installed on the local computer. It also allows you to listen for certain events like if a Steam App has been launched or has been updated etc.

After you have instantiated this class, InstallDir, LibraryFolders list and SteamApps list fields will automatically be populated.

It is also important to note that the data provided by the class is static meaning, it doesn't get updated. (e.g. if a new app has been installed or an app has been removed etc.)

Event Listener

The class also provides an event listener which you can start by calling the method StartListeningForEvents. What the event listener does is periodically check if an app has been launched and/or updated by checking certain associated registry keys for the Steam Application being checked. If an app has been started, is being updated, has exited and/or has stopped updating, the events associated with them will be fired accordingly.

The Event Listener will also try to capture the process associated with the app if it has been started by looping through the processes running on the computer and doing certain conditional checks on them. If a process passes the conditional check, the RunningProcess field of that app will be set to that certain process.

IMPORTANT NOTE: The StartListeningForEvents method creates a new thread which fires the method CheckForEvents periodically so thread safety must be kept in mind if you are dealing with the fields managed by the event listener. If you wish to avoid this altogether, what you can do is to not start the event listener and manually call the method CheckForEvents in a single thread instead and only fire it when you need it.

Fields

An instance of this class has 6 fields which are:

InstallDir

A string field which indicates the path to the installation directory of the Steam Client.

LibraryFolders

An IReadOnlyList collection of strings pertaining to the path of the Library Folders of the Steam Installation.

SteamApps

An IReadOnlyList collection of SteamApp that are installed on the local computer.

EventListenerRunning

This field returns true if the Event Listener is running and false if not.

EventListenerMustRun

Returns true if the Event Listener was set to run or false if not or if it was set to stop.

EventListenerInterval

The interval set between Event Listener checks in milliseconds.

Delegates

There are two delegates declaration in the class which signature must be followed by methods subscribed to the events on this class. They are:

dStatus_Change

This delegate takes a single argument which pertains to a SteamApp and returns nothing. Methods subscribed to SteamApp_OnUpdating, SteamApp_OnUpdateAbortOrFinish, SteamApp_OnLaunched and SteamApp_OnExit events must follow the signature of this delegate.

dExec_Change

This delegate takes two arguments; A SteamApp and a Process. The delegate also returns nothing. Methods subscribed to SteamApp_OnProcessDetected and SteamApp_OnProcessQuit must follow the signature of this delegate.

Events

There are 6 events that you can subscribe to under an instance of this class. They are fired accordingly by the CheckForEvents method when called or by the Event Listener if it is running.

SteamApp_OnUpdating

This event is fired when the Steam Client has updates the status of a certain app to updating. Methods must follow the delegate dStatus_Change's signature in order to subscribe to this. The event passes on the associated SteamApp instance which is being updated by the Steam Client.

SteamApp_OnUpdateAbortOrFinish

This event is fired when a Steam Application was being updated and then the update has finished, was paused, was cancelled or was stopped abruptly by the Steam Client. Methods must follow the delegate dStatus_Change's signature in order to subscribe to this. The event passes on the associated SteamApp instance that was being updated.

SteamApp_OnLaunched

This event is fired when the Steam Clients changes a status of a Steam Application to Launched. Methods must follow the delegate dStatus_Change's signature in order to subscribe to this. The event passes on the associated SteamApp instance that was started.

SteamApp_OnExit

This event is fired when a Steam Application has exited. Methods must follow the delegate dStatus_Change's signature in order to subscribe to this. The event passes on the associated exited SteamApp instance.

SteamApp_OnProcessDetected

This event is fired when the process pertaining to the Steam Application has been detected. Methods must follow the delegate dExec_Change's signature in order to subscribe to this. The event passes on the SteamApp instance associated with the process and the process (System.Diagnostics) itself.

SteamApp_OnProcessQuit

This event is fired when the process pertaining to the Steam Application has exited. Methods must follow the delegate dExec_Change's signature in order to subscribe to this. The event passes on the SteamApp instance associated with the process and the process (System.Diagnostics) itself.

Methods

Almost all the methods under the class is for the event listener. They are:

CheckForEvents

Updates the IsUpdating and IsRunning statuses of the SteamApps instances by checking certain registry keys associated with the SteamApp. The method will also try to capture the process associated with the SteamApp if the Steam Client has updated the status of the SteamApp to running. (This is the method called by the Event Listener periodically when it is started.)

SetEventListenerInterval

Sets the interval between the checks done by the Event Listener. The Event Listener must be running in order to set this. Otherwise, it'll throw an error.

StartListeningForEvents

Creates a new thread which will call the CheckForEvents method periodically. The Event Listener must not be running or the method will throw an error otherwise.

StopListeningForEvents

Stops the thread which is listening for events. The method will throw an error if the field EventListenerMustRun was already set to false. Also, a delay might occur before the thread completely stops executing.

Refresh

Refreshes the list of library paths and the list of steam applications installed fields of the class. This also stops the Event Listener if it is already running and starts it again after the refresh has completed.

Extension methods for IEnumerable Collection of SteamApp

The library provides 2 extension methods for an IEnumerable Collection of SteamApps which you can use to locate an App in the collection. They both return a reference to the SteamApp class that was found if located.

FindAppByName

Find a Steam App by its name in the SteamApps collection.

FindAppByID

Find a Steam App using its unique ID in the SteamApps collection.

Miscellaneous

Both the FindAppByName and FindAppByID method will throw an exception of type SteamAppNotFoundException if the Application was not found on the collection they are looping through and the argument ThrowErrorOnNotFound was set to true.

SteamApp Class

The Steam App class provides basic read only information about a single Steam Application.

Fields

Name

Returns the name of the Steam Application.

AppID

Returns the unique ID of the Steam Application.

InstallDir

Returns the path to the installation directory of the Steam Application.

InstallDirName

Returns the name of the installation directory of the Steam Application.

IsUpdating

Returns true if the status of the Steam Application was set to updating by the Steam Client and false if not. This field only gets updated if the Event Listener is running or the CheckForEvents/UpdateAppStatus method was called beforehand.

IsRunning

Returns true if the status of the Steam Application was set to running by the Steam Client and false if not. This field only gets updated if the Event Listener is running or the CheckForEvents/UpdateAppStatus method was called beforehand.

RunningProcess

Returns a Process class instance which contains detailed information about the running process pertaining to the application. This field only gets updated if the Event Listener is running or the CheckForEvents/UpdateAppStatus method was called beforehand.

ProcessNameToFind

Indicates the executable name of the application (without the .exe) which will be used to locate the running process when the app is launched. If left empty, the library will try to guess which process pertains to the app.

UnparsedData

Returns the VDF Data Structure pertaining to the Steam Application which was parsed to retrieve information like the Name, AppId, etc. of the app.

Methods

There are only two methods provided under the SteamApp class.

Launch

Launches the Steam Application.

UpdateAppStatus

Checks if the Steam Application is running or updating by checking certain registry keys and updates the fields IsUpdating and IsRunning accordingly. Also, sets the RunningProcess field if the process pertaining to the app is found.

Exiting a Steam App via the Library

There are many ways to exit a steam app using the library but you will need to make sure that the RunningProcess field of the Steam App is set to the running process pertaining to the app.

The library provides its own extension method for the System.Diagnostics.Process class which allows you to kill the process tree of the running Steam Application. The method is called KillProcessAndChildren which was based from In C#, how to kill a process tree reliably. The method doesn't take any argument so it should work out of the box when called.

Here's an example of how to use the extension method.

using Indieteur.SAMAPI;
using System.Diagnostics;

namespace Demo
{
    static class Program
    {
        
        static void Main()
        {
            SteamAppsManager SAM = new SteamAppsManager();
            SAM.SteamApp_OnProcessDetected += SAM_SteamApp_OnProcessDetected; //Subscribe to our event listener.
            SAM.StartListeningForEvents(); //The default interval is 1000 milliseconds or 1 second.
        }

        private static void SAM_SteamApp_OnProcessDetected(SteamApp app, Process process)
        {
            process.KillProcessAndChildren(); //Kills the process tree just right after it is detected.
        }
    }
}