是否可以将System .__ ComObject强制转换为某种类型,仅在运行时才知道? 我有以下代码
Type ComClassType = SomeDLLAssembly.GetType("ClassName");
dynamic comClassInstance = icf2.CreateInstanceLic(null, null, ComClassType.GUID, "License string");
//This will throw exception, because comClassInstance type is __ComObject and it does not contains ComClassMethod
comClassInstance.ComClassMethod();
当我将使用下面的代码时,它工作正常,但不幸的是我不能在我的代码中使用InvokeMember,因为它会非常复杂。
ComClassType.InvokeMember("ComClassMethod", BindingFlags.InvokeMethod, null, comClassInstance, null);
所以我想问一下,是否可以投出" comClassInstance" to" ComClassType"为了能够以这种方式调用方法comClassInstance.ComClassMethod();
答案 0 :(得分:5)
仅在运行时才知道?
至少部分问题。在编译时知道类型时,只能使用强制转换。你不知道所以你不能写出演员表达。但它比那更深,你不知道运行时的类型。 __ComObject
是RCW的低级包装器,它存储IDispatch接口指针。它没有说明您可以调用哪些方法以及可以使用哪些属性。
这是较低级别的输入,它是动态类型。这个术语的一般术语是后期绑定。这是另一种程序员编写的与代码接口的尝试调用方法。 C#团队长时间拒绝它,静态类型是语言的核心,迫使程序员使用Reflection。但不过,根据大众需求,他们在v4中添加了动态关键字,使得C#与Visual Basic保持一致,并始终支持它。您现在可以使用符号而不是将字符串传递给Reflection方法,而DLR会自动使用反射来进行调用。否则完全相同的编程工作,你必须知道字符串。
后期绑定的主要优点是它对版本控制具有弹性,这是第三方支持它的基本原因。但它的主要缺点是,如果你没有一本好的手册或者版本变化太多,那么你会得到一个讨厌的运行时异常,除了“它没有用”之外什么也不会告诉你。编译器无法帮助您正确完成,它不知道类型。 IntelliSense无法帮助您,它无法提供任何自动完成功能。只是在运行时爆炸,找出问题的唯一方法是翻阅(缺失)手册或与程序员交谈。
许多COM组件都支持早期和晚期绑定。您需要类型库来使用早期绑定,它是组件支持的接口和coclass的机器可读描述。它与.NET程序集中的元数据完全等效。并执行相同的角色,使用类型库,编译器现在可以检查您的代码,IntelliSense可以提供自动完成。
类型库通常嵌入在可执行文件(.dll或.exe)中,有时它作为单独的文件提供,.tlb和.olb是常见的扩展名。您可以使用Visual Studio的文件>打开>要查看可执行文件内部的文件,如果嵌入了类型库,您将看到TYPELIB节点。然后,您可以使用OleView.exe,文件>查看Typelib命令以查看其内容。并运行Tlbimp.exe以生成互操作库。
如果您找不到类型库并且没有合适的最新编程手册,那么只有电话可以帮助您。致电该组件的所有者或作者以获得帮助。
答案 1 :(得分:3)
调用COM对象的方法不需要强制转换。
C#dynamic可以用作(在调用之前不需要编写强制转换表达式)
public static void main(String[] args) throws FileNotFoundException, IOException {
System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe");
ChromeDriver browser = new ChromeDriver();
WebDriver driver = browser;
driver.get("https://news.google.co.in/");
driver.manage().timeouts().implicitlyWait(500, TimeUnit.SECONDS);
JavascriptExecutor jse = (JavascriptExecutor) driver;
Long clientHeight = (Long) jse.executeScript("return document.documentElement.clientHeight");
Long scrollHeight = (Long) jse.executeScript("return document.documentElement.scrollHeight");
int screens = 0, xAxis = 0, yAxis = clientHeight.intValue();
String screenNames = "D:\\Screenshots\\Yash";
for (screens = 0; ; screens++) {
if (scrollHeight.intValue() - xAxis < clientHeight) {
File crop = new File(screenNames + screens+".jpg");
FileUtils.copyFile(browser.getScreenshotAs(OutputType.FILE), crop);
BufferedImage image = ImageIO.read(new FileInputStream(crop));
int y_Axixs = scrollHeight.intValue() - xAxis;
BufferedImage croppedImage = image.getSubimage(0, image.getHeight()-y_Axixs, image.getWidth(), y_Axixs);
ImageIO.write(croppedImage, "jpg", crop);
break;
}
FileUtils.copyFile(browser.getScreenshotAs(OutputType.FILE), new File(screenNames + screens+".jpg"));
jse.executeScript("window.scrollBy("+ xAxis +", "+yAxis+")");
jse.executeScript("var elems = window.document.getElementsByTagName('*');"
+ " for(i = 0; i < elems.length; i++) { "
+ " var elemStyle = window.getComputedStyle(elems[i], null);"
+ " if(elemStyle.getPropertyValue('position') == 'fixed' && elems[i].innerHTML.length != 0 ){"
+ " elems[i].parentNode.removeChild(elems[i]); "
+ "}}"); // Sticky Content Removes
xAxis += yAxis;
}
driver.quit();
}
OR
在vb.net中创建一个库项目(Option strict应为Off,Project属性)。在vb.net中完成与COM相关的所有内容,并在C#项目中添加对此的引用。
将实例类型声明为dynamic comClassInstance = Activator.CreateInstance(Type.GetTypeFromProgID("ClassName"));
comClassInstance.ComClassMethod();
var result = comClassInstance.ComClassFMethod(param);
。
对COM组件进行Object
调用,并将方法调用为CreateObject
comClassInstance.ComClassMethod()
答案 2 :(得分:0)
如果你的&#34; ClassName&#34; COM是可见的,您应该能够使用基本类型转换来转换返回的com对象。
Type ComClassType = SomeDLLAssembly.GetType("ClassName");
ClassName myInstance = (ClassName)icf2.CreateInstanceLic(null, null, ComClassType.GUID, "License string");
myInstance.ComClassMethod();
答案 3 :(得分:0)
我不完全确定这是你所追求的,如果是,你需要根据你创建实例的方式进行调整,因为我并没有真正关注icf2的来源。但是,如果您只是尝试清理大多数代码与COM对象交互的方式,那么一种方法是扩展dynamic
解析过程。您可以通过继承DynamicObject
并覆盖TryInvokeMember
方法来实现此目的(您可以覆盖其他方法,但TryInvokeMember
似乎是关键方法)。当动态调度程序无法找到方法时,可以在对象上调用此方法,以便您可以执行某些自定义解析。
所以,在基本层面(就像我跳过错误处理的所有好例子一样),你可以写一个这样的类:
public class ComWrapper : DynamicObject {
Object _instance;
Type _type;
// Create + save type/instance information in constructor
// You seem to do this differently, so you'd want to change this...
public ComWrapper(Guid guid) {
_type = Type.GetTypeFromCLSID(guid, true);
_instance = Activator.CreateInstance(_type, true);
}
// Invoke requested method, passing in args and assigning return value
// to result
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args,
out object result) {
result = _type.InvokeMember(binder.Name,
System.Reflection.BindingFlags.InvokeMethod, null,
_instance, args);
return true; // Return true to indicate it's been handled
}
}
然后,基于an example which creates an instance of Word, then tells it to quit,您将使用上面的代码:
dynamic val = new ComWrapper(new Guid("{000209FF-0000-0000-C000-000000000046}"));
val.Quit(0, 0, false );
我认为动态类很可能已经做了类似于上面的内容,所以这可能不会解决你的问题。但是,它可能会让您更接近找到解决方案。例如,在不支持调度的COM对象上调用方法将通过InvokeMethod
报告错误,但在通过动态实例调用时将报告Does not contain a definition
。