来自脚本而非 ISE 的 WinAPI

WinAPI from a script, not the ISE

我正在使用这段代码,它在 ISE 中运行良好,但在 运行 作为脚本时却无法正常运行。我得到的错误是 "Specified cast is not valid",它发生在此处显示的最后一行。我认为这实际上是 Set-Type 的问题,但我删除了 -ignoreWarnings 并且我没有得到任何问题的迹象。如果我以 运行 以管理员身份启动脚本,我会得到同样的错误。我希望 WinAPI 不局限于 ISE

Add-Type -typeDefinition @'
using System; 
using System.Runtime.InteropServices; 
namespace WinAPIs { 
    public class UserAccountPicture { 
        [DllImport("shell32.dll", EntryPoint = "#262", CharSet = CharSet.Unicode, PreserveSig = false)] 
        public static extern void SetUserTile(string username, int notneeded, string picturefilename); 
    }
}
'@ -ignoreWarnings
[WinAPIs.UserAccountPicture]::SetUserTile($userName, 0, $imagePath)

我也尝试了另一种方法,结果相同。

$methodDefinition = @'
[DllImport("shell32.dll", EntryPoint = "#262", CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern bool SetUserTile(string username, int notneeded, string picturefilename);
'@

$shell32 = Add-Type -memberDefinition:$methodDefinition -name:'shell32' -namespace:'Win32' -passThru

$shell32::SetUserTile("RTC", 0, "$scriptPath\RTC.bmp")

我在这里有点不适应,所以希望有人能指出我的错误。或者验证我不能在脚本中执行此操作。

谢谢!

来自this post

CoInitialize(NULL)/CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) must be called prior to calling this function.

你试过事先调用这个函数吗?

您的 PowerShell 版本是多少?因为这可能与STA\MTA模式有关:

Did you know that in Windows PowerShell 3.0, we changed the Windows PowerShell console from multi-threaded apartment (MTA) to single-threaded apartment (STA)? If you did not notice the change, you are probably not doing anything that requires MTA mode. If all of a sudden, you have some Windows PowerShell 2.0 or even Windows PowerShell 1.0 scripts that no longer work, now you know why.

您可以这样检查您的 PS 主持人的模式:$host.Runspace.ApartmentState

即使您使用的是 PS 3 及更高版本,您也可以尝试使用 -Sta-Mta 参数启动 PowerShell.exe 并查看是否这样做区别。

此外,我已经在 PS 5.0 上尝试了您的代码,它在 ISE 和 PowerShell 控制台中都有效。

更新:这是defintely STA\MTA issue

The function is in shell32.dll. It doesn’t have a name but the ordinal 262. It takes a username (MACHINE\user or DOMAIN\user format), a zero (the usual reserved stuff, I guess), and a picture path (can be any well known format or size) parameter, and returns an HRESULT. If you pass a null username, then the result of GetUserNameEx with a NameSamCompatible parameter will be used. It uses COM inside, and only works on STA threads (otherwise throws an InvalidCastException (0×80004002, E_NOINTERFACE)).

我不明白的是,为什么您的 PowerShell 控制台以 MTA 运行,它不应该这样做。