Is this the right group for this?

From: smith (rcsTAKEOUT_at_smithvoiceTAKEOUT.com)
Date: 03/20/04


Date: Sat, 20 Mar 2004 20:01:22 GMT

Maybe this question could go to a .net api group but I know that you folks
here in the Windows Media SDK group would better understand the reason
behind the code so...

Looking for assistance in a port of one of the functions in the Managed
WMFormat Metadata C# code to vb.net.

I have the ShowAttributes working fine and that was the one I thought would
be the pain. But no matter how I slice it I keep getting "invalid
parameter" returned from AddAttribute.

I have C# and VB.net open side by side and every single parameter debugs
*exactly* the same at the byte level but the call fails.

Please no snobby C# vs VB non-answers. We need it working in VB.net because
we don't feel like including a C# dll in the distribution of this VB.net app
just for this one function and it's not opur fault that Microsoft has
decided not to get their WMFormat SDK act together for the majority of
developers who buy their language tools.

Anyone has a clue why the VB.net code that appears to do the same thing in
the same way with the same values fails?

Thanks, if you can figure it out.

-Robert Smith
Kirkland WA

First: C# and ported VB.net declarations:

C#:

using System;
using System.Runtime.InteropServices;

public class WMFSDKFunctions
{
  [DllImport("WMVCore.dll", EntryPoint="WMCreateEditor", SetLastError=true,
   CharSet=CharSet.Unicode, ExactSpelling=true,
   CallingConvention=CallingConvention.StdCall)]
   public static extern uint WMCreateEditor(
   [Out, MarshalAs(UnmanagedType.Interface)]out IWMMetadataEditor
ppMetadataEditor );

