Home All Groups Group Topic Archive Search About
Author
2 Apr 2005 12:26 AM
Peter Zentner
I have a weird problem...

A while ago I wrote some code in VB.NET which gets the block formats from
mshtml like shown below. I am now converting this into C# and I have the
problem that the IOleCommandTarget.Exec function doesn't return the
supported formats - in VB it works fine. (sorry code is long)

Thanks for helping
Peter

VB code:

Imports System.Runtime.InteropServices
' OLECMD
<StructLayout(LayoutKind.Sequential)> _
Public Structure OLECMD
    Public cmdID As Int32
    Public cmdf As Int32
End Structure
' OLECMDTEXT
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
Public Class OLECMDTEXT
    Public cmdtextf As OLECMDTEXTF
    Public cwActual As Int32
    Private cwBuf As Int32 = 256 'Make sure this is the same as SizeConst
below
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
    Public text As String
End Class

Public Enum OLECMDTEXTF
    OLECMDTEXTF_NONE = 0
    OLECMDTEXTF_NAME = 1
    OLECMDTEXTF_STATUS = 2
End Enum

' IOleCommandTarget interface
<ComVisible(True), ComImport(),
Guid("b722bccb-4e68-101b-a2bc-00aa00404770"), _
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IOleCommandTarget
    <PreserveSig()> Function QueryStatus(ByRef pguidCmdGroup As Guid, ByVal
cCmds As Int32, _
    <InAttribute(), Out(), MarshalAs(UnmanagedType.LPArray,
SizeParamIndex:=1)> ByVal prgCmds() As OLECMD, _
    <InAttribute(), Out()> ByVal pCmdText As OLECMDTEXT) As Integer

    <PreserveSig()> Function Exec(ByRef pguidCmdGroup As Guid, ByVal nCmdId
As Int32, _
    ByVal nCmdExecOpt As Int32, ByVal pvaIn As OLEVARIANT, ByVal pvaOut As
OLEVARIANT) As Integer
End Interface

<StructLayout(LayoutKind.Explicit)> _
Public Class OLEVARIANT
    <FieldOffset(0)> Public vt As System.Int16
    <FieldOffset(2)> Public wReserved1 As System.Int16
    <FieldOffset(4)> Public wReserved2 As System.Int16
    <FieldOffset(6)> Public wReserved3 As System.Int16
    <FieldOffset(8)> Public lVal As Integer
    <FieldOffset(8)> Public iVal As Short
    <FieldOffset(8)> Public bstrVal As IntPtr
    <FieldOffset(8)> Public pUnkVal As IntPtr
    <FieldOffset(8)> Public pArray As IntPtr
    <FieldOffset(8)> Public pvRecord As IntPtr
    <FieldOffset(12)> Public pRecInfo As IntPtr

    Public Sub Clear()
        VariantClear(Me)
    End Sub 'Clear

    Public Sub LoadString(ByVal Value As String)
        bstrVal = Marshal.StringToBSTR(Value)
    End Sub

    Public Function ToNativeObject() As Object
        Dim p As IntPtr

        Try
            'Allocate a buffer to hold the data in this OLEVARIANT
            p = Marshal.AllocCoTaskMem(Marshal.SizeOf(Me.GetType()))
            Marshal.StructureToPtr(Me, p, False)
            Return Marshal.GetObjectForNativeVariant(p)
        Finally
            'Called no matter what
            Marshal.FreeCoTaskMem(p)
        End Try
    End Function

    <DllImport("Oleaut32.dll", PreserveSig:=False)> _
    Private Shared Sub VariantClear(ByVal var As OLEVARIANT)
        ' Leave this blank. Call will be redirected to external DLL.
    End Sub
End Class 'OLEVARIANT

Get the formats...

Dim oOut As New OLEVARIANT()
Dim oIn As OLEVARIANT
Dim cmdt As IOleCommandTarget

Try
    Dim pguidCmdGroup As System.Guid = New
