如何使用C#查找第三方应用程序(如Google Earth)的安装目录

本文关键字:安装 Earth 何使用 查找 第三方 应用程序 Google | 更新日期: 2023-09-27 17:48:53

我有以下代码片段,它使用硬编码路径启动Google Earth进程:

var process =
    new Process
        {
            StartInfo =
                {
                    //TODO: Get location of google earth executable from registry
                    FileName = @"C:'Program Files'Google'Google Earth'googleearth.exe",
                    Arguments = "'"" + kmlPath + "'""
                }
        };
process.Start();

我想通过编程从某个地方(很可能是注册表)获取googleearth.exe的安装位置。

如何使用C#查找第三方应用程序(如Google Earth)的安装目录

显然,如果您要打开与程序相关联的特定文件,则最好通过该文件启动它(例如,用户可能有一个与他们喜欢使用的文件类型相关联的程序)。

这是我过去使用过的一种方法,用于启动与特定文件类型相关联的应用程序,但实际上没有打开文件。也许有更好的方法。

static Regex pathArgumentsRegex = new Regex(@"(%'d+)|(""%'d+"")", RegexOptions.ExplicitCapture);
static string GetPathAssociatedWithFileExtension(string extension)
{
    RegistryKey extensionKey = Registry.ClassesRoot.OpenSubKey(extension);
    if (extensionKey != null)
    {
        object applicationName = extensionKey.GetValue(string.Empty);
        if (applicationName != null)
        {
            RegistryKey commandKey = Registry.ClassesRoot.OpenSubKey(applicationName.ToString() + @"'shell'open'command");
            if (commandKey != null)
            {
                object command = commandKey.GetValue(string.Empty);
                if (command != null)
                {
                    return pathArgumentsRegex.Replace(command.ToString(), "");
                }
            }
        }
    }
    return null;
}

不过,有时也有这样的情况,即您希望在不打开文件的情况下启动特定程序。通常(希望)程序有一个带有安装位置的注册表项。下面是一个如何以这种方式启动谷歌地球的例子。

private static string GetGoogleEarthExePath()
{
    RegistryKey googleEarthRK = Registry.CurrentUser.OpenSubKey(@"Software'Google'Google Earth Plus'");
    if (googleEarthRK != null)
    {
        object rootDir = googleEarthRK.GetValue("InstallLocation");
        if (rootDir != null)
        {
            return Path.Combine(rootDir.ToString(), "googleearth.exe");
        }
    }
    return null;
}

从给出的例子中,您可以判断出我实际上正试图将KML文件传递给Google Earth。因此,解决此问题的最简单方法是依赖KML与Google Earth的文件关联,并使用以下内容作为整个示例的替代:

Process.Start(kmlPath);

这是通过回顾这个问题的答案发现的。

这也可以:(C#代码)

        Type type = Type.GetTypeFromProgID("WindowsInstaller.Installer");
        Installer msi = (Installer)Activator.CreateInstance(type);
        foreach (string productcode in msi.Products)
        {
            string productname = msi.get_ProductInfo(productcode, "InstalledProductName");
            if (productname.Contains("Google Earth"))
            {
                string installdir = msi.get_ProductInfo(productcode, "InstallLocation");
                Console.WriteLine("{0}: {1} @({2})", productcode, productname, installdir);
            }
        }

这是我刚刚编写的C++版本。直接取自ICR的C#版本。

void PrintString(CString string)
{
    std::wcout << static_cast<LPCTSTR>(string) << endl;
}
CString GetClassesRootKeyValue(const wchar_t * keyName)
{
    HKEY hkey;
    TCHAR keyNameCopy[256] = {0};
    _tcscpy_s(keyNameCopy, 256, keyName);
    BOOL bResult = SUCCEEDED(::RegOpenKey(HKEY_CLASSES_ROOT, keyNameCopy, &hkey));
    CString hkeyValue = CString("");
    if (bResult) {
        TCHAR temporaryValueBuffer[256];
        DWORD bufferSize = sizeof (temporaryValueBuffer);
        DWORD type;
        bResult = SUCCEEDED(RegQueryValueEx(hkey, _T(""), NULL, &type, (BYTE*)temporaryValueBuffer, &bufferSize)) && (bufferSize > 1);
        if (bResult) {
            hkeyValue = CString(temporaryValueBuffer);
        }
        RegCloseKey(hkey);
        return hkeyValue;
    }
    return hkeyValue;
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;
    // initialize MFC and print and error on failure
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: change error code to suit your needs
        _tprintf(_T("Fatal Error: MFC initialization failed'n"));
        nRetCode = 1;
    }
    else
    {
        CString dwgAppName = GetClassesRootKeyValue(_T(".dwg"));
        PrintString(dwgAppName);
        dwgAppName.Append(_T("''shell''open''command"));
        PrintString(dwgAppName);
        CString trueViewOpenCommand = GetClassesRootKeyValue(static_cast<LPCTSTR>(dwgAppName));
        PrintString(trueViewOpenCommand);
        //  Shell open command usually ends with a "%1" for commandline params.  We don't want that,
        //  so strip it off.
        int firstParameterIndex = trueViewOpenCommand.Find(_T("%"));
        PrintString(trueViewOpenCommand.Left(firstParameterIndex).TrimRight('"').TrimRight(' '));

        cout << "'n'nPress <enter> to exit...";
        getchar();
    }
}