  [Guid("96406BD9-2B2B-11d3-B36B-00C04F6108FF"),
    InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
     public interface IWMMetadataEditor
 {
   uint Open( [In,MarshalAs(UnmanagedType.LPWStr)] string pwszFilename );
 uint Close();
 uint Flush();

 }

   [Guid("15CC68E3-27CC-4ecd-B222-3F5D02D80BD5"),
     InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
      public interface IWMHeaderInfo3
 {
   uint GetAttributeCount(
    [In] ushort wStreamNum,
           [Out] out ushort pcAttributes );

   uint GetAttributeByIndex(
     [In] ushort wIndex,
     [Out,In] ref ushort pwStreamNum,
     [Out, MarshalAs(UnmanagedType.LPWStr)] string pwszName,
     [Out,In] ref ushort pcchNameLen,
     [Out] out WMT_ATTR_DATATYPE pType,
     [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pValue,
     [Out,In] ref ushort pcbLength );
      }
 }

 public enum WMT_ATTR_DATATYPE
 {
           WMT_TYPE_DWORD = 0,
    WMT_TYPE_STRING = 1,
    WMT_TYPE_BINARY = 2,
    WMT_TYPE_BOOL = 3,
    WMT_TYPE_QWORD = 4,
    WMT_TYPE_WORD = 5,
    WMT_TYPE_GUID = 6,
 }
}

VB.net:

Imports System
Imports System.Runtime.InteropServices
Public Class WMFFunctions

    Public Declare Auto Function WMCreateEditor Lib "WMVCore.dll" Alias
"WMCreateEditor" _
     (ByRef ppMetadataEditor As IWMMetadataEditor) As UInt32

    <Guid("96406BD9-2B2B-11d3-B36B-00C04F6108FF"), _
        InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
        Public Interface IWMMetadataEditor

        Function Open(ByVal pwszFilename As String) As UInt32

        Function Close() As UInt32

        Function Flush() As UInt32

    End Interface

    <Guid("15CC68E3-27CC-4ecd-B222-3F5D02D80BD5"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
       Public Interface IWMHeaderInfo3

        Function GetAttributeCount(ByVal wStreamNum As UInt16, _
           ByRef pcAttributes As UInt16) As UInt32

        Function GetAttributeByIndex(ByVal wIndex As UInt16, _
         ByRef pwStreamNum As UInt16, _
        <MarshalAs(UnmanagedType.LPWStr)> ByVal pwszName As String, _
         ByRef pcchNameLen As UInt16, _
         ByRef pType As WMT_ATTR_DATATYPE, _
         <MarshalAs(UnmanagedType.LPArray)> ByVal pValue As Byte(), _
         ByRef pcbLength As UInt16) As UInt32
   end interface

 Public Enum WMT_ATTR_DATATYPE
        WMT_TYPE_DWORD = 0
        WMT_TYPE_STRING = 1
        WMT_TYPE_BINARY = 2
        WMT_TYPE_BOOL = 3
        WMT_TYPE_QWORD = 4
        WMT_TYPE_WORD = 5
        WMT_TYPE_GUID = 6
 End Enum

End Class

Working Methods:

C#:

bool ShowAttributes3( string pwszFileName, ushort wStreamNum )
 {
   try
    {
      IWMMetadataEditor MetadataEditor;
      IWMHeaderInfo3 HeaderInfo3;
      ushort wAttributeCount = 0;

      WMFSDKFunctions.WMCreateEditor( out MetadataEditor );
      MetadataEditor.Open( pwszFileName ) ;

      HeaderInfo3 = ( IWMHeaderInfo3 )MetadataEditor;

      HeaderInfo3.GetAttributeCountEx( wStreamNum, out wAttributeCount );

      for( ushort wAttribIndex = 0; wAttribIndex < wAttributeCount;
wAttribIndex++)
         {
           WMT_ATTR_DATATYPE wAttribType;
           ushort wLangIndex = 0;
           string pwszAttribName = null;
           byte[] pbAttribValue = null;
           ushort wAttribNameLen = 0;
           uint dwAttribValueLen = 0;

           HeaderInfo3.GetAttributeByIndexEx( wStreamNum,
             wAttribIndex,
             pwszAttribName,
             ref wAttribNameLen,
             out wAttribType,
             out wLangIndex,
             pbAttribValue,
             ref dwAttribValueLen);

           pwszAttribName = new String( ( char )0, wAttribNameLen );
           pbAttribValue = new byte[ dwAttribValueLen ];

           HeaderInfo3.GetAttributeByIndexEx( wStreamNum,
             wAttribIndex,
             pwszAttribName,
             ref wAttribNameLen,
             out wAttribType,
             out wLangIndex,
             pbAttribValue,
             ref dwAttribValueLen );

             //The following just prints to console ... works fine
             //PrintAttribute( wAttribIndex, wStreamNum,
                  pwszAttribName, wAttribType, 0, pbAttribValue,
dwAttribValueLen );
           }
    }
    catch( Exception e )
      {
       Console.WriteLine( e.Message );
       return( false );
      }

    return( true );
}

VB.Net version:

Public Function ReadAttributes(ByVal pwszFileName As String, ByVal
wStreamNum As Integer) As Boolean

   Dim MetadataEditor As WMFFunctions.IWMMetadataEditor
   Dim HeaderInfo3 As IWMHeaderInfo3
   Dim wAttributeCount As UInt16
   Try
       WMFFunctions.WMCreateEditor(MetadataEditor)
       MetadataEditor.Open(pwszFileName)
       HeaderInfo3 = MetadataEditor

       HeaderInfo3.GetAttributeCount(Convert.ToUInt16(wStreamNum),
wAttributeCount)

            For wAttribIndex As Integer = 0 To
Convert.ToInt16(wAttributeCount) - 1

              Dim wAttribType As WMT_ATTR_DATATYPE
              Dim pwszAttribName As String = Nothing
              Dim pbAttribValue As Byte() = Nothing
              Dim wAttribNameLen As UInt16
              Dim wAttribValueLen As UInt16

              'get the attribute "filler" information

HeaderInfo3.GetAttributeByIndex(Convert.ToUInt16(wAttribIndex), _
                   Convert.ToUInt16(wStreamNum), _
                   pwszAttribName, _
                   wAttribNameLen, _
                   wAttribType, _
                   pbAttribValue, _
                   wAttribValueLen)

               Dim arAttribTemp As Byte()
               ReDim arAttribTemp(Convert.ToInt16(wAttribValueLen))
               pbAttribValue = arAttribTemp
               pwszAttribName = New String("0",
Convert.ToInt16(wAttribNameLen))

               'now get the actual values

HeaderInfo3.GetAttributeByIndex(Convert.ToUInt16(wAttribIndex), _
                   Convert.ToUInt16(wStreamNum), _
                   pwszAttribName, _
                   Convert.ToUInt16(wAttribNameLen), _
                   wAttribType, _
                   pbAttribValue, _
                   Convert.ToUInt16(wAttribValueLen))

                Dim MyVal As String = ""

                'for our needs, just convert all to strings
                Select Case wAttribType
                    Case WMT_ATTR_DATATYPE.WMT_TYPE_STRING
                        MyVal = bytearraytostring(pbAttribValue)
                    Case WMT_ATTR_DATATYPE.WMT_TYPE_BOOL
                        If BitConverter.ToBoolean(pbAttribValue, 0) Then
                            MyVal = "True"
                        Else
                            MyVal = "False"
                        End If
                    Case WMT_ATTR_DATATYPE.WMT_TYPE_DWORD
                        Dim dwValue As UInt32 =
BitConverter.ToUInt32(pbAttribValue, 0)
                        MyVal = dwValue.ToString()
                    Case WMT_ATTR_DATATYPE.WMT_TYPE_QWORD
                        Dim qwValue As UInt64 =
BitConverter.ToUInt64(pbAttribValue, 0)
                        MyVal = qwValue.ToString
                    Case Else
                        MyVal = "nadda" 'ok for me
                End Select
                Dim Attributename As String = pwszAttribName.Substring(0,
pwszAttribName.Length - 1)

                'the following just sticks the values in the right
variables, works fine
                PutPropertyValue(Attributename, MyVal)

            Next

         Return True
        Catch ex As System.Runtime.InteropServices.COMException
            Throw ex
            Return False
        Catch ex As Exception
            'Todo: remove after final testing
            Throw ex
            Return False

        Finally
            If Not MetadataEditor Is Nothing Then
                MetadataEditor.Close()
            End If
        End Try

    End Function

The above work great, and the above calls to GetAttributeByIndex should be
way more involved than the one that sets an attribute.

Here is that code:

C# (works):

 bool AddAttrib( string pwszFileName, ushort wStreamNum, string
pwszAttribName,
                  ushort wAttribType, string pwszAttribValue, ushort
wLangIndex )
 {
   try
    {
    IWMMetadataEditor MetadataEditor;
    IWMHeaderInfo3 HeaderInfo3;
    byte[] pbAttribValue;
    int nAttribValueLen;
    WMT_ATTR_DATATYPE AttribDataType = ( WMT_ATTR_DATATYPE ) wAttribType;
    ushort wAttribIndex = 0;

    ushort nValueLength = ( ushort )( ( pwszAttribValue.Length + 1 ) * 2 );
    byte[] pbValue = new Byte[ nValueLength ];
    char[] c = pwszAttribValue.ToCharArray();
    Buffer.BlockCopy(c, 0, pbValue, 0, pwszAttribValue.Length * 2 );
    pbValue[ nValueLength - 2 ] = 0;
    pbValue[ nValueLength - 1 ] = 0;

    WMFSDKFunctions.WMCreateEditor( out MetadataEditor );

    MetadataEditor.Open( pwszFileName ) ;

    HeaderInfo3 = ( IWMHeaderInfo3 )MetadataEditor;

    HeaderInfo3.AddAttribute( wStreamNum,
       pwszAttribName,
       out wAttribIndex,
       AttribDataType,
       wLangIndex,
       pbValue,
       (uint)nValueLength);

    MetadataEditor.Flush();
    MetadataEditor.Close();
     }
  catch( Exception e )
   {
    Console.WriteLine( e.Message );
    return( false );
   }

  return( true );
}

VB.Net port of above Fails at AddAttribute call with Invalid Parameter But
The Parameters Are Exactly The Same:

Public Function AddStringAttrib(ByVal pwszFileName As String, _
    ByVal wStreamNum As UInt16, _
    ByVal pwszAttribName As String, _
    ByVal pwszAttribValue As String, _
    ByVal wLangIndex As UInt16) As Boolean

    Dim MetadataEditor As WMFFunctions.IWMMetadataEditor
    Dim HeaderInfo3 As IWMHeaderInfo3
    Try
      Dim wAttribIndex As Int16 = 0

      'convert the string to the valid array settings:
      Dim arTempAttrib As Byte()
      ReDim arTempAttrib (((Convert.ToInt16(pwszAttribValue.Length) + 1) *
2) - 1)
      Dim nValueLength As Integer = ((pwszAttribValue.Length + 1) * 2)
      Dim c As Char() = pwszAttribValue.ToCharArray

      Buffer.BlockCopy(pwszAttribValue.ToCharArray, 0, arTempAttrib , 0,
pwszAttribValue.Length * 2)
      arTempAttrib (x.Length - 2) = 0
      arTempAttrib (x.Length - 1) = 0

      WMFFunctions.WMCreateEditor(MetadataEditor)
      MetadataEditor.Open(pwszFileName)

      HeaderInfo3 = MetadataEditor

      'FAILS HERE but debugging shows every Byte the same as the C# version

      HeaderInfo3.AddAttribute(Convert.ToUInt16(0), _
         pwszAttribName, _
         Convert.ToUInt16(wAttribIndex), _
         WMT_ATTR_DATATYPE.WMT_TYPE_STRING, _
         Convert.ToUInt16(0), _
         arTempAttrib, _
         Convert.ToUInt16(arTempAttrib.Length))

      Return True

   Catch e As Exception
      MsgBox(e.ToString)
      Return False
   Finally
      if not MetadataEditor Is Nothing then
          MetadataEditor.Flush()
          MetadataEditor.Close()
      end if
   End Try

End Function



Relevant Pages

  • Re: Is C# support load device driver?
    ... how to manage driver loading/unloading using both PInvoke interop and WMI. ... string driverName; ... IntPtr fileHandle; ... databaseName, uint dwDesiredAccess); ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: IStorage::CopyTo throws Invalid Pointer exception
    ... [PreserveSig] ... uint CreateStream( ... string pwcsName, ... int reserved1, ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: SHGetFileInfo - Getting blank file type
    ... public IntPtr hIcon; ... public string szDisplayName; ... public static extern IntPtr SHGetFileInfo(string pszPath, uint ... ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags); ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: OSQL UserName and PWd
    ... ref uint mode); ... static string GetPasswordFromConsole() { ... GetConsoleMode(hCon, ref oldMode); ... string pwd = Console.ReadLine; ...
    (microsoft.public.dotnet.languages.csharp)