Guid("DE4BA900-59CA-11CF-9592-444553540000")
    cmdt = DirectCast(HtmlEditor1.Document, IOleCommandTarget)
    cmdt.Exec(pguidCmdGroup, cmdID,
onlyconnect.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, oIn, oOut)
Catch ex As Exception
    Throw New Exception("Exec Command: " & ex.Message)
End Try

C# code:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct OLECMD
{
    public long cmdID;
    public long cmdf;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public class OLECMDTEXT
{
    public OLECMDTEXTF cmdtextf;
    public long cwActual;
    private long cwBuf = 256; // make sure this is the same as SizeConst
below
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
    public String text;
}

public enum OLECMDTEXTF
{
    OLECMDTEXTF_NONE = 0,
    OLECMDTEXTF_NAME,
    OLECMDTEXTF_STATUS
}

[ComVisible(true), ComImport(),
Guid("b722bccb-4e68-101b-a2bc-00aa00404770"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleCommandTarget
{
    [PreserveSig()]
    int QueryStatus(ref Guid pguidCmdGroup, long cCmds, [In, Out]OLECMD
prgCmds, [In, Out]OLECMDTEXT pCmdText);

    [PreserveSig()]
    int Exec(ref Guid pguidCmdGroup, long nCmdId, long nCmdExecOpt,
OLEVARIANT pvaIn, OLEVARIANT pvaOut);
}

[StructLayout(LayoutKind.Explicit)]
public class OLEVARIANT
{
    [FieldOffset(0)]public int vt;
    [FieldOffset(2)]public int wReserved1;
    [FieldOffset(4)]public int wReserved2;
    [FieldOffset(6)]public int wReserved3;
    [FieldOffset(8)]public long lVal;
    [FieldOffset(8)]public int iVal;
    [FieldOffset(8)]public IntPtr bstrVal;
    [FieldOffset(8)]public IntPtr bUnkVal;
    [FieldOffset(8)]public IntPtr pArray;
    [FieldOffset(8)]public IntPtr pvRecord;
    [FieldOffset(12)]public IntPtr pRecInfo;

    public void Clear()
    {
        VariantClear(this);
    }

    public void LoadString(String Value)
    {
        bstrVal = Marshal.StringToBSTR(Value);
    }

    public object ToNativeObject()
    {
        IntPtr p = IntPtr.Zero;
        try
        {
            // allocate a buffer to hold the data in this OLEVARIANT
            p = Marshal.AllocCoTaskMem(Marshal.SizeOf(this.GetType()));
            Marshal.StructureToPtr(this, p, false);
            return Marshal.GetObjectForNativeVariant(p);
        }
        finally
        {
            // called no matter what
            Marshal.FreeCoTaskMem(p);
        }
    }

    [DllImport("Oleaut32.dll", PreserveSig=false)]
    private static extern void VariantClear(OLEVARIANT var);
}

Author
7 Apr 2005 10:25 PM
Leonhardt Wille
Well I don't know C# - but I think there's no need to work with the raw
interfaces :) The MFC contain a wrapper class for MSHTML, the
CHtmlEditCtrlBase class (afxhtml.h) which implements retrieval of
blockformats as follows: (sorry code is also long, but at least readable
:P )
Hope this helps you, I don't know whether the code can be ported to C#
or whether there's an equivalent class in C#.

HRESULT GetBlockFormatNames(CStringArray &sa) const
    {
        CComVariant vaRet;
        HRESULT hr = E_FAIL;
        long lStatus = QueryStatus(IDM_GETBLOCKFMTS);
        if (lStatus & OLECMDF_ENABLED || lStatus & OLECMDF_LATCHED)
        {
            if (S_OK == ExecCommand(IDM_GETBLOCKFMTS, OLECMDEXECOPT_DODEFAULT,
NULL, &vaRet))
            {                       
                if(vaRet.vt & VT_ARRAY)
                {
                    USES_CONVERSION;
                    SAFEARRAY *psa = vaRet.parray;

                    long lBound = 0,uBound = 0;
                    if(S_OK == SafeArrayGetLBound(psa,1,&lBound) &&
                       S_OK == SafeArrayGetUBound(psa,1,&uBound) )
                    {
                        for(long i=lBound; i<uBound; i++)
                        {   
                            CComBSTR bstrElem;
                            if( (S_OK == SafeArrayGetElement(psa, &i, &bstrElem) ))
                            {
                                sa.Add(CString(bstrElem));
                            }
                        }       
                        hr = S_OK;
                    }
                }
            }
        }

        if (vaRet.vt == VT_ERROR)
            hr = V_ERROR(&vaRet);

        return hr;
    }

regards, Leo

Peter Zentner wrote:
Show quote
> I have a weird problem...
>
> A while ago I wrote some code in VB.NET which gets the block formats from
> mshtml like shown below. I am now converting this into C# and I have the
> problem that the IOleCommandTarget.Exec function doesn't return the
> supported formats - in VB it works fine. (sorry code is long)
>
> Thanks for helping
> Peter
>
> VB code:
>
> Imports System.Runtime.InteropServices
> ' OLECMD
> <StructLayout(LayoutKind.Sequential)> _
> Public Structure OLECMD
>     Public cmdID As Int32
>     Public cmdf As Int32
> End Structure
> ' OLECMDTEXT
> <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _
> Public Class OLECMDTEXT
>     Public cmdtextf As OLECMDTEXTF
>     Public cwActual As Int32
>     Private cwBuf As Int32 = 256 'Make sure this is the same as SizeConst
> below
>     <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> _
>     Public text As String
> End Class
>
> Public Enum OLECMDTEXTF
>     OLECMDTEXTF_NONE = 0
>     OLECMDTEXTF_NAME = 1
>     OLECMDTEXTF_STATUS = 2
> End Enum
>
> ' IOleCommandTarget interface
> <ComVisible(True), ComImport(),
> Guid("b722bccb-4e68-101b-a2bc-00aa00404770"), _
> InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
> Public Interface IOleCommandTarget
>     <PreserveSig()> Function QueryStatus(ByRef pguidCmdGroup As Guid, ByVal
> cCmds As Int32, _
>     <InAttribute(), Out(), MarshalAs(UnmanagedType.LPArray,
> SizeParamIndex:=1)> ByVal prgCmds() As OLECMD, _
>     <InAttribute(), Out()> ByVal pCmdText As OLECMDTEXT) As Integer
>
>     <PreserveSig()> Function Exec(ByRef pguidCmdGroup As Guid, ByVal nCmdId
> As Int32, _
>     ByVal nCmdExecOpt As Int32, ByVal pvaIn As OLEVARIANT, ByVal pvaOut As
> OLEVARIANT) As Integer
> End Interface
>
> <StructLayout(LayoutKind.Explicit)> _
> Public Class OLEVARIANT
>     <FieldOffset(0)> Public vt As System.Int16
>     <FieldOffset(2)> Public wReserved1 As System.Int16
>     <FieldOffset(4)> Public wReserved2 As System.Int16
>     <FieldOffset(6)> Public wReserved3 As System.Int16
>     <FieldOffset(8)> Public lVal As Integer
>     <FieldOffset(8)> Public iVal As Short
>     <FieldOffset(8)> Public bstrVal As IntPtr
>     <FieldOffset(8)> Public pUnkVal As IntPtr
>     <FieldOffset(8)> Public pArray As IntPtr
>     <FieldOffset(8)> Public pvRecord As IntPtr
>     <FieldOffset(12)> Public pRecInfo As IntPtr
>
>     Public Sub Clear()
>         VariantClear(Me)
>     End Sub 'Clear
>
>     Public Sub LoadString(ByVal Value As String)
>         bstrVal = Marshal.StringToBSTR(Value)
>     End Sub
>
>     Public Function ToNativeObject() As Object
>         Dim p As IntPtr
>
>         Try
>             'Allocate a buffer to hold the data in this OLEVARIANT
>             p = Marshal.AllocCoTaskMem(Marshal.SizeOf(Me.GetType()))
>             Marshal.StructureToPtr(Me, p, False)
>             Return Marshal.GetObjectForNativeVariant(p)
>         Finally
>             'Called no matter what
>             Marshal.FreeCoTaskMem(p)
>         End Try
>     End Function
>
>     <DllImport("Oleaut32.dll", PreserveSig:=False)> _
>     Private Shared Sub VariantClear(ByVal var As OLEVARIANT)
>         ' Leave this blank. Call will be redirected to external DLL.
>     End Sub
> End Class 'OLEVARIANT
>
> Get the formats...
>
> Dim oOut As New OLEVARIANT()
> Dim oIn As OLEVARIANT
> Dim cmdt As IOleCommandTarget
>
> Try
>     Dim pguidCmdGroup As System.Guid = New
> Guid("DE4BA900-59CA-11CF-9592-444553540000")
>     cmdt = DirectCast(HtmlEditor1.Document, IOleCommandTarget)
>     cmdt.Exec(pguidCmdGroup, cmdID,
> onlyconnect.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER, oIn, oOut)
> Catch ex As Exception
>     Throw New Exception("Exec Command: " & ex.Message)
> End Try
>
> C# code:
>
> using System;
> using System.Runtime.InteropServices;
>
> [StructLayout(LayoutKind.Sequential)]
> public struct OLECMD
> {
>     public long cmdID;
>     public long cmdf;
> }
>
> [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
> public class OLECMDTEXT
> {
>     public OLECMDTEXTF cmdtextf;
>     public long cwActual;
>     private long cwBuf = 256; // make sure this is the same as SizeConst
> below
>     [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]
>     public String text;
> }
>
> public enum OLECMDTEXTF
> {
>     OLECMDTEXTF_NONE = 0,
>     OLECMDTEXTF_NAME,
>     OLECMDTEXTF_STATUS
> }
>
> [ComVisible(true), ComImport(),
> Guid("b722bccb-4e68-101b-a2bc-00aa00404770"),
> InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
> public interface IOleCommandTarget
> {
>     [PreserveSig()]
>     int QueryStatus(ref Guid pguidCmdGroup, long cCmds, [In, Out]OLECMD
> prgCmds, [In, Out]OLECMDTEXT pCmdText);
>
>     [PreserveSig()]
>     int Exec(ref Guid pguidCmdGroup, long nCmdId, long nCmdExecOpt,
> OLEVARIANT pvaIn, OLEVARIANT pvaOut);
> }
>
> [StructLayout(LayoutKind.Explicit)]
> public class OLEVARIANT
> {
>     [FieldOffset(0)]public int vt;
>     [FieldOffset(2)]public int wReserved1;
>     [FieldOffset(4)]public int wReserved2;
>     [FieldOffset(6)]public int wReserved3;
>     [FieldOffset(8)]public long lVal;
>     [FieldOffset(8)]public int iVal;
>     [FieldOffset(8)]public IntPtr bstrVal;
>     [FieldOffset(8)]public IntPtr bUnkVal;
>     [FieldOffset(8)]public IntPtr pArray;
>     [FieldOffset(8)]public IntPtr pvRecord;
>     [FieldOffset(12)]public IntPtr pRecInfo;
>
>     public void Clear()
>     {
>         VariantClear(this);
>     }
>
>     public void LoadString(String Value)
>     {
>         bstrVal = Marshal.StringToBSTR(Value);
>     }
>
>     public object ToNativeObject()
>     {
>         IntPtr p = IntPtr.Zero;
>         try
>         {
>             // allocate a buffer to hold the data in this OLEVARIANT
>             p = Marshal.AllocCoTaskMem(Marshal.SizeOf(this.GetType()));
>             Marshal.StructureToPtr(this, p, false);
>             return Marshal.GetObjectForNativeVariant(p);
>         }
>         finally
>         {
>             // called no matter what
>             Marshal.FreeCoTaskMem(p);
>         }
>     }
>
>     [DllImport("Oleaut32.dll", PreserveSig=false)]
>     private static extern void VariantClear(OLEVARIANT var);
> }
>
>

AddThis Social Bookmark Button