-4

While translating the code below to VB.NET, I stumbled into a roadblock.

My problem is: in C# my delegates are called without arguments as an argument itself. How does one do that in VB.NET? All the online and offline translator can't translate all of the code as is. See below where i'm at:

The part where the translation fails is at the most important things...

Here:

EnumThreadWindows(t.Id, MyEnumThreadWindowsProc, IntPtr.Zero);

(Not sufficient arguments to call "MyEnumThreadWindowsProc" function)

And here:

startWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, (IntPtr)0xC017, "Start");

(The pointer)


For reference, the full source is

/*
 *  Copyright (c) 2008..11 by Simon Baer
 * 
 *  You may use this code for whatever you want.
 */

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace TaskbarHide
{
    /// <summary>
    /// Helper class for hiding/showing the taskbar and startmenu on
    /// Windows XP and Vista.
    /// </summary>
    public static class Taskbar
    {
        [DllImport("user32.dll")]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count); 
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool EnumThreadWindows(int threadId, EnumThreadProc pfnEnum, IntPtr lParam);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern System.IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className,  string windowTitle);
        [DllImport("user32.dll")]
        private static extern IntPtr FindWindowEx(IntPtr parentHwnd, IntPtr childAfterHwnd, IntPtr className, string windowText);
        [DllImport("user32.dll")]
        private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hwnd, out int lpdwProcessId);

        private const int SW_HIDE = 0;
        private const int SW_SHOW = 5;

        private const string VistaStartMenuCaption = "Start";
        private static IntPtr vistaStartMenuWnd = IntPtr.Zero;
        private delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam);

        /// <summary>
        /// Show the taskbar.
        /// </summary>
        public static void Show()
        {
            SetVisibility(true);
        }

        /// <summary>
        /// Hide the taskbar.
        /// </summary>
        public static void Hide()
        {
            SetVisibility(false);
        }

        /// <summary>
        /// Sets the visibility of the taskbar.
        /// </summary>
        public static bool Visible
        {
            set { SetVisibility(value); }
        }

        /// <summary>
        /// Hide or show the Windows taskbar and startmenu.
        /// </summary>
        /// <param name="show">true to show, false to hide</param>
        private static void SetVisibility(bool show)
        {
            // get taskbar window
            IntPtr taskBarWnd = FindWindow("Shell_TrayWnd", null);

            // try it the WinXP way first...
            IntPtr startWnd = FindWindowEx(taskBarWnd, IntPtr.Zero, "Button", "Start");

            if (startWnd == IntPtr.Zero)
            {
                // try an alternate way, as mentioned on CodeProject by Earl Waylon Flinn
                startWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, (IntPtr)0xC017, "Start");
            }

            if (startWnd == IntPtr.Zero)
            {
                // ok, let's try the Vista easy way...
                startWnd = FindWindow("Button", null);

                if (startWnd == IntPtr.Zero)
                {
                    // no chance, we need to to it the hard way...
                    startWnd = GetVistaStartMenuWnd(taskBarWnd);
                }
            }

            ShowWindow(taskBarWnd, show ? SW_SHOW : SW_HIDE);
            ShowWindow(startWnd, show ? SW_SHOW : SW_HIDE);
        }

        /// <summary>
        /// Returns the window handle of the Vista start menu orb.
        /// </summary>
        /// <param name="taskBarWnd">windo handle of taskbar</param>
        /// <returns>window handle of start menu</returns>
        private static IntPtr GetVistaStartMenuWnd(IntPtr taskBarWnd)
        {
            // get process that owns the taskbar window
            int procId;
            GetWindowThreadProcessId(taskBarWnd, out procId);

            Process p = Process.GetProcessById(procId);
            if (p != null)
            {
                // enumerate all threads of that process...
                foreach (ProcessThread t in p.Threads)
                {
                    EnumThreadWindows(t.Id, MyEnumThreadWindowsProc, IntPtr.Zero);
                }
            }
            return vistaStartMenuWnd;
        }

        /// <summary>
        /// Callback method that is called from 'EnumThreadWindows' in 'GetVistaStartMenuWnd'.
        /// </summary>
        /// <param name="hWnd">window handle</param>
        /// <param name="lParam">parameter</param>
        /// <returns>true to continue enumeration, false to stop it</returns>
        private static bool MyEnumThreadWindowsProc(IntPtr hWnd, IntPtr lParam)
        {
            StringBuilder buffer = new StringBuilder(256);
            if (GetWindowText(hWnd, buffer, buffer.Capacity) > 0)
            {
                Console.WriteLine(buffer);
                if (buffer.ToString() == VistaStartMenuCaption)
                {
                    vistaStartMenuWnd = hWnd;
                    return false;
                }
            }
            return true;
        }
    }
}

This is the code translated by Telerik online service:

'
' * Copyright (c) 2008..11 by Simon Baer
' * 
' *  You may use this code for whatever you want.
' 


Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Diagnostics

