Windows Vista Forums

Passing ref type to methods using invocation within Powershell
  1. #1



    Junior Member
    Join Date : Mar 2007
    Posts : 22
    Local Time: 12:59 PM

    Passing ref type to methods using invocation within Powershell

    In the code below [my5.stuff]::EnumDisplayDevices($null,1,[ref]$test,0)
    does not work because the $null is cast as ""

    The following line does return true but $test is not populated with the expected details.
    Presumably this is because [my5.DISPLAY_DEVICE]$test is not a reference
    $obj.gettype().getmethod("EnumDisplayDevices").invoke($obj,@($null,[uint32]0,[my5.DISPLAY_DEVICE]$test,[uint32]0))

    How can I pass a reference type to the invoked method so that $test is populated with the details for Display Device 0?

    I have tried all sorts of different ways can cannot get $test set as needed.

    (Watch out for line wrapping in the code)

    Thanks

    ####Code####

    $source=@"
    using System;
    using System.Runtime.InteropServices;
    using System.Threading;

    namespace My5
    {
    // Remove the next flags line and the flags will be returned as integers
    [Flags()]
    public enum DisplayDeviceStateFlags : int
    {
    /// <summary>The device is part of the desktop.</summary>
    AttachedToDesktop = 0x1,
    MultiDriver = 0x2,
    /// <summary>The device is part of the desktop.</summary>
    PrimaryDevice = 0x4,
    /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
    MirroringDriver = 0x8,
    /// <summary>The device is VGA compatible.</summary>
    VGACompatible = 0x16,
    /// <summary>The device is removable; it cannot be the primary display.</summary>
    Removable = 0x20,
    /// <summary>The device has more display modes than its output devices support.</summary>
    ModesPruned = 0x8000000,
    Remote = 0x4000000,
    Disconnect = 0x2000000
    }

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
    public struct DISPLAY_DEVICE
    {
    [MarshalAs(UnmanagedType.U4)]
    public int cb;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
    public string DeviceName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
    public string DeviceString;
    [MarshalAs(UnmanagedType.U4)]
    public DisplayDeviceStateFlags StateFlags;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
    public string DeviceID;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
    public string DeviceKey;
    }


    }
    "@

    add-type -typedefinition $source

    $test=new-object my5.display_device
    $test.cb=[system.runtime.interopservices.marshal]::sizeof($test)

    #The following line errors
    [my5.stuff]::EnumDisplayDevices($null,1,$test,0)
    #Argument: '3' should be a System.Management.Automation.PSReference. Use [ref].



    #The following line returns False and $test is not set to anything - this is due to the $null being cast as ""
    [my5.stuff]::EnumDisplayDevices($null,1,[ref]$test,0)

    $obj=(new-object -typename "my5.stuff")
    #The following method was suggested to get round the 'null' issue
    #but, while it returns True, $test is not set.
    #Presumably this is because [my5.DISPLAY_DEVICE]$test is not a reference
    $obj.gettype().getmethod("EnumDisplayDevices").invoke($obj,@($null,[uint32]0,[my5.DISPLAY_DEVICE]$test,[uint32]0))


    $obj.gettype().getmethod("EnumDisplayDevices").getparameters()


    #ParameterType : System.String
    #Name : lpDevice
    #DefaultValue :
    #RawDefaultValue :
    #Position : 0
    #Attributes : None
    #Member : Boolean EnumDisplayDevices(System.String, UInt32, My5.DISPLAY_DEVICE ByRef, UInt32)
    #IsIn : False
    #IsOut : False
    #IsLcid : False
    #IsRetval : False
    #IsOptional : False
    #MetadataToken : 134217729

    #ParameterType : System.UInt32
    #Name : iDevNum
    #DefaultValue :
    #RawDefaultValue :
    #Position : 1
    #Attributes : None
    #Member : Boolean EnumDisplayDevices(System.String, UInt32, My5.DISPLAY_DEVICE ByRef, UInt32)
    #IsIn : False
    #IsOut : False
    #IsLcid : False
    #IsRetval : False
    #IsOptional : False
    #MetadataToken : 134217730

    #ParameterType : My5.DISPLAY_DEVICE&
    #Name : lpDisplayDevice
    #DefaultValue :
    #RawDefaultValue :
    #Position : 2
    #Attributes : None
    #Member : Boolean EnumDisplayDevices(System.String, UInt32, My5.DISPLAY_DEVICE ByRef, UInt32)
    #IsIn : False
    #IsOut : False
    #IsLcid : False
    #IsRetval : False
    #IsOptional : False
    #MetadataToken : 134217731

    #ParameterType : System.UInt32
    #Name : dwFlags
    #DefaultValue :
    #RawDefaultValue :
    #Position : 3
    #Attributes : None
    #Member : Boolean EnumDisplayDevices(System.String, UInt32, My5.DISPLAY_DEVICE ByRef, UInt32)
    #IsIn : False
    #IsOut : False
    #IsLcid : False
    #IsRetval : False
    #IsOptional : False
    #MetadataToken : 134217732

      My System SpecsSystem Spec

  2. #2


    Bob Landau Guest

    RE: Passing ref type to methods using invocation within Powershell

    1) I don't see where you've declared the function. Down where you've used
    reflection on the $obj variable it appears to look correct but you need to
    verify this

    Check out this site

    http://pinvoke.net/default.aspx/user...ayDevices.html

    2) Why are you using 1 for the id. It starts at 0 and will fail if "id" is >
    # of devices

    3) The way the function is defined the first parameter is a string. If you
    need to make certain "null' and not "" is passed change it to an IntPtr

    4) You're to Invoke is not marking $test as a [ref]. I believe this is a
    parameter where you can specify the direction when making this call but all
    of that is a pain.

    try this I'll let you provide the correct PS syntax

    [DllImport("user32.dll")]
    static extern bool EnumDisplayDevices(IntPtr lpDevice, uint iDevNum, ref
    DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);


    [my5.stuff]::EnumDisplayDevices($null,1,[ref]$test,0)
    ^^^^

    I'm assuming that "EnumXXX" is placed in the "Stuff" namespace


    "Whisperer" wrote:

    >
    > In the code below [my5.stuff]::EnumDisplayDevices($null,1,[ref]$test,0)
    > does not work because the $null is cast as ""
    >
    > The following line does return true but $test is not populated with the
    > expected details.
    > Presumably this is because [my5.DISPLAY_DEVICE]$test is not a reference
    > $obj.gettype().getmethod("EnumDisplayDevices").invoke($obj,@($null,[uint32]0,[my5.DISPLAY_DEVICE]$test,[uint32]0))
    >
    > HOW CAN I PASS A REFERENCE TYPE TO THE INVOKED METHOD SO THAT $TEST IS
    > POPULATED WITH THE DETAILS FOR DISPLAY DEVICE 0?
    >
    > I have tried all sorts of different ways can cannot get $test set as
    > needed.
    >
    > (Watch out for line wrapping in the code)
    >
    > Thanks
    >
    > ####Code####
    >
    > $source=@"
    > using System;
    > using System.Runtime.InteropServices;
    > using System.Threading;
    >
    > namespace My5
    > {
    > // Remove the next flags line and the flags will be returned as
    > integers
    > [Flags()]
    > public enum DisplayDeviceStateFlags : int
    > {
    > /// <summary>The device is part of the desktop.</summary>
    > AttachedToDesktop = 0x1,
    > MultiDriver = 0x2,
    > /// <summary>The device is part of the desktop.</summary>
    > PrimaryDevice = 0x4,
    > /// <summary>Represents a pseudo device used to mirror application
    > drawing for remoting or other purposes.</summary>
    > MirroringDriver = 0x8,
    > /// <summary>The device is VGA compatible.</summary>
    > VGACompatible = 0x16,
    > /// <summary>The device is removable; it cannot be the primary
    > display.</summary>
    > Removable = 0x20,
    > /// <summary>The device has more display modes than its output
    > devices support.</summary>
    > ModesPruned = 0x8000000,
    > Remote = 0x4000000,
    > Disconnect = 0x2000000
    > }
    >
    > [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
    > public struct DISPLAY_DEVICE
    > {
    > [MarshalAs(UnmanagedType.U4)]
    > public int cb;
    > [MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
    > public string DeviceName;
    > [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
    > public string DeviceString;
    > [MarshalAs(UnmanagedType.U4)]
    > public DisplayDeviceStateFlags StateFlags;
    > [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
    > public string DeviceID;
    > [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
    > public string DeviceKey;
    > }
    >
    >
    > }
    > "@
    >
    > add-type -typedefinition $source
    >
    > $test=new-object my5.display_device
    > $test.cb=[system.runtime.interopservices.marshal]::sizeof($test)
    >
    > #The following line errors
    > [my5.stuff]::EnumDisplayDevices($null,1,$test,0)
    > #Argument: '3' should be a System.Management.Automation.PSReference. Use
    > [ref].
    >
    > #The following line returns False and $test is not set to anything -
    > this is due to the $null being cast as ""
    > [my5.stuff]::EnumDisplayDevices($null,1,[ref]$test,0)
    >
    > $obj=(new-object -typename "my5.stuff")
    > #The following method was suggested to get round the 'null' issue
    > #but, while it returns True, $test is not set.
    > #Presumably this is because [my5.DISPLAY_DEVICE]$test is not a
    > reference
    > $obj.gettype().getmethod("EnumDisplayDevices").invoke($obj,@($null,[uint32]0,[my5.DISPLAY_DEVICE]$test,[uint32]0))
    >
    >
    > $obj.gettype().getmethod("EnumDisplayDevices").getparameters()
    >
    >
    > #ParameterType : System.String
    > #Name : lpDevice
    > #DefaultValue :
    > #RawDefaultValue :
    > #Position : 0
    > #Attributes : None
    > #Member : Boolean EnumDisplayDevices(System.String, UInt32,
    > My5.DISPLAY_DEVICE ByRef, UInt32)
    > #IsIn : False
    > #IsOut : False
    > #IsLcid : False
    > #IsRetval : False
    > #IsOptional : False
    > #MetadataToken : 134217729
    >
    > #ParameterType : System.UInt32
    > #Name : iDevNum
    > #DefaultValue :
    > #RawDefaultValue :
    > #Position : 1
    > #Attributes : None
    > #Member : Boolean EnumDisplayDevices(System.String, UInt32,
    > My5.DISPLAY_DEVICE ByRef, UInt32)
    > #IsIn : False
    > #IsOut : False
    > #IsLcid : False
    > #IsRetval : False
    > #IsOptional : False
    > #MetadataToken : 134217730
    >
    > #ParameterType : My5.DISPLAY_DEVICE&
    > #Name : lpDisplayDevice
    > #DefaultValue :
    > #RawDefaultValue :
    > #Position : 2
    > #Attributes : None
    > #Member : Boolean EnumDisplayDevices(System.String, UInt32,
    > My5.DISPLAY_DEVICE ByRef, UInt32)
    > #IsIn : False
    > #IsOut : False
    > #IsLcid : False
    > #IsRetval : False
    > #IsOptional : False
    > #MetadataToken : 134217731
    >
    > #ParameterType : System.UInt32
    > #Name : dwFlags
    > #DefaultValue :
    > #RawDefaultValue :
    > #Position : 3
    > #Attributes : None
    > #Member : Boolean EnumDisplayDevices(System.String, UInt32,
    > My5.DISPLAY_DEVICE ByRef, UInt32)
    > #IsIn : False
    > #IsOut : False
    > #IsLcid : False
    > #IsRetval : False
    > #IsOptional : False
    > #MetadataToken : 134217732
    >
    >
    > --
    > Whisperer
    > .
    >

      My System SpecsSystem Spec

Passing ref type to methods using invocation within Powershell problems?

Similar Threads
Thread Thread Starter Forum Replies Last Post
Generic Class: Passing Data Type to Placeholder Etienne-Louis Nicolet .NET General 4 08 Aug 2008
Passing arguments from .BAT to PowerShell script wofat68 PowerShell 8 02 Aug 2008
Passing credential object - what's the type? bobuva PowerShell 2 09 May 2008
shild i use vbscript or powershell in this situation / or other methods ? James PowerShell 1 22 Jul 2007
COM IDispatch and Powershell invocation =?Utf-8?B?S2Jnbw==?= PowerShell 1 12 Sep 2006