gpt4 book ai didi

c# - Windows 10 在使用已注册的动词调用 ShellExecute 时出错

转载 作者:太空宇宙 更新时间:2023-11-03 12:37:33 35 4
gpt4 key购买 nike

我们遇到了一个奇怪的问题,看来我们不是唯一的问题(见底部注释)。

问题是我们想用 shell 动词 printto 调用 ShellExecute。我们正在检查它是否已注册,如果已注册,则启动一个流程。可以在ProcessStartInfo.Verbs 中检索已注册的动词。 .

ProcessStartInfo startInfo = new ProcessStartInfo();

startInfo.FileName = @"C:\test.jpg";
startInfo.Verb = "printto";
startInfo.Arguments = "MyPrinter";
startInfo.UseShellExecute = true;

if (!startInfo.Verbs.Contains("printto"))
throw new Exception("PrintTo is not supported!");

try
{
Process.Start(startInfo);
}
catch (Win32Exception ex) when (ex.NativeErrorCode == 1155)
{
Console.WriteLine("Somehow printto is NOT registered...");
}

当使用照片 UWP 应用程序作为默认查看器运行 Windows 10 时,控制台将打印出代码为 1155 的 Win32Exception,这意味着文件类型未注册(对于给定的动词)。如果(旧的)Windows 图片查看器是默认的,则此方法有效。

另请注意,我们正在检查动词是否已注册,只有在注册时才调用它。微软似乎在这里做了一些不同的事情。

最大的问题是:为什么这两个 MS API 不再协同工作,我们如何避免这种情况?

注意:有一个旧的讨论,答案不是特别正确,但问题描述也略有不同: Windows 8 blows error on c# process for printing pdf file, how?

因此,我决定提出一个新问题,并希望它符合 SO 原则。

最佳答案

ProcessStartInfo.Verbs属性有些损坏,因为它没有考虑较新版本的 Windows(Windows 8 及更高版本 afaik)检索已注册应用程序的方式。该属性仅检查为 HKCR\.ext 下定义的 ProgId 注册的动词(在 reference source 中可以看出)并且不考虑其他地方,例如注册表项下方的 HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.ext或其他一些地方,例如通过策略定义。

获取注册的动词

最好的方法是不要依赖直接检查注册表(如 ProcessStartInfo 类所做的),而是使用适当的 Windows API 函数 AssocQueryString 检索关联的 ProgId:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32;

class Program
{
private static void Main(string[] args)
{
string fileName = @"E:\Pictures\Sample.jpg";
string progId = AssocQueryString(AssocStr.ASSOCSTR_PROGID, fileName);

var verbs = GetVerbsByProgId(progId);

if (!verbs.Contains("printto"))
{
throw new Exception("PrintTo is not supported!");
}

}

private static string[] GetVerbsByProgId(string progId)
{
var verbs = new List<string>();

if (!string.IsNullOrEmpty(progId))
{
using (var key = Registry.ClassesRoot.OpenSubKey(progId + "\\shell"))
{
if (key != null)
{
var names = key.GetSubKeyNames();
verbs.AddRange(
names.Where(
name =>
string.Compare(
name,
"new",
StringComparison.OrdinalIgnoreCase)
!= 0));
}
}
}

return verbs.ToArray();
}

private static string AssocQueryString(AssocStr association, string extension)
{
uint length = 0;
uint ret = AssocQueryString(
AssocF.ASSOCF_NONE, association, extension, "printto", null, ref length);
if (ret != 1) //expected S_FALSE
{
throw new Win32Exception();
}

var sb = new StringBuilder((int)length);
ret = AssocQueryString(
AssocF.ASSOCF_NONE, association, extension, null, sb, ref length);
if (ret != 0) //expected S_OK
{
throw new Win32Exception();
}

return sb.ToString();
}

[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern uint AssocQueryString(
AssocF flags,
AssocStr str,
string pszAssoc,
string pszExtra,
[Out] StringBuilder pszOut,
ref uint pcchOut);

[Flags]
private enum AssocF : uint
{
ASSOCF_NONE = 0x00000000,
ASSOCF_INIT_NOREMAPCLSID = 0x00000001,
ASSOCF_INIT_BYEXENAME = 0x00000002,
ASSOCF_OPEN_BYEXENAME = 0x00000002,
ASSOCF_INIT_DEFAULTTOSTAR = 0x00000004,
ASSOCF_INIT_DEFAULTTOFOLDER = 0x00000008,
ASSOCF_NOUSERSETTINGS = 0x00000010,
ASSOCF_NOTRUNCATE = 0x00000020,
ASSOCF_VERIFY = 0x00000040,
ASSOCF_REMAPRUNDLL = 0x00000080,
ASSOCF_NOFIXUPS = 0x00000100,
ASSOCF_IGNOREBASECLASS = 0x00000200,
ASSOCF_INIT_IGNOREUNKNOWN = 0x00000400,
ASSOCF_INIT_FIXED_PROGID = 0x00000800,
ASSOCF_IS_PROTOCOL = 0x00001000,
ASSOCF_INIT_FOR_FILE = 0x00002000
}

private enum AssocStr
{
ASSOCSTR_COMMAND = 1,
ASSOCSTR_EXECUTABLE,
ASSOCSTR_FRIENDLYDOCNAME,
ASSOCSTR_FRIENDLYAPPNAME,
ASSOCSTR_NOOPEN,
ASSOCSTR_SHELLNEWVALUE,
ASSOCSTR_DDECOMMAND,
ASSOCSTR_DDEIFEXEC,
ASSOCSTR_DDEAPPLICATION,
ASSOCSTR_DDETOPIC,
ASSOCSTR_INFOTIP,
ASSOCSTR_QUICKTIP,
ASSOCSTR_TILEINFO,
ASSOCSTR_CONTENTTYPE,
ASSOCSTR_DEFAULTICON,
ASSOCSTR_SHELLEXTENSION,
ASSOCSTR_DROPTARGET,
ASSOCSTR_DELEGATEEXECUTE,
ASSOCSTR_SUPPORTED_URI_PROTOCOLS,
ASSOCSTR_PROGID,
ASSOCSTR_APPID,
ASSOCSTR_APPPUBLISHER,
ASSOCSTR_APPICONREFERENCE,
ASSOCSTR_MAX
}
}

实际打印图像

但是,这并不能解决您的实际问题,即在 Windows 10 上打印图像。如果您的要求只是打印图像,您可以使用 PrintDocument 来实现。来自 System.Drawing.Printing 的类(class)相关帖子中描述的命名空间:Print images in C# :

PrintDocument pd = new PrintDocument();
pd.PrintPage += PrintPage;
pd.Print();

private void PrintPage(object o, PrintPageEventArgs e)
{
System.Drawing.Image img = System.Drawing.Image.FromFile("D:\\Foto.jpg");
Point loc = new Point(100, 100);
e.Graphics.DrawImage(img, loc);
}

关于c# - Windows 10 在使用已注册的动词调用 ShellExecute 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40338767/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com