Thi*_*heT 6 c# com interop com-interop
我做了很多谷歌搜索,试图找到获取 COM 接口实例的标准方法。
Microsoft 在其文章COM Interop 第 1 部分:客户端教程中提供了一个示例:
// Create an instance of a COM coclass:
FilgraphManager graphManager = new FilgraphManager();
// See if it supports the IMediaControl COM interface.
// Note that this will throw a System.InvalidCastException if
// the cast fails. This is equivalent to QueryInterface for
// COM objects:
IMediaControl mc = (IMediaControl) graphManager;
// Now you call a method on a COM interface:
mc.Run();
Run Code Online (Sandbox Code Playgroud)
然而,看起来好像他们正在实例化一个 COM 对象并将其转换为 COM 接口。
对于我感兴趣的接口,IDesktopWallpaper似乎没有可实例化的实现 COM 对象。
我在这里找到的一个示例定义了一些被实例化的类,然后将其转换为接口,就像 msdn 示例一样:
[ComImport, Guid("C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD")]
internal class IDesktopWallpaper
{
}
[Guid("B92B56A9-8B55-4E14-9A89-0199BBB6F93B"), //B92B56A9-8B55-4E14-9A89-0199BBB6F93B
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface DesktopWallpaperInterface
{
// declared members
}
Run Code Online (Sandbox Code Playgroud)
我不明白实例化的对象是什么。它看起来像一个任意对象,它有一个GuidAttribute似乎表明它是一个实际的 COM 对象。
我在这里 System.Type找到了另一个例子,System.Runtime.InteropServices.Marshal实例化一个对象,然后将其转换为接口:
IntPtr ptrRet;
SHGetMalloc(out ptrRet);
System.Type mallocType = System.Type.GetType("IMalloc");
Object obj = Marshal.GetTypedObjectForIUnknown(ptrRet,mallocType);
IMalloc pMalloc = (IMalloc)obj;
Run Code Online (Sandbox Code Playgroud)
该方法似乎正在请求指向该接口的现有实例的指针。我在 Windows Shell 文档中找不到类似SHGetMallocfor的任何方法。IDesktopWallpaper
那么,长话短说,获取 COM 接口实例的标准方法是什么?
如果没有一刀切的解决方案,那么可以使用哪些标准方法来获取 COM 接口的实例?每种方法在什么情况下最有用?
下载 Windows 10 SDK 并根据IDesktopWallpaper 接口文档的要求部分引用该 SDK 后,我发现您可以从中查找 MIDLShobjidl.h并将其GuidAttribute用于您的接口声明,然后从中查找 CLSIDShobjidl.idl并在中使用它结合 和Type.GetTypeFromCLSID(Guid)来Activator.CreateInstance(Type)获取实现 的对象的实例IDesktopWallpaper。
我现在还看到,CLSID 是上面列出的第二种方法中用于看似GuidAttribute任意对象的内容。看起来这个方法允许您通过实例化类然后将实例转换为 COM 接口来模拟对象的托管实例化。
不过, 我仍然有兴趣知道这是否是最好的方法,以及此方法与其他方法相比有何优缺点。
您可以通过多种方法获取指向 COM 对象引用的指针:
CoCreateInstanceCLSIDFromProgID→CoCreateInstanceIRunningObjectTable.GetObjectType.GetTypeFromCLSID→Activator.CreateInstanceType.GetTypeFromProgID→Activator.CreateInstancenew SomeType()其中SomeType标有ComImportActivator.CreateInstance并new SomeType()最终命中CoCreateInstance(如果它们没有被各种应用程序域内的东西拦截)。CoCreateInstance对进程外服务器的调用最终将受到IRunningObjectTable类名称的影响(我认为)。最佳选择取决于您想要做什么:
ComImportComImport将可以工作,我更愿意调用CoCreateInstance以传递正确的CLSCTX.ComImport会导致服务器在进程内运行IRunningObjectTableCLSIDFromProgID或Type.GetTypeFromProgID无论我们如何获取对象的引用,我们都是从IUnknown(object在.Net中)开始,然后必须调用IUnknown->QueryInterface以获取指向特定接口的指针。.Net 中的调用是通过转换到标记为(通常用 注释)QueryInterface的接口来实现的。 ComVisibleGuidAttribute
在您指定的示例中,您最终会得到:
// based off of https://bitbucket.org/ciniml/desktopwallpaper
[ComImport]
[Guid("B92B56A9-8B55-4E14-9A89-0199BBB6F93B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDesktopWallpaper
{
void SetWallpaper([MarshalAs(UnmanagedType.LPWStr)] string monitorID, [MarshalAs(UnmanagedType.LPWStr)] string wallpaper);
[return: MarshalAs(UnmanagedType.LPWStr)]
string GetWallpaper([MarshalAs(UnmanagedType.LPWStr)] string monitorID);
[return: MarshalAs(UnmanagedType.LPWStr)]
string GetMonitorDevicePathAt(uint monitorIndex);
[return: MarshalAs(UnmanagedType.U4)]
uint GetMonitorDevicePathCount();
[return: MarshalAs(UnmanagedType.Struct)]
Rect GetMonitorRECT([MarshalAs(UnmanagedType.LPWStr)] string monitorID);
void SetBackgroundColor([MarshalAs(UnmanagedType.U4)] uint color);
[return: MarshalAs(UnmanagedType.U4)]
uint GetBackgroundColor();
void SetPosition([MarshalAs(UnmanagedType.I4)] DesktopWallpaperPosition position);
[return: MarshalAs(UnmanagedType.I4)]
DesktopWallpaperPosition GetPosition();
void SetSlideshow(IntPtr items);
IntPtr GetSlideshow();
void SetSlideshowOptions(DesktopSlideshowDirection options, uint slideshowTick);
void GetSlideshowOptions(out DesktopSlideshowDirection options, out uint slideshowTick);
void AdvanceSlideshow([MarshalAs(UnmanagedType.LPWStr)] string monitorID, [MarshalAs(UnmanagedType.I4)] DesktopSlideshowDirection direction);
DesktopSlideshowDirection GetStatus();
bool Enable();
}
[ComImport]
[Guid("C2CF3110-460E-4fc1-B9D0-8A1C0C9CC4BD")]
public class DesktopWallpaper
{
}
[Flags]
public enum DesktopSlideshowOptions
{
None = 0,
ShuffleImages = 0x01
}
[Flags]
public enum DesktopSlideshowState
{
None = 0,
Enabled = 0x01,
Slideshow = 0x02,
DisabledByRemoteSession = 0x04
}
public enum DesktopSlideshowDirection
{
Forward = 0,
Backward = 1
}
public enum DesktopWallpaperPosition
{
Center = 0,
Tile = 1,
Stretch = 2,
Fit = 3,
Fill = 4,
Span = 5,
}
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Run Code Online (Sandbox Code Playgroud)
其用法示例如下:
public partial class Form1 : Form
{
private IDesktopWallpaper Wallpaper;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Wallpaper = (IDesktopWallpaper)new DesktopWallpaper();
uint monitorCount = Wallpaper.GetMonitorDevicePathCount();
for (uint i = 0; i < monitorCount; i++)
{
lbMonitors.Items.Add(Wallpaper.GetMonitorDevicePathAt(i));
}
}
private void lbMonitors_SelectedValueChanged(object sender, EventArgs e)
{
var path = (string)lbMonitors.SelectedItem;
tbWallpaper.Text = Wallpaper.GetWallpaper(path);
}
}
Run Code Online (Sandbox Code Playgroud)
产生以下形式:
| 归档时间: |
|
| 查看次数: |
4679 次 |
| 最近记录: |