Note that there are some explanatory texts on larger screens.

plurals
  1. POIs it posible to perform QueryInterface on behalf of VBScript
    primarykey
    data
    text
    <p>I'm trying to create a COM class with one method that will cast an object to a specific interface on behalf of VBScript.</p> <p>This is the method signature I'm using:<br /> <code>public object GetInterface(object unknown, string iid)</code></p> <p>I thought this would be possible because if the method explicitly declares the return type as : <br /> <code>public IRequestedInterface GetInterface(object unknown, string iid)</code> </p> <p>Then VBScript gets the reference to the desired interface.</p> <p>So I tried just casting to the interface<br /> <code>return (IRequestedInterface)unknown;</code> </p> <p>Unfortunately, VBScript gets a reference to the default interface instead of the requested interface.</p> <p>I have tried getting round this by creating a custom marshaller using <code>ICustomMarshaler</code>.<br /> I thought this would work because the method <code>MarshalManagedToNative</code> returns a <code>IntPtr</code>.</p> <p>Because of this I thought that if i just returned the <code>IntPtr</code> to the interface <br /> <code>return Marshal.GetComInterfaceForObject(unknown, typeof(IRequestedInterface));</code><br /> it would work. But, obviously, it didn't have the desired effect :(</p> <p>So does anybody know if it is posible and how you would do it?</p> <p>EDIT:</p> <p>I thought it would be helpful to add a concrete example (although it is contrived) to explain why I haven't accepted that VBScript will always get the default interface. I'm still clinging to my hope.</p> <p>Below you will find the contents of 3 files, 'TestLib.cs', 'Build.cmd' and 'Test.vbs'. These hopefully demonstrate why I still think it 'should' be possible.</p> <p>Note: I have tested this on Windows XP SP3 (x86).</p> <p>TestLib.cs</p> <pre><code>using System; using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; [assembly: ComVisible(false)] [assembly: Guid("64e20009-c664-4883-a6e5-1e36a31a0fd8")] [assembly: AssemblyVersion("2012.06.*")] [ComVisible(true)] [Guid("EB77C7B1-D1B9-4BB3-9D63-FBFBD56C9ABA")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IPerformQi { [DispId(1000)] object GetInterface(object unknown, string iid); [DispId(2000)] IRequested GetIRequested(object unknown); } [ComVisible(true)] [Guid("7742BC0A-8719-483E-B1DF-AE9CD9A958DC")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IDefault { [DispId(1000)] void SayHello(string name); } [ComVisible(true)] [Guid("FFF34296-2A06-47D4-B09C-B93B63D5CC53")] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IRequested { [DispId(1000)] void SayGoodbye(string name); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof(IPerformQi))] [Guid("222BB88D-B9FA-4F23-8DB3-BA998F4E668B")] [ProgId("TestLib.PerformQi")] public class PerformQi : IPerformQi { object IPerformQi.GetInterface(object unknown, string iid) { if(iid == "FFF34296-2A06-47D4-B09C-B93B63D5CC53") return (IRequested)unknown; throw new Exception("Unable to find inteface"); } IRequested IPerformQi.GetIRequested(object unknown) { return (IRequested)unknown; } } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [ComDefaultInterface(typeof(IDefault))] [Guid("174ABED6-3325-4878-89E3-BF8BD1107488")] [ProgId("TestLib.Test")] public class Test : IDefault, IRequested { void IDefault.SayHello(string name) { MessageBox.Show(string.Format("Hello '{0}'", name)); } void IRequested.SayGoodbye(string name) { MessageBox.Show(string.Format("Goodbye '{0}'", name)); } }</code></pre> <p>Build.cmd</p> <pre><code>"%windir%\Microsoft.Net\Framework\v4.0.30319\csc.exe" /out:TestLib.dll /target:library /r:System.Windows.Forms.dll TestLib.cs "%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" TestLib.dll /codebase /tlb:TestLib.tlb PAUSE</code></pre> <p>Test.vbs</p> <pre><code>Dim oPerformQi 'As TestLib.PerformQi Dim oTest 'As TestLib.Test Dim oTest2 'As IRequested Dim oTest3 'As IRequested Set oPerformQi = CreateObject("TestLib.PerformQi") Set oTest = CreateObject("TestLib.Test") Call oTest.SayHello("Robert") Set oTest2 = oPerformQi.GetIRequested(oTest) 'Note: This works Call oTest2.SayGoodbye("Robert") Set oTest3 = oPerformQi.GetInterface(oTest, "FFF34296-2A06-47D4-B09C-B93B63D5CC53") 'Note: This does not work Call oTest3.SayGoodbye("Robert")</code></pre> <p>Using the call <code>oPerformQi.GetIRequested(oTest)</code> makes the call to <code>oTest3.SayGoodbye("Robert")</code> work. This makes me think you are not limited to just the default interface in VBS.</p> <p>Perhaps .Net is not capable of returning the specified interface because of an implicit cast on the return value? Ideally I would use generics for this, but as we all know COM does not support genrics.</p> <p>Under this restriction is there any other way that you can think of to achieve this?</p> <p>EDIT 2:</p> <p>I have found that I can achieve this using VB6, below is the code for the class.</p> <pre><code>Option Explicit Public Function GetInterface(ByVal oUnknown As Object, ByVal IID As String) As Variant Dim oIRequested As IRequested If IID = "FFF34296-2A06-47D4-B09C-B93B63D5CC53" Then Set oIRequested = oUnknown Set GetInterface = oIRequested Else Err.Raise 1, , "Unable to find inteface" End If End Function </code></pre> <p>I would still like to find a C# version if anybody can shed some light on the subject i would appreciate it.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload