我正在尝试查找游戏的可执行文件;但是有些嵌套(例如方舟:生存进化)( A:\ Steam Games \ steamapps \ common \ ARK \ ShooterGame \ Binaries \ Win64 \ ShooterGame.exe )
我花了很长时间尝试寻找一种只找到相关的可执行文件的方法。
This link在我们不进行递归搜索时显示游戏。它找到最多但不是全部.exe的
This link显示了递归搜索的游戏,但同时显示了一堆二进制文件/ redist exe。
最初,我尝试排除“ bin”,“ binary”,“ binaries”,“ redist”文件夹,但后来却没有给我方舟:例如《生存进化》。
我还考虑过根据.exe的大小对其进行过滤,但是Aperture Tag的 QC_Eyes.exe 大小为3055KB,而Tomb Raider II.exe的大小为892KB。
这是我用来查找Steam安装目录并检查libraryfolders.vdf文件中库位置的方法。现在,我只是在写控制台,以便可以看到输出。
如果有人对我如何为合适的游戏找到合适的文件有任何提示,将不胜感激。谢谢
public void SearchSteam()
{
steamGameDirs.Clear();
string steam32 = "SOFTWARE\\VALVE\\";
string steam64 = "SOFTWARE\\Wow6432Node\\Valve\\";
string steam32path;
string steam64path;
string config32path;
string config64path;
RegistryKey key32 = Registry.LocalMachine.OpenSubKey(steam32);
RegistryKey key64 = Registry.LocalMachine.OpenSubKey(steam64);
foreach(string k32subKey in key32.GetSubKeyNames())
{
using (RegistryKey subKey = key32.OpenSubKey(k32subKey))
{
steam32path = subKey.GetValue("InstallPath").ToString();
config32path = steam32path + "/steamapps/libraryfolders.vdf";
if (File.Exists(config32path))
{
string[] configLines = File.ReadAllLines(config32path);
foreach(var item in configLines)
{
Console.WriteLine("32: " + item);
}
}
}
}
foreach(string k64subKey in key64.GetSubKeyNames())
{
using (RegistryKey subKey = key64.OpenSubKey(k64subKey))
{
steam64path = subKey.GetValue("InstallPath").ToString();
config64path = steam64path + "/steamapps/libraryfolders.vdf";
string driveRegex = @"[A-Z]:\\";
if (File.Exists(config64path))
{
string[] configLines = File.ReadAllLines(config64path);
foreach (var item in configLines)
{
Console.WriteLine("64: " + item);
Match match = Regex.Match(item, driveRegex);
if(item != string.Empty && match.Success)
{
string matched = match.ToString();
string item2 = item.Substring(item.IndexOf(matched));
item2 = item2.Replace("\\\\", "\\");
steamGameDirs.Add(item2);
}
}
steamGameDirs.Add(steam64path + "\\steamapps\\common\\");
}
}
}
foreach(string item in steamGameDirs)
{
string GameTitle;
string[] Executables = new string[0];
string[] steamGames = Directory.GetDirectories(item);
foreach (var dir in steamGames)
{
string title = dir.Substring(dir.IndexOf("\\common\\"));
string[] titlex = title.Split('\\');
title = titlex[2].ToString();
GameTitle = title;
Console.WriteLine("Title: " + GameTitle);
Console.WriteLine("Directory: " + dir);
string[] executables = Directory.GetFiles(dir, "*.exe", SearchOption.AllDirectories);
int num = 0;
foreach (var ex in executables)
{
//add "ex" to Executables[] if poss
Console.WriteLine(ex);
num++;
}
}
}
}
答案 0 :(得分:1)
我已经尽力了,所以首先我通过注册表检测到Steam的安装位置,然后检查/steamapps/libraryfolders.vdf中用户库的位置,然后检查这些库中是否有“顶级”目录。 “可执行文件。然后,如果在顶层目录中找不到该exe,该程序将允许用户选择自己的exe。
steamfiles模块当前未激活,似乎是目前最好的解决方案。
public void SearchSteam()
{
steamGameDirs.Clear();
string steam32 = "SOFTWARE\\VALVE\\";
string steam64 = "SOFTWARE\\Wow6432Node\\Valve\\";
string steam32path;
string steam64path;
string config32path;
string config64path;
RegistryKey key32 = Registry.LocalMachine.OpenSubKey(steam32);
RegistryKey key64 = Registry.LocalMachine.OpenSubKey(steam64);
if (key64.ToString() == null || key64.ToString() == "")
{
foreach (string k32subKey in key32.GetSubKeyNames())
{
using (RegistryKey subKey = key32.OpenSubKey(k32subKey))
{
steam32path = subKey.GetValue("InstallPath").ToString();
config32path = steam32path + "/steamapps/libraryfolders.vdf";
string driveRegex = @"[A-Z]:\\";
if (File.Exists(config32path))
{
string[] configLines = File.ReadAllLines(config32path);
foreach (var item in configLines)
{
Console.WriteLine("32: " + item);
Match match = Regex.Match(item, driveRegex);
if (item != string.Empty && match.Success)
{
string matched = match.ToString();
string item2 = item.Substring(item.IndexOf(matched));
item2 = item2.Replace("\\\\", "\\");
item2 = item2.Replace("\"", "\\steamapps\\common\\");
steamGameDirs.Add(item2);
}
}
steamGameDirs.Add(steam32path + "\\steamapps\\common\\");
}
}
}
}
foreach(string k64subKey in key64.GetSubKeyNames())
{
using (RegistryKey subKey = key64.OpenSubKey(k64subKey))
{
steam64path = subKey.GetValue("InstallPath").ToString();
config64path = steam64path + "/steamapps/libraryfolders.vdf";
string driveRegex = @"[A-Z]:\\";
if (File.Exists(config64path))
{
string[] configLines = File.ReadAllLines(config64path);
foreach (var item in configLines)
{
Console.WriteLine("64: " + item);
Match match = Regex.Match(item, driveRegex);
if(item != string.Empty && match.Success)
{
string matched = match.ToString();
string item2 = item.Substring(item.IndexOf(matched));
item2 = item2.Replace("\\\\", "\\");
item2 = item2.Replace("\"", "\\steamapps\\common\\");
steamGameDirs.Add(item2);
}
}
steamGameDirs.Add(steam64path + "\\steamapps\\common\\");
}
}
}
}
附加了代码,以便其他人可以看到我是如何做到的。我知道这不是最好的,但是可以正常工作
答案 1 :(得分:1)
密钥数据似乎在 appinfo.vdf 文件中。因此,为 Steam 游戏获取正确 EXE 文件的一些工作代码如下。如果游戏是带有指向 URL 的指针的 EA 游戏,或者 appinfo.vdf 中没有数据,则可以使用您以前的解决方案的后备方案。如果有人对 appinfo.vdf 有很好的解析器,那么代码会更好,而且不会像“IndexOf”解决方案那样笨拙。
以下代码中的 GetSteamPath() 可以更新为从注册表中获取。
我将使用该代码修复那些可追溯到那个匿名全球网址图标的琐碎蒸汽链接。
(用 .Net 5.0 编写 - 似乎 .4.7.2 的 IndexOf 很古怪。我认为不喜欢 \x00)
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace SteamAppsParser
{
class Program
{
static void Main(string[] args)
{
var libs = GetSteamLibs();
var apps = GetSteamApps(libs);
}
static List<AppInfo> GetSteamApps(List<string> steamLibs)
{
var apps = new List<AppInfo>();
foreach (var lib in steamLibs)
{
var appMetaDataPath = Path.Combine(lib, "SteamApps");
var files = Directory.GetFiles(appMetaDataPath, "*.acf");
foreach (var file in files)
{
var appInfo = GetAppInfo(file);
if (appInfo != null)
{
apps.Add(appInfo);
}
}
}
return apps;
}
static AppInfo GetAppInfo(string appMetaFile)
{
var fileDataLines = File.ReadAllLines(appMetaFile);
var dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var line in fileDataLines)
{
var match = Regex.Match(line, @"\s*""(?<key>\w+)""\s+""(?<val>.*)""");
if (match.Success)
{
var key = match.Groups["key"].Value;
var val = match.Groups["val"].Value;
dic[key] = val;
}
}
AppInfo appInfo = null;
if (dic.Keys.Count > 0)
{
appInfo = new AppInfo();
var appId = dic["appid"];
var name = dic["name"];
var installDir = dic["installDir"];
var path = Path.GetDirectoryName(appMetaFile);
var libGameRoot = Path.Combine(path, "common", installDir);
if (!Directory.Exists(libGameRoot)) return null;
appInfo.Id = appId;
appInfo.Name = name;
appInfo.Manifest = appMetaFile;
appInfo.GameRoot = libGameRoot;
appInfo.InstallDir = installDir;
appInfo.SteamUrl = $"steam://runsteamid/{appId}";
//if (appInfo.Name.StartsWith("Sid Meier"))
appInfo.Executable = GetExecutable(appInfo);
}
return appInfo;
}
static string _appInfoText = null;
static string GetExecutable(AppInfo appInfo)
{
if (_appInfoText == null)
{
var appInfoFile = Path.Combine(GetSteamPath(), "appcache", "appinfo.vdf");
var bytes = File.ReadAllBytes(appInfoFile);
_appInfoText = Encoding.UTF8.GetString(bytes);
}
var startIndex = 0;
int maxTries = 50;
var fullName = "";
do
{
var startOfDataArea = _appInfoText.IndexOf($"\x00\x01name\x00{appInfo.Name}\x00", startIndex);
if (startOfDataArea < 0 && maxTries == 50) startOfDataArea = _appInfoText.IndexOf($"\x00\x01gamedir\x00{appInfo.Name}\x00", startIndex); //Alternative1
if (startOfDataArea < 0 && maxTries == 50) startOfDataArea = _appInfoText.IndexOf($"\x00\x01name\x00{appInfo.Name}\x00", startIndex); //Alternative2
if (startOfDataArea > 0)
{
startIndex = startOfDataArea + 10;
int nextLaunch = -1;
do
{
var executable = _appInfoText.IndexOf($"\x00\x01executable\x00", startOfDataArea);
if (executable>-1 && nextLaunch == -1)
{
nextLaunch = _appInfoText.IndexOf($"\x00\x01launch\x00", executable);
}
if ((nextLaunch <= 0 || executable < nextLaunch) && executable > 0)
{
if (executable > 0)
{
executable += 10;
string filename = "";
while (_appInfoText[executable] != '\x00')
{
filename += _appInfoText[executable];
executable++;
}
if (filename.Contains("://"))
{
//EA or other external
return filename; //Need to use other means to grab the EXE here.
}
fullName = Path.Combine(appInfo.GameRoot, filename);
startOfDataArea = executable + 1;
startIndex = startOfDataArea + 10;
}
}
else
{
break;
}
}
while (!File.Exists(fullName) && maxTries-- > 0);
}
else
{
return null;
}
} while (!File.Exists(fullName) && maxTries-- > 0);
if (File.Exists(fullName)) return fullName;
return null;
}
static List<string> GetSteamLibs()
{
var steamPath = GetSteamPath();
var libraries = new List<string>() { steamPath };
var listFile = Path.Combine(steamPath, @"steamapps\libraryfolders.vdf");
var lines = File.ReadAllLines(listFile);
foreach (var line in lines)
{
var match = Regex.Match(line, @"""(?<path>\w:\\\\.*)""");
if (match.Success)
{
var path = match.Groups["path"].Value.Replace(@"\\", @"\");
if (Directory.Exists(path))
{
libraries.Add(path);
}
}
}
return libraries;
}
static string GetSteamPath()
{
return @"C:\Spill\Steam";
}
class AppInfo
{
public string Id { get; internal set; }
public string Name { get; internal set; }
public string SteamUrl { get; internal set; }
public string Manifest { get; internal set; }
public string GameRoot { get; internal set; }
public string Executable { get; internal set; }
public string InstallDir { get; internal set; }
public override string ToString()
{
return $"{Name} ({Id}) - {SteamUrl} - {Executable}";
}
}
}
}