
Imports System.Runtime.InteropServices.Marshal
Imports System.Diagnostics

Public Class Form1

#Region "ClassEnumerations"

    Private Enum localMSOTriState
        msoTrue = -1
        msoFalse = 0
    End Enum

    Private Enum localPpAlertLevel
        ppAlertsNone = 1
        ppAlertsAll = 2
    End Enum

    Private Enum localPpSlideShowAdvanceMode
        ppSlideShowManualAdvance = 1
        ppSlideShowUseSlideTimings = 2
        ppSlideShowRehearseNewTimings = 3
    End Enum

#End Region

    Private Const _dynamicPictureBoxNamePrefix As String = "SlidePictureBox"
    Private Const _dodgyHardcodedPPTFileName As String = "C:\SamplePowerPointFile.ppt"
    Private Const _dodgyHardcodedSlideImageSaveName As String = "C:\_ExportedPPTSlideImage"

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        OutputPowerPointFileSlides(Me, _DodgyHardcodedPPTFileName)
    End Sub

    ' Executed when one of the dynamically created pictureboxes are clicked.
    Private Sub DynamicPictureBox_OnClick(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim slideIndexNumber As Integer = CType(CType(sender, PictureBox).Name.Replace(_dynamicPictureBoxNamePrefix, String.Empty), Integer)
        MessageBox.Show(String.Concat("Picture box number ", slideIndexNumber.ToString, _
                                      " was clicked!", Environment.NewLine, Environment.NewLine, _
                                      "(Remember this is a zero-based sheet ID, PowerPoint recognises 1-based)"))
    End Sub

    ' Gathers screenshots of slides in a given PowerPoint file and outputs these via a series of 
    ' dynamically created picturebox controls at runtime, placed on the specified form. 
    Private Sub OutputPowerPointFileSlides(ByVal formName As Form, ByVal PowerPointFileName As String)
        Dim newPowerPointInstance As Object
        Try
            ' Instanciate PowerPoint. I've included a reference from beneath the Project>Add Reference
            ' menu to Powerpoint from beneath the COM tab. You might want to convert this to late binding 
            ' later on - I'm jsut doing you a quick sample here. Note there's no file validation check
            ' or error handling yet - I'll leave that to you! ;c) First, Open the given PowerPoint file.
            newPowerPointInstance = CreateObject("PowerPoint.Application")
            With newPowerPointInstance
                .ShowStartupDialog = localMSOTriState.msoFalse
                .DisplayAlerts = localPpAlertLevel.ppAlertsNone
                .Visible = localMSOTriState.msoTrue
                .Presentations.Open(PowerPointFileName)
            End With

            ' Set the animations off - we're only wanting a static screenshot. Also turn off 
            ' Powerpoints automatic "show next slide after a set interval" option. Follow
            ' this by running the slideshow - equal to pressing F5 in PowerPoint.
            With newPowerPointInstance.Presentations(1).SlideShowSettings
                .AdvanceMode = localPpSlideShowAdvanceMode.ppSlideShowManualAdvance
                .ShowWithAnimation = localMSOTriState.msoFalse
                .Run()
            End With

            ' We want to start by viewing the 1st slide...
            newPowerPointInstance.Presentations(1).SlideShowWindow.View.First()

            Dim newPictureBoxInstance As New List(Of PictureBox)
            Dim pictureBoxTopPos As Integer = 10

            ' Then performing a loop to iterate through each of the other slides of the given PowerPoint file.
            ' Notice there's no need for sizing or sleeping in this code.
            For slideShowSlideIndex As Integer = 0 To newPowerPointInstance.Presentations(1).Slides.Count - 1
                ' With each slide and therefore loop iteration encountered, create a new picturebox 
                ' control. These controls are created at runtime and are known as dynamic controls.
                newPictureBoxInstance.Add(New PictureBox)
                With newPictureBoxInstance(slideShowSlideIndex)
                    .Left = 5
                    .Height = 150
                    .Width = 150
                    .Top = CType((slideShowSlideIndex * newPictureBoxInstance(slideShowSlideIndex).Height) + 10, Integer)

                    ' It's important to set the right size mode for the screenshot to take up the picturebox height and 
                    ' width correctly. I also name each picturebox with an ending (zero-based) slide index number.
                    .SizeMode = PictureBoxSizeMode.Zoom
                    .Name = _dynamicPictureBoxNamePrefix & slideShowSlideIndex.ToString

                    ' Add an onclick event handler - this says to call the above 
                    ' DynamicPictureBox_OnClick method when the picturebox is clicked onto.
                    AddHandler newPictureBoxInstance(slideShowSlideIndex).Click, AddressOf DynamicPictureBox_OnClick

                    ' Call the below method to put a screenshot of the currently viewed slide into the current picturebox.
                    ' Follow this by adding the picturebox to the given form's controls collection.
                    OutputScreenCaptureToPictureBox(newPictureBoxInstance(slideShowSlideIndex), slideShowSlideIndex)
                    Panel1.Controls.Add(newPictureBoxInstance(slideShowSlideIndex))
                End With

                ' If there is one, move PowerPoint to look at the next file.
                If Not (slideShowSlideIndex = (newPowerPointInstance.Presentations(1).Slides.Count - 1)) Then
                    newPowerPointInstance.Presentations(1).SlideShowWindow.View.Next()
                End If
            Next slideShowSlideIndex

        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        Finally
            ' Clean up code. Dispose of PowerPoint as it's no longer needed.
            If Not (newPowerPointInstance Is Nothing) Then
                If (newPowerPointInstance.Presentations.Count > 0) Then
                    newPowerPointInstance.Presentations(1).close()
                End If
                newPowerPointInstance.DisplayAlerts = localPpAlertLevel.ppAlertsAll
                newPowerPointInstance.Quit()
                ReleaseComObject(newPowerPointInstance)
                newPowerPointInstance = Nothing

                For Each PowerPointProcess As Process In Process.GetProcessesByName("POWERPNT")
                    PowerPointProcess.Kill()
                Next
            End If
        End Try
    End Sub

    ' Captures a screen shot and assigns this to a given picturebox control.
    Private Sub OutputScreenCaptureToPictureBox(ByVal pictureBoxControl As PictureBox, ByVal indexNumber As Integer)
        Dim screenCaptureBitmap As Bitmap
        Dim newGraphicsObject As Graphics

        Try
            ' Create a new bitmap image object with the dimentions of the screen.
            screenCaptureBitmap = New Bitmap(My.Computer.Screen.Bounds.Width, My.Computer.Screen.Bounds.Height)

            ' Create a new graphics object, and capture a screenshot of the current screen, 
            ' using and passing in the dimentions of the screen as defined in the bitmap object.
            newGraphicsObject = Graphics.FromImage(screenCaptureBitmap)
            newGraphicsObject.CopyFromScreen(0, 0, 0, 0, screenCaptureBitmap.Size)
            screenCaptureBitmap.Save(_dodgyHardcodedSlideImageSaveName & indexNumber.ToString & ".jpg", Imaging.ImageFormat.Jpeg)
            pictureBoxControl.Image = screenCaptureBitmap

        Catch ex As Exception
            MessageBox.Show(ex.ToString)
        Finally
            ' These can't be called yet as they are in use by the picturebox controls. Seems we 
            ' have no option but to let the framework dispose of these itself.
            'if not (screenCaptureBitmap is nothing) then
            '    'screenCaptureBitmap.Dispose
            'End If
            'if not (newGraphicsObject is nothing) then
            '    'newGraphicsObject.Dispose
            'End If
        End Try
    End Sub

End Class