매장 안내 화면이나 현장 모니터링 화면처럼 프로그램 하나만 화면 전체에 띄워 두는 용도라면, 아래쪽 작업 표시줄이 보이지 않아야 깔끔합니다. 테두리 없는 최대화 폼을 띄우면서 Windows API로 작업 표시줄 창 자체를 숨기고, 프로그램이 끝날 때 다시 보이게 하는 예제입니다. 테두리를 없앴으니 닫기 버튼은 PictureBox로 직접 만들어 오른쪽 위에 붙였습니다.

작업 표시줄 없이 전체화면으로 실행된 폼과 오른쪽 위 닫기 버튼

광고
Imports System.Runtime.InteropServices

Public Class fMain

    ' 윈도우 API 함수 선언
    <DllImport("user32.dll")>
    Private Shared Function FindWindow(lpClassName As String, lpWindowName As String) As IntPtr
    End Function

    <DllImport("user32.dll", SetLastError:=True)>
    Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As SetWindowPosFlags) As Boolean
    End Function

    ' SetWindowPos 함수의 플래그 열거형
    <Flags>
    Private Enum SetWindowPosFlags As UInteger
        SynchronousWindowPosition = &H4000
        DeferErase = &H2000
        DrawFrame = &H20
        FrameChanged = &H20
        HideWindow = &H80
        DoNotActivate = &H10
        DoNotCopyBits = &H100
        IgnoreMove = &H2
        DoNotChangeOwnerZOrder = &H200
        DoNotRedraw = &H8
        DoNotReposition = &H200
        DoNotSendChangingEvent = &H400
        IgnoreResize = &H1
        IgnoreZOrder = &H4
        ShowWindow = &H40
    End Enum

    ' 사용자 지정 닫기 버튼 PictureBox
    Private cmd_close As PictureBox

    ' 폼이 로드될 때 발생하는 이벤트 처리기
    Private Sub fMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' 사용자 지정 닫기 버튼 생성
        cmd_close = New PictureBox
        cmd_close.Image = My.Resources.ResourceManager.GetObject("close") ' 리소스에서 이미지 가져오기
        cmd_close.Size = New Size(17, 17) ' 크기 설정
        cmd_close.SizeMode = PictureBoxSizeMode.Zoom ' 이미지 크기 조정 방법 설정
        Me.Controls.Add(cmd_close) ' 폼에 PictureBox 추가
        ' 사용자 지정 닫기 버튼 클릭 이벤트 핸들러 추가
        AddHandler cmd_close.Click, Sub(xs As Object, xe As EventArgs)
                                        Application.Exit() ' 애플리케이션 종료
                                    End Sub

        ' 폼 설정
        Me.FormBorderStyle = FormBorderStyle.None ' 테두리 스타일 없음
        Dim window As IntPtr = FindWindow("Shell_traywnd", "") ' 작업 표시줄 찾기
        SetWindowPos(window, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.HideWindow) ' 작업 표시줄 숨기기
        Me.WindowState = FormWindowState.Maximized ' 최대화
        Me.TopMost = True ' 항상 위에 표시
    End Sub

    ' 폼이 Dispose될 때 발생하는 이벤트 처리기
    Private Sub MyBase_Disposed(sender As Object, e As EventArgs) Handles Me.Disposed
        Dim window As IntPtr = FindWindow("Shell_traywnd", "") ' 작업 표시줄 찾기
        SetWindowPos(window, IntPtr.Zero, 0, 0, 0, 0, SetWindowPosFlags.ShowWindow) ' 작업 표시줄 다시 표시
    End Sub

    ' 폼 크기 조정 이벤트 처리기
    Private Sub fMain_Resize(sender As Object, e As EventArgs) Handles Me.Resize
        Dim S As Size = Me.ClientRectangle.Size ' 클라이언트 영역 크기 가져오기
        If cmd_close IsNot Nothing Then cmd_close.Location = New Point(S.Width - cmd_close.Width - 15, 15) ' 사용자 지정 닫기 버튼 위치 설정
    End Sub

End Class

작업 표시줄을 숨기는 원리

Windows 작업 표시줄도 하나의 창이고, 창 클래스 이름이 Shell_TrayWnd 입니다. FindWindow 에 이 클래스 이름을 넘기면 작업 표시줄의 창 핸들이 돌아옵니다(클래스 이름 비교는 대소문자를 가리지 않아서 코드처럼 Shell_traywnd 로 써도 찾습니다). 그 핸들에 SetWindowPos 를 HideWindow(SWP_HIDEWINDOW, &H80) 플래그로 호출하면 작업 표시줄이 사라지고, 폼이 닫힐 때 ShowWindow(&H40)로 다시 부르면 돌아옵니다.

열거형에 같은 값이 두 번 나오는 항목(DrawFrame/FrameChanged 는 &H20, DoNotChangeOwnerZOrder/DoNotReposition 은 &H200)은 오타가 아니라 Win32 헤더에도 같은 값의 별칭으로 정의된 플래그들입니다.

폼 쪽은 FormBorderStyle.None 으로 제목 표시줄과 테두리를 없앤 뒤 최대화하고, TopMost 로 다른 창 위에 고정합니다. 테두리가 없으면 기본 닫기 버튼도 없으니, 리소스의 close 이미지를 넣은 17×17 PictureBox를 만들어 클릭하면 Application.Exit() 하도록 연결했습니다. 버튼 위치는 Resize 이벤트에서 폼 오른쪽 위로부터 15픽셀 안쪽에 맞춥니다.

주의

가장 조심할 부분은 비정상 종료입니다. 작업 표시줄을 되살리는 코드가 폼의 Disposed 이벤트에 있어서, 예외로 프로그램이 죽거나 작업 관리자에서 강제 종료하면 작업 표시줄이 숨겨진 채로 남습니다. 이럴 때는 프로그램을 다시 실행했다가 정상 종료하거나, 작업 관리자에서 Windows 탐색기를 다시 시작하면 돌아옵니다. 실제 배포용이라면 Application.ThreadException, AppDomain.CurrentDomain.UnhandledException 처리기에서도 작업 표시줄을 다시 보이게 해 두는 게 안전합니다.

SetWindowPos 를 위치·크기 0으로 부르면서 IgnoreMove, IgnoreResize 플래그를 함께 주지 않았기 때문에, 환경에 따라 작업 표시줄 위치나 크기에 영향을 줄 여지가 있습니다. 숨기기·보이기만 하려는 목적이라면 HideWindow Or IgnoreMove Or IgnoreResize Or IgnoreZOrder 처럼 플래그를 묶어서 넘기는 편이 의도에 맞습니다.

모니터를 여러 대 쓰면 보조 모니터의 작업 표시줄은 클래스 이름이 달라(Shell_SecondaryTrayWnd) 이 코드로는 숨겨지지 않습니다. 또 Windows 키를 누르면 시작 메뉴와 함께 작업 표시줄이 다시 나타날 수 있으니, 완전한 키오스크가 필요하다면 Windows의 키오스크(할당된 액세스) 기능을 쓰는 쪽도 검토해 볼 만합니다.