Namespace TaskbarHide
    ''' <summary>
    ''' Helper class for hiding/showing the taskbar and startmenu on
    ''' Windows XP and Vista.
    ''' </summary>
    Public NotInheritable Class Taskbar
        Private Sub New()
        End Sub
        <DllImport("user32.dll")> _
        Private Shared Function GetWindowText(hWnd As IntPtr, text As StringBuilder, count As Integer) As Integer
        End Function
        <DllImport("user32.dll", CharSet := CharSet.Auto)> _
        Private Shared Function EnumThreadWindows(threadId As Integer, pfnEnum As EnumThreadProc, lParam As IntPtr) As Boolean
        End Function
        <DllImport("user32.dll", SetLastError := True)> _
        Private Shared Function FindWindow(lpClassName As String, lpWindowName As String) As System.IntPtr
        End Function
        <DllImport("user32.dll", SetLastError := True)> _
        Private Shared Function FindWindowEx(parentHandle As IntPtr, childAfter As IntPtr, className As String, windowTitle As String) As IntPtr
        End Function
        <DllImport("user32.dll")> _
        Private Shared Function FindWindowEx(parentHwnd As IntPtr, childAfterHwnd As IntPtr, className As IntPtr, windowText As String) As IntPtr
        End Function
        <DllImport("user32.dll")> _
        Private Shared Function ShowWindow(hwnd As IntPtr, nCmdShow As Integer) As Integer
        End Function
        <DllImport("user32.dll")> _
        Private Shared Function GetWindowThreadProcessId(hwnd As IntPtr, lpdwProcessId As Integer) As UInteger
        End Function

        Private Const SW_HIDE As Integer = 0
        Private Const SW_SHOW As Integer = 5

        Private Const VistaStartMenuCaption As String = "Start"
        Private Shared vistaStartMenuWnd As IntPtr = IntPtr.Zero
        Private Delegate Function EnumThreadProc(hwnd As IntPtr, lParam As IntPtr) As Boolean

        ''' <summary>
        ''' Show the taskbar.
        ''' </summary>
        Public Shared Sub Show()
            SetVisibility(True)
        End Sub

        ''' <summary>
        ''' Hide the taskbar.
        ''' </summary>
        Public Shared Sub Hide()
            SetVisibility(False)
        End Sub

        ''' <summary>
        ''' Sets the visibility of the taskbar.
        ''' </summary>
        Public Shared WriteOnly Property Visible() As Boolean
            Set
                SetVisibility(value)
            End Set
        End Property

        ''' <summary>
        ''' Hide or show the Windows taskbar and startmenu.
        ''' </summary>
        ''' <param name="show">true to show, false to hide</param>
        Private Shared Sub SetVisibility(show As Boolean)
            ' get taskbar window
            Dim taskBarWnd As IntPtr = FindWindow("Shell_TrayWnd", Nothing)

            ' try it the WinXP way first...
            Dim startWnd As IntPtr = FindWindowEx(taskBarWnd, IntPtr.Zero, "Button", "Start")

            If startWnd = IntPtr.Zero Then
                ' try an alternate way, as mentioned on CodeProject by Earl Waylon Flinn
                startWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, DirectCast(&Hc017, IntPtr), "Start")
            End If

            If startWnd = IntPtr.Zero Then
                ' ok, let's try the Vista easy way...
                startWnd = FindWindow("Button", Nothing)

                If startWnd = IntPtr.Zero Then
                    ' no chance, we need to to it the hard way...
                    startWnd = GetVistaStartMenuWnd(taskBarWnd)
                End If
            End If

            ShowWindow(taskBarWnd, If(show, SW_SHOW, SW_HIDE))
            ShowWindow(startWnd, If(show, SW_SHOW, SW_HIDE))
        End Sub

        ''' <summary>
        ''' Returns the window handle of the Vista start menu orb.
        ''' </summary>
        ''' <param name="taskBarWnd">windo handle of taskbar</param>
        ''' <returns>window handle of start menu</returns>
        Private Shared Function GetVistaStartMenuWnd(taskBarWnd As IntPtr) As IntPtr
            ' get process that owns the taskbar window
            Dim procId As Integer
            GetWindowThreadProcessId(taskBarWnd, procId)

            Dim p As Process = Process.GetProcessById(procId)
            If p IsNot Nothing Then
                ' enumerate all threads of that process...
                For Each t As ProcessThread In p.Threads
                    EnumThreadWindows(t.Id, MyEnumThreadWindowsProc, IntPtr.Zero)
                Next
            End If
            Return vistaStartMenuWnd
        End Function

        ''' <summary>
        ''' Callback method that is called from 'EnumThreadWindows' in 'GetVistaStartMenuWnd'.
        ''' </summary>
        ''' <param name="hWnd">window handle</param>
        ''' <param name="lParam">parameter</param>
        ''' <returns>true to continue enumeration, false to stop it</returns>
        Private Shared Function MyEnumThreadWindowsProc(hWnd As IntPtr, lParam As IntPtr) As Boolean
            Dim buffer As New StringBuilder(256)
            If GetWindowText(hWnd, buffer, buffer.Capacity) > 0 Then
                Console.WriteLine(buffer)
                If buffer.ToString() = VistaStartMenuCaption Then
                    vistaStartMenuWnd = hWnd
                    Return False
                End If
            End If
            Return True
        End Function
    End Class
End Namespace

'=======================================================
'Service provided by Telerik (www.telerik.com)
'Conversion powered by NRefactory.
'Twitter: @telerik, @toddanglin
'Facebook: facebook.com/telerik
'=======================================================
Adrian Panasiuk
  • 7,249
  • 5
  • 33
  • 54
ElektroStudios
  • 19,105
  • 33
  • 200
  • 417
  • rather compile it as a dll and write a pretty interface of your own to make api type calls – ericosg Jun 04 '13 at 16:33
  • 3
    Stackoverflow.com is not a code translator, y'know... – Federico Berasategui Jun 04 '13 at 16:33
  • Agreed...this is not a question, it's shopping for services. – DonBoitnott Jun 04 '13 at 16:34
  • @Highcore @ DonBoitnott huh? I've asked to help to translate only **TWO LINES OF CODE**, that's too much for you all? I want too much? really? I need to pay for this little help?, well at least some people want to help other people instead of comment things like that. – ElektroStudios Jun 04 '13 at 16:37
  • @ericosg Thankyou for your suggestion but if I make a C# dll I don't learn anything, also I want to have re-usable VB code, I hope you can understand me, thanks again. – ElektroStudios Jun 04 '13 at 16:38
  • @Elektrohacker if you only need 2 lines of code, then why do you post a whole bunch of other code no one cares about? – Federico Berasategui Jun 04 '13 at 16:40
  • @HighCore I gived all the needed information to write a good question, that's all. – ElektroStudios Jun 04 '13 at 16:40
  • @elektrohacker not really. If that was true you would not have got 10 downvotes. – Federico Berasategui Jun 04 '13 at 16:41
  • @HighCore then maybe now all are wizards and If I only post the two lines of code all can know what are those variables objects without the rest of the code and what would be MyEnumThreadWindowsProc without the code?. – ElektroStudios Jun 04 '13 at 16:43
  • The tag "c#-to-vb.net" I thing exist for some reason, but if moderators think in StackOverFlow a guy can't make a question to help people who need to translate code then maybe moderators will reconsider the existence of that tag. sorry 'cause my english. – ElektroStudios Jun 04 '13 at 16:47
  • 3
    at a better look, this question is *not* shopping for services, but rather (needs rephrasing) is really asking: "In C# my delegates are called without arguments as an argument itself. How does one do that in VB.NET? Code translators are failing to do the same. See below where i'm at. TIA" – ericosg Jun 04 '13 at 16:49
  • @ericosg thanks for the suggestion again, I need to translate C# code but also maybe I need someone to translate my words so good as you did xD, updated the answer . – ElektroStudios Jun 04 '13 at 16:55
  • @ericosg I agree - the title is the only misleading part of this question. It is actually two very specific and focused questions. Voting to re-open. – J... Jun 04 '13 at 21:56

2 Answers2

3

I think it is as simple as :

For Each t As ProcessThread In p.Threads
     EnumThreadWindows(t.Id, AddressOf MyEnumThreadWindowsProc, IntPtr.Zero)
Next

VB.NET uses the AddressOf keyword to indicate method pointers for delegates, etc.

For the IntPtr conversion, perhaps use CType instead of DirectCast :

startWnd = FindWindowEx(IntPtr.Zero, IntPtr.Zero, CType(&HC017, IntPtr), "Start")
J...
  • 30,968
  • 6
  • 66
  • 143
1

I'm guessing here, so please give it a try:

Instead of:

            For Each t As ProcessThread In p.Threads
                EnumThreadWindows(t.Id, MyEnumThreadWindowsProc, IntPtr.Zero)
            Next

Try:

            For Each t As ProcessThread In p.Threads
                Dim returnMyEnumThreadWindowsProc As Object
                returnMyEnumThreadWindowsProc = MyEnumThreadWindowsProc ( ... )
                EnumThreadWindows(t.Id, returnMyEnumThreadWindowsProc , IntPtr.Zero)
            Next

I know that VB.NET doesn't do anonymous functions like C# does, but I am not sure how the alternative works.

ericosg
  • 4,926
  • 4
  • 37
  • 59
  • seems to be usefull, thanks, but then I still can't know wich arguments need to be passed to the function, I can't notice in the C# code if is passing the hwnd of the current application, or the hwnd of the Windows TaskBar, also don't know which mean the second argument, the "lparam". – ElektroStudios Jun 04 '13 at 17:15