diff --git a/openlp/plugins/presentations/lib/impresscom.py b/openlp/plugins/presentations/lib/impresscom.py
new file mode 100644
index 000000000..beeba6e7c
--- /dev/null
+++ b/openlp/plugins/presentations/lib/impresscom.py
@@ -0,0 +1,118 @@
+from win32com.client import Dispatch
+
+# OOo API documentation:
+# http://api.openoffice.org/docs/common/ref/com/sun/star/presentation/XSlideShowController.html
+# http://docs.go-oo.org/sd/html/classsd_1_1SlideShow.html
+# http://www.oooforum.org/forum/viewtopic.phtml?t=5252
+# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Working_with_Presentations
+# http://mail.python.org/pipermail/python-win32/2008-January/006676.html
+
+class ImpressCOMApp(object):
+ def __init__(self):
+ self.createApp()
+
+ def createApp(self):
+ try:
+ self._sm = Dispatch("com.sun.star.ServiceManager")
+ self._app = self._sm.createInstance( "com.sun.star.frame.Desktop" )
+ except:
+ self._sm = None
+ self._app = None
+ return
+
+ def getApp(self):
+ if self._app == None:
+ self.createApp()
+ if self._app == None:
+ return None
+ return self._app
+
+ app = property(getApp)
+
+ def quit(self):
+ self._app.Terminate()
+ self._app = None
+ self._sm = None
+
+class ImpressCOMPres(object):
+ def __init__(self, oooApp, filename):
+ self.oooApp = oooApp
+ self.filename = filename
+ self.open()
+
+ def getPres(self):
+ if self._pres == None:
+ self.open()
+ return self._pres
+
+ pres = property(getPres)
+
+ def open(self):
+ self.comp = self.oooApp.app.loadComponentFromURL("file:///" + self.filename, "_blank", 0, [])
+ self.presdoc = self.comp.getPresentation()
+ self.presdoc.start()
+ self._pres = self.presdoc.getController()
+
+ def close(self):
+ self.pres.deactivate()
+ self.presdoc.end()
+ self.comp.dispose()
+ self._pres = None
+ self.presdoc = None
+ self.comp = None
+
+ def isActive(self):
+ return self.pres.isRunning() and self.pres.isActive()
+
+ def resume(self):
+ return self.pres.resume()
+
+ def pause(self):
+ return self.pres.pause()
+
+ def blankScreen(self):
+ self.pres.blankScreen(0)
+
+ def stop(self):
+ self.pres.deactivate()
+ # self.presdoc.end()
+
+ def go(self):
+ self.pres.activate()
+ # self.presdoc.start()
+
+ def getSlideNumber(self):
+ return self.pres.getCurrentSlideIndex
+
+ def setSlideNumber(self, slideno):
+ self.pres.gotoSlideIndex(slideno)
+
+ slideNumber = property(getSlideNumber, setSlideNumber)
+
+ def nextStep(self):
+ self.pres.gotoNextEffect()
+
+ def prevStep(self):
+ self.pres.gotoPreviousSlide()
+
+ def moveWindow(self, top, height, left, width):
+ # position the window somehow
+ pass
+
+class ImpressCOMSlide(object):
+ def __init__(self, pres, index):
+ self.pres = pres
+ self.slide = pres.getSlideByIndex(index)
+
+ def preview(self):
+ if self.preview == None:
+ # get a slide somehow
+ pass
+ return self.preview
+
+if __name__ == '__main__':
+ ooo = ImpressCOMApp()
+ show = ImpressCOMPres(ooo, "c:/test1.ppt")
+ show.go()
+ show.resume()
+ show.nextStep()
diff --git a/openlp/plugins/presentations/lib/powerpoint.py b/openlp/plugins/presentations/lib/powerpoint.py
new file mode 100644
index 000000000..5d3c5989c
--- /dev/null
+++ b/openlp/plugins/presentations/lib/powerpoint.py
@@ -0,0 +1,139 @@
+from win32com.client import Dispatch
+
+# PPT API documentation:
+# http://msdn.microsoft.com/en-us/library/aa269321(office.10).aspx
+
+
+class PowerPointApp(object):
+ def __init__(self):
+ self.createApp()
+
+ def createApp(self):
+ try:
+ self._app = Dispatch("PowerPoint.Application")
+ except:
+ self._app = None
+ return
+ self._app.Visible = True
+ self._app.WindowState = 2
+
+ def getApp(self):
+ if self._app == None:
+ self.createApp()
+ if self._app == None:
+ return None
+ if self._app.Windows.Count == 0:
+ self.createApp()
+ return self._app
+
+ app = property(getApp)
+
+ def quit(self):
+ self._app.Quit()
+ self._app = None
+
+class PowerPointPres(object):
+ def __init__(self, pptApp, filename):
+ self.pptApp = pptApp
+ self.filename = filename
+ self.open()
+
+ def getPres(self):
+ if self._pres == None:
+ for p in self.pptApp.app.Presentations:
+ if p.FullName == self.filename:
+ self._pres = p
+ break
+ if self._pres != None:
+ try:
+ x = self._pres.Name
+ except:
+ self._pres = None
+ if self._pres == None:
+ self.openPres()
+ return self._pres
+
+ pres = property(getPres)
+
+ def open(self):
+ self.pptApp.app.Presentations.Open(self.filename, False, False, True)
+ self._pres = self.pptApp.app.Presentations(ppt.app.Presentations.Count)
+
+ def close(self):
+ self.pres.Close()
+ self._pres = None
+
+ def isActive(self):
+ if self.pres.SlideShowWindow == None:
+ return False
+ if self.pres.SlideShowWindow.View == None:
+ return False
+ return True
+
+ def resume(self):
+ self.pres.SlideShowSettings.Run()
+ self.pres.SlideShowWindow.View.State = 1
+ self.pres.SlideShowWindow.Activate()
+
+ def pause(self):
+ if self.isActive():
+ self.pres.SlideShowWindow.View.State = 2
+
+ def blankScreen(self):
+ if self.isActive():
+ self.pres.SlideShowWindow.View.State = 3
+
+ def stop(self):
+ if self.isActive():
+ self.pres.SlideShowWindow.View.Exit()
+
+ def go(self):
+ self.pres.SlideShowSettings.Run()
+
+ def getCurrentSlideIndex(self):
+ if self.isActive():
+ return self.pres.SlideShowWindow.View.CurrentShowPosition
+ else:
+ return -1
+
+ def setCurrentSlideIndex(self, slideno):
+ if not self.isActive():
+ self.resume()
+ self.pres.SlideShowWindow.View.GotoSlide(slideno)
+
+ currentSlideIndex = property(getSlideNumber, setSlideNumber)
+
+ def nextStep(self):
+ if not self.isActive():
+ self.resume()
+ self.pres.SlideShowWindow.View.Next()
+
+ def prevStep(self):
+ if not self.isActive():
+ self.resume()
+ self.pres.SlideShowWindow.View.Previous()
+
+ def moveWindow(self, top, height, left, width):
+ if not self.isActive():
+ self.resume()
+ self.pres.SlideShowWindow.Top = top / 20
+ self.pres.SlideShowWindow.Height = height / 20
+ self.pres.SlideShowWindow.Left = left / 20
+ self.pres.SlideShowWindow.Width = width / 20
+
+class PowerPointSlide(object):
+ def __init__(self, pres, index):
+ self.pres = pres
+ self.slide = pres.Slides[index]
+
+ def preview(self):
+ if self.preview == None:
+ self.slide.Copy
+ # import win32clipboard as w
+ # import win32con
+ # w.OpenClipboard()
+ # self.preview = w.GetClipboardData.GetData(win32con.CF_BITMAP)
+ # w.CloseClipboard()
+ return self.preview
+
+
diff --git a/openlp/plugins/presentations/lib/pptview.py b/openlp/plugins/presentations/lib/pptview.py
new file mode 100644
index 000000000..941223cc2
--- /dev/null
+++ b/openlp/plugins/presentations/lib/pptview.py
@@ -0,0 +1,126 @@
+import sys
+import win32api
+from PyQt4 import QtGui, QtCore
+from ctypes import *
+from ctypes.wintypes import RECT
+
+pptdll = cdll.LoadLibrary(r"C:\Documents and Settings\jonathan\My Documents\Personal\openlp\openlp-2\trunk\openlp\libraries\pptviewlib\pptviewlib.dll")
+
+class BoxLayout(QtGui.QWidget):
+ def __init__(self, parent=None):
+ QtGui.QWidget.__init__(self, parent)
+ self.pptid = -1
+ self.setWindowTitle('box layout')
+
+ PPTLabel = QtGui.QLabel('Open PowerPoint file')
+ slideLabel = QtGui.QLabel('Go to slide #')
+ self.PPTEdit = QtGui.QLineEdit()
+ self.slideEdit = QtGui.QLineEdit()
+ self.total = QtGui.QLabel()
+ PPTBtn = QtGui.QPushButton("Open")
+ PPTDlgBtn = QtGui.QPushButton("...")
+ slideBtn = QtGui.QPushButton("Go")
+ prev = QtGui.QPushButton("Prev")
+ next = QtGui.QPushButton("Next")
+ blank = QtGui.QPushButton("Blank")
+ unblank = QtGui.QPushButton("Unblank")
+ restart = QtGui.QPushButton("Restart")
+ close = QtGui.QPushButton("Close")
+ resume = QtGui.QPushButton("Resume")
+ stop = QtGui.QPushButton("Stop")
+ pptwindow = QtGui.QWidget()
+
+ grid = QtGui.QGridLayout()
+ grid.addWidget(PPTLabel, 0, 0)
+ grid.addWidget(self.PPTEdit, 0, 1)
+ grid.addWidget(PPTDlgBtn, 0, 2)
+ grid.addWidget(PPTBtn, 0, 3)
+ grid.addWidget(slideLabel, 1, 0)
+ grid.addWidget(self.slideEdit, 1, 1)
+ grid.addWidget(slideBtn, 1, 3)
+ grid.addWidget(prev, 2, 0)
+ grid.addWidget(next, 2, 1)
+ grid.addWidget(blank, 3, 0)
+ grid.addWidget(unblank, 3, 1)
+ grid.addWidget(restart, 4, 0)
+ grid.addWidget(stop, 4, 1)
+ grid.addWidget(resume, 4, 2)
+ grid.addWidget(pptwindow, 5, 0, 10, 3)
+ self.connect(PPTBtn, QtCore.SIGNAL('clicked()'), self.OpenClick)
+ self.connect(PPTDlgBtn, QtCore.SIGNAL('clicked()'), self.OpenDialog)
+ self.connect(slideBtn, QtCore.SIGNAL('clicked()'), self.GotoClick)
+ self.connect(prev, QtCore.SIGNAL('clicked()'), self.PrevClick)
+ self.connect(next, QtCore.SIGNAL('clicked()'), self.NextClick)
+ self.connect(blank, QtCore.SIGNAL('clicked()'), self.BlankClick)
+ self.connect(unblank, QtCore.SIGNAL('clicked()'), self.UnblankClick)
+ self.connect(restart, QtCore.SIGNAL('clicked()'), self.RestartClick)
+ self.connect(close, QtCore.SIGNAL('clicked()'), self.CloseClick)
+ self.connect(stop, QtCore.SIGNAL('clicked()'), self.StopClick)
+ self.connect(resume, QtCore.SIGNAL('clicked()'), self.ResumeClick)
+
+ self.setLayout(grid)
+
+ self.resize(300, 150)
+
+ def PrevClick(self):
+ if self.pptid<0: return
+ pptdll.PrevStep(self.pptid)
+ self.slideEdit.setText(pptdll.GetCurrentSlide(self.pptid))
+
+ def NextClick(self):
+ if(self.pptid<0): return
+ pptdll.NextStep(self.pptid)
+ self.slideEdit.setText(pptdll.GetCurrentSlide(self.pptid))
+
+ def BlankClick(self):
+ if(self.pptid<0): return
+ pptdll.Blank(self.pptid)
+
+ def UnblankClick(self):
+ if(self.pptid<0): return
+ pptdll.Unblank(self.pptid)
+
+ def RestartClick(self):
+ if(self.pptid<0): return
+ pptdll.RestartShow(self.pptid)
+ self.slideEdit.setText(pptdll.GetCurrentSlide(self.pptid))
+
+ def StopClick(self):
+ if(self.pptid<0): return
+ pptdll.Stop(self.pptid)
+
+ def ResumeClick(self):
+ if(self.pptid<0): return
+ pptdll.Resume(self.pptid)
+
+ def CloseClick(self):
+ if(self.pptid<0): return
+ pptdll.Close(self.pptid)
+ self.pptid = -1
+
+ def OpenClick(self):
+ if(self.pptid>=0):
+ self.CloseClick()
+ rect = RECT()
+ rect.left = 100
+ rect.top = 100
+ rect.width = 900
+ rect.hight = 700
+ #self.pptid = pptdll.OpenPPT(self.PPTEdit.text, None, rect, "c:\temp\slide")
+ self.pptid = pptdll.OpenPPT("C:\\test 1.ppt", None, rect, "c:\temp\slide")
+ self.total.setText(pptdll.GetSlideCount(self.pptid))
+ self.slideEdit.setText(str(pptdll.GetCurrentSlide(self.pptid)))
+
+ def GotoClick(self):
+ if(self.pptid<0): return
+ pptdll.GotoSlide(self.pptid, self.slideEdit.text)
+ self.slideEdit.setText(pptdll.GetCurrentSlide(self.pptid))
+
+ def OpenDialog(self):
+ self.PPTEdit.setText(QtGui.QFileDialog.getOpenFileName(self, 'Open file'))
+
+app = QtGui.QApplication(sys.argv)
+qb = BoxLayout()
+qb.show()
+sys.exit(app.exec_())
+
diff --git a/openlp/plugins/presentations/lib/pptviewlib/README.TXT b/openlp/plugins/presentations/lib/pptviewlib/README.TXT
new file mode 100644
index 000000000..43954d150
--- /dev/null
+++ b/openlp/plugins/presentations/lib/pptviewlib/README.TXT
@@ -0,0 +1,116 @@
+
+PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
+Copyright (C) 2008 Jonathan Corwin (j@corwin.co.uk)
+
+This library wrappers the free Microsoft PowerPoint Viewer (2003/2007) program,
+allowing it to be more easily controlled from another program.
+
+The PowerPoint Viewer must already be installed on the destination machine, and is
+freely available at microsoft.com.
+
+The full Microsoft Office PowerPoint and PowerPoint Viewer 97 have a COM interface allowing
+automation. This ability was removed from the 2003+ viewer offerings.
+
+To developers: I am not a C/C++ or Win32 API programmer as you can probably tell.
+The code and API of this DLL could certainly do with some tidying up, and the
+error trapping, where it exists, is very basic. I'll happily accept patches!
+
+This library is covered by the GPL (http://www.gnu.org/licenses/)
+It is NOT covered by the LGPL, so can only be used in GPL compatable programs.
+(http://www.gnu.org/licenses/why-not-lgpl.html)
+
+This README.TXT must be distributed with the pptviewlib.dll
+
+This library has a limit of 50 PowerPoints which can be opened simultaneously.
+
+USAGE
+-----
+int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
+
+ Opens the PowerPoint file, counts the number of slides, sizes and positions accordingly
+ and creates preview images of each slide. Note PowerPoint Viewer only allows the
+ slideshow to be resized whilst it is being loaded. It can be moved at any time however.
+
+ The only way to count the number of slides is to step through the entire show. Therefore
+ there will be a delay whilst opening large presentations for the first time.
+ For pre XP/2003 systems, the slideshow will flicker as the screen snapshots are taken.
+
+ filename: The PowerPoint file to be opened. Full path
+ hParentWnd: The window which will become the parent of the slideshow window.
+ Can be NULL.
+ rect: The location/dimensions of the slideshow window.
+ If all properties of this structure are zero, the dimensions of the hParentWnd
+ are used.
+ previewpath If specified, the prefix to use for snapshot images of each slide, in the
+ form: previewpath + n + ".bmp", where n is the slide number.
+ A file called previewpath + "info.txt" will also be created containing information
+ about the PPT file, to speed up future openings of the unmodified file.
+ Note it is up the calling program to directly access these images if they
+ are required.
+
+ RETURNS: An unique identifier to pass to other methods in this library.
+ If < 0, then the PPT failed to open.
+ If >=0, ClosePPT must be called when the PPT is no longer being used
+ or when the calling program is closed to release resources/hooks.
+
+void ClosePPT(int id);
+ Closes the presentation, releasing any resources and hooks.
+
+ id: The value returned from OpenPPT.
+
+int GetCurrentSlide(int id);
+ Returns the current slide number (from 1)
+
+ id: The value returned from OpenPPT.
+
+int GetSlideCount(int id);
+ Returns the total number of slides.
+
+ id: The value returned from OpenPPT.
+
+void NextStep(int id);
+ Advances one step (animation) through the slideshow.
+
+ id: The value returned from OpenPPT.
+
+void PrevStep(int id);
+ Goes backwards one step (animation) through the slideshow.
+
+ id: The value returned from OpenPPT.
+
+void GotoSlide(int id, int slideno);
+ Goes directly to a specific slide in the slideshow
+
+ id: The value returned from OpenPPT.
+ slideno: The number of the slide (from 1) to go directly to.
+
+ If the slide has already been displayed, then the completed slide with animations performed
+ will be shown. This is how the PowerPoint Viewer works so have no control over this.
+
+void RestartShow(int id);
+ Restarts the show from the beginning. To reset animations, behind the scenes it
+ has to travel to the end and step backwards though the entire show. Therefore
+ for large presentations there might be a delay.
+
+ id: The value returned from OpenPPT.
+
+void Blank(int id);
+ Blanks the screen, colour black.
+
+ id: The value returned from OpenPPT.
+
+void Unblank(int id)
+ Unblanks the screen, restoring it to it's pre-blank state.
+
+ id: The value returned from OpenPPT.
+
+void Stop(int id)
+ Moves the slideshow off the screen. (There is no concept of stop show in the PowerPoint Viewer)
+
+ id: The value returned from OpenPPT.
+
+void Resume(int id)
+ Moves the slideshow display back onto the screen following a Stop()
+
+ id: The value returned from OpenPPT.
+
diff --git a/openlp/plugins/presentations/lib/pptviewlib/ppttest.py b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py
new file mode 100644
index 000000000..f65e84f52
--- /dev/null
+++ b/openlp/plugins/presentations/lib/pptviewlib/ppttest.py
@@ -0,0 +1,147 @@
+import sys
+from PyQt4 import QtGui, QtCore
+from ctypes import *
+from ctypes.wintypes import RECT
+
+class PPTViewer(QtGui.QWidget):
+ def __init__(self, parent=None):
+ QtGui.QWidget.__init__(self, parent)
+ self.pptid = -1
+ self.setWindowTitle('PowerPoint Viewer Test')
+
+ PPTLabel = QtGui.QLabel('Open PowerPoint file')
+ slideLabel = QtGui.QLabel('Go to slide #')
+ self.PPTEdit = QtGui.QLineEdit()
+ self.slideEdit = QtGui.QLineEdit()
+ self.total = QtGui.QLabel()
+ PPTBtn = QtGui.QPushButton("Open")
+ PPTDlgBtn = QtGui.QPushButton("...")
+ slideBtn = QtGui.QPushButton("Go")
+ prev = QtGui.QPushButton("Prev")
+ next = QtGui.QPushButton("Next")
+ blank = QtGui.QPushButton("Blank")
+ unblank = QtGui.QPushButton("Unblank")
+ restart = QtGui.QPushButton("Restart")
+ close = QtGui.QPushButton("Close")
+ resume = QtGui.QPushButton("Resume")
+ stop = QtGui.QPushButton("Stop")
+ pptwindow = QtGui.QWidget()
+
+ grid = QtGui.QGridLayout()
+ grid.addWidget(PPTLabel, 0, 0)
+ grid.addWidget(self.PPTEdit, 0, 1)
+ grid.addWidget(PPTDlgBtn, 0, 2)
+ grid.addWidget(PPTBtn, 0, 3)
+ grid.addWidget(slideLabel, 1, 0)
+ grid.addWidget(self.slideEdit, 1, 1)
+ grid.addWidget(slideBtn, 1, 3)
+ grid.addWidget(prev, 2, 0)
+ grid.addWidget(next, 2, 1)
+ grid.addWidget(blank, 3, 0)
+ grid.addWidget(unblank, 3, 1)
+ grid.addWidget(restart, 4, 0)
+ grid.addWidget(close, 4, 1)
+ grid.addWidget(stop, 5, 0)
+ grid.addWidget(resume, 5, 1)
+ grid.addWidget(pptwindow, 6, 0, 10, 3)
+ self.connect(PPTBtn, QtCore.SIGNAL('clicked()'), self.OpenClick)
+ self.connect(PPTDlgBtn, QtCore.SIGNAL('clicked()'), self.OpenDialog)
+ self.connect(slideBtn, QtCore.SIGNAL('clicked()'), self.GotoClick)
+ self.connect(prev, QtCore.SIGNAL('clicked()'), self.PrevClick)
+ self.connect(next, QtCore.SIGNAL('clicked()'), self.NextClick)
+ self.connect(blank, QtCore.SIGNAL('clicked()'), self.BlankClick)
+ self.connect(unblank, QtCore.SIGNAL('clicked()'), self.UnblankClick)
+ self.connect(restart, QtCore.SIGNAL('clicked()'), self.RestartClick)
+ self.connect(close, QtCore.SIGNAL('clicked()'), self.CloseClick)
+ self.connect(stop, QtCore.SIGNAL('clicked()'), self.StopClick)
+ self.connect(resume, QtCore.SIGNAL('clicked()'), self.ResumeClick)
+
+ self.setLayout(grid)
+
+ self.resize(300, 150)
+
+ def PrevClick(self):
+ if self.pptid<0: return
+ pptdll.PrevStep(self.pptid)
+ self.UpdateCurrSlide()
+ app.processEvents()
+
+ def NextClick(self):
+ if(self.pptid<0): return
+ pptdll.NextStep(self.pptid)
+ self.UpdateCurrSlide()
+ app.processEvents()
+
+ def BlankClick(self):
+ if(self.pptid<0): return
+ pptdll.Blank(self.pptid)
+ app.processEvents()
+
+ def UnblankClick(self):
+ if(self.pptid<0): return
+ pptdll.Unblank(self.pptid)
+ app.processEvents()
+
+ def RestartClick(self):
+ if(self.pptid<0): return
+ pptdll.RestartShow(self.pptid)
+ self.UpdateCurrSlide()
+ app.processEvents()
+
+ def StopClick(self):
+ if(self.pptid<0): return
+ pptdll.Stop(self.pptid)
+ app.processEvents()
+
+ def ResumeClick(self):
+ if(self.pptid<0): return
+ pptdll.Resume(self.pptid)
+ app.processEvents()
+
+ def CloseClick(self):
+ if(self.pptid<0): return
+ pptdll.ClosePPT(self.pptid)
+ self.pptid = -1
+ app.processEvents()
+
+ def OpenClick(self):
+ oldid = self.pptid;
+ rect = RECT(100,100,900,700)
+ filename = str(self.PPTEdit.text())
+ print filename
+ self.pptid = pptdll.OpenPPT(filename, None, rect, "c:\\temp\\slide")
+ print "id: " + str(self.pptid)
+ if oldid>=0:
+ pptdll.ClosePPT(oldid);
+ slides = pptdll.GetSlideCount(self.pptid)
+ print "slidecount: " + str(slides)
+ self.total.setNum(pptdll.GetSlideCount(self.pptid))
+ self.UpdateCurrSlide()
+
+ def UpdateCurrSlide(self):
+ if(self.pptid<0): return
+ slide = str(pptdll.GetCurrentSlide(self.pptid))
+ print "currslide: " + slide
+ self.slideEdit.setText(slide)
+ app.processEvents()
+
+ def GotoClick(self):
+ if(self.pptid<0): return
+ print self.slideEdit.text()
+ pptdll.GotoSlide(self.pptid, int(self.slideEdit.text()))
+ self.UpdateCurrSlide()
+ app.processEvents()
+
+ def OpenDialog(self):
+ self.PPTEdit.setText(QtGui.QFileDialog.getOpenFileName(self, 'Open file'))
+
+if __name__ == '__main__':
+ #pptdll = cdll.LoadLibrary(r"C:\Documents and Settings\jonathan\Desktop\pptviewlib.dll")
+ pptdll = cdll.LoadLibrary(r"pptviewlib.dll")
+ pptdll.SetDebug(1)
+ print "Begin..."
+ app = QtGui.QApplication(sys.argv)
+ qb = PPTViewer()
+ qb.show()
+ sys.exit(app.exec_())
+
diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp
new file mode 100644
index 000000000..4e5d8cfd8
--- /dev/null
+++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.cpp
@@ -0,0 +1,753 @@
+/*
+ * PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
+ * Copyright (C) 2008 Jonathan Corwin
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "pptviewlib.h"
+
+// Because of the callbacks used by SetWindowsHookEx, the memory used needs to be
+// sharable across processes (the callbacks are done from a different process)
+// Therefore use data_seg with RWS memory.
+//
+// See http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx for alternative
+// method of holding memory, removing fixed limits which would allow dynamic number
+// of items, rather than a fixed number. Use a Local\ mapping, since global has UAC
+// issues in Vista.
+#pragma data_seg(".PPTVIEWLIB")
+PPTVIEWOBJ pptviewobj[MAX_PPTOBJS] = {NULL};
+HHOOK globalhook = NULL;
+BOOL debug = FALSE;
+#pragma data_seg()
+#pragma comment(linker, "/SECTION:.PPTVIEWLIB,RWS")
+
+#define DEBUG(...) if(debug) printf(__VA_ARGS__)
+
+
+HINSTANCE hInstance = NULL;
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ hInstance = (HINSTANCE)hModule;
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ DEBUG("PROCESS_ATTACH\n");
+ break;
+ case DLL_THREAD_ATTACH:
+ DEBUG("THREAD_ATTACH\n");
+ break;
+ case DLL_THREAD_DETACH:
+ DEBUG("THREAD_DETACH\n");
+ break;
+ case DLL_PROCESS_DETACH:
+ // Clean up... hopefully there is only the one process attached?
+ // We'll find out soon enough during tests!
+ DEBUG("PROCESS_DETACH\n");
+ for(int i = 0; i.bmp" will be appended to complete the path. E.g. "c:\temp\slide" would
+// create "c:\temp\slide1.bmp" slide2.bmp, slide3.bmp etc.
+// It will also create a *info.txt containing information about the ppt
+DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ char cmdline[MAX_PATH * 2];
+ int id;
+
+ DEBUG("OpenPPT start: %s; %s\n", filename, previewpath);
+ DEBUG("OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top, rect.left, rect.bottom, rect.right);
+ if(GetPPTViewerPath(cmdline, sizeof(cmdline))==FALSE)
+ {
+ DEBUG("OpenPPT: GetPPTViewerPath failed\n");
+ return -1;
+ }
+ id = -1;
+ for(int i = 0; ibottom-wndrect->top;
+ pptviewobj[id].rect.right = wndrect->right-wndrect->left;
+ }
+ else
+ {
+ pptviewobj[id].rect.top = rect.top;
+ pptviewobj[id].rect.left = rect.left;
+ pptviewobj[id].rect.bottom = rect.bottom;
+ pptviewobj[id].rect.right = rect.right;
+ }
+ strcat_s(cmdline, MAX_PATH * 2, "/S \"");
+ strcat_s(cmdline, MAX_PATH * 2, filename);
+ strcat_s(cmdline, MAX_PATH * 2, "\"");
+ memset(&si, 0, sizeof(si));
+ memset(&pi, 0, sizeof(pi));
+ BOOL gotinfo = GetPPTInfo(id);
+ /*
+ * I'd really like to just hook on the new threadid. However this always gives
+ * error 87. Perhaps I'm hooking to soon? No idea... however can't wait
+ * since I need to ensure I pick up the WM_CREATE as this is the only
+ * time the window can be resized in such away the content scales correctly
+ *
+ * hook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,pi.dwThreadId);
+ */
+ if(globalhook!=NULL)
+ UnhookWindowsHookEx(globalhook);
+ globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
+ if(globalhook==0)
+ {
+ DEBUG("OpenPPT: SetWindowsHookEx failed\n");
+ ClosePPT(id);
+ return -1;
+ }
+ pptviewobj[id].state = PPT_STARTED;
+ Sleep(10);
+ if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
+ {
+ DEBUG("OpenPPT: CreateProcess failed\n");
+ ClosePPT(id);
+ return -1;
+ }
+ pptviewobj[id].dwProcessId = pi.dwProcessId;
+ pptviewobj[id].dwThreadId = pi.dwThreadId;
+ pptviewobj[id].hThread = pi.hThread;
+ pptviewobj[id].hProcess = pi.hProcess;
+ while(pptviewobj[id].state==PPT_STARTED)
+ Sleep(10);
+ if(gotinfo)
+ {
+ DEBUG("OpenPPT: Info loaded, no refresh\n");
+ pptviewobj[id].state = PPT_LOADED;
+ Resume(id);
+ }
+ else
+ {
+ DEBUG("OpenPPT: Get info\n");
+ pptviewobj[id].steps = 0;
+ int steps = 0;
+ while(pptviewobj[id].state==PPT_OPENED)
+ {
+ if(steps<=pptviewobj[id].steps)
+ {
+ Sleep(20);
+ DEBUG("OpenPPT: Step %d/%d\n",steps,pptviewobj[id].steps);
+ steps++;
+ NextStep(id);
+ }
+ Sleep(10);
+ }
+ DEBUG("OpenPPT: Steps %d, first slide steps %d\n",pptviewobj[id].steps,pptviewobj[id].firstSlideSteps);
+ SavePPTInfo(id);
+ if(pptviewobj[id].state==PPT_CLOSING){
+ ClosePPT(id);
+ id=-1;
+ }
+ else
+ RestartShow(id);
+ }
+ if(id>=0)
+ {
+ if(pptviewobj[id].mhook!=NULL)
+ UnhookWindowsHookEx(pptviewobj[id].mhook);
+ pptviewobj[id].mhook = NULL;
+ }
+ DEBUG("OpenPPT: Exit: id=%i\n", id);
+ return id;
+}
+// Load information about the ppt from an info.txt file.
+// Format:
+// version
+// filedate
+// filesize
+// slidecount
+// first slide steps
+BOOL GetPPTInfo(int id)
+{
+ struct _stat filestats;
+ char info[MAX_PATH];
+ FILE* pFile;
+ char buf[100];
+
+ DEBUG("GetPPTInfo: start\n");
+ if(_stat(pptviewobj[id].filename, &filestats)!=0)
+ return FALSE;
+ sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath);
+ int err = fopen_s(&pFile, info, "r");
+ if(err!=0)
+ {
+ DEBUG("GetPPTInfo: file open failed - %d\n", err);
+ return FALSE;
+ }
+ fgets(buf, 100, pFile); // version == 1
+ fgets(buf, 100, pFile);
+ if(filestats.st_mtime!=atoi(buf))
+ {
+ fclose (pFile);
+ return FALSE;
+ }
+ fgets(buf, 100, pFile);
+ if(filestats.st_size!=atoi(buf))
+ {
+ fclose (pFile);
+ return FALSE;
+ }
+ fgets(buf, 100, pFile); // slidecount
+ int slidecount = atoi(buf);
+ fgets(buf, 100, pFile); // first slide steps
+ int firstslidesteps = atoi(buf);
+ // check all the preview images still exist
+ for(int i = 1; i<=slidecount; i++)
+ {
+ sprintf_s(info, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, i);
+ if(GetFileAttributes(info)==INVALID_FILE_ATTRIBUTES)
+ return FALSE;
+ }
+ fclose(pFile);
+ pptviewobj[id].slideCount = slidecount;
+ pptviewobj[id].firstSlideSteps = firstslidesteps;
+ DEBUG("GetPPTInfo: exit ok\n");
+ return TRUE;
+}
+
+BOOL SavePPTInfo(int id)
+{
+ struct _stat filestats;
+ char info[MAX_PATH];
+ FILE* pFile;
+
+ DEBUG("SavePPTInfo: start\n");
+ if(_stat(pptviewobj[id].filename, &filestats)!=0)
+ {
+ DEBUG("SavePPTInfo: stat of %s failed\n", pptviewobj[id].filename);
+ return FALSE;
+ }
+ sprintf_s(info, MAX_PATH, "%sinfo.txt", pptviewobj[id].previewpath);
+ int err = fopen_s(&pFile, info, "w");
+ if(err!=0)
+ {
+ DEBUG("SavePPTInfo: fopen of %s failed%i\n", info, err);
+ return FALSE;
+ }
+ fprintf(pFile, "1\n");
+ fprintf(pFile, "%u\n", filestats.st_mtime);
+ fprintf(pFile, "%u\n", filestats.st_size);
+ fprintf(pFile, "%u\n", pptviewobj[id].slideCount);
+ fprintf(pFile, "%u\n", pptviewobj[id].firstSlideSteps);
+ fclose (pFile);
+ DEBUG("SavePPTInfo: exit ok\n");
+ return TRUE;
+}
+
+// Get the path of the PowerPoint viewer from the registry
+BOOL GetPPTViewerPath(char *pptviewerpath, int strsize)
+{
+ HKEY hkey;
+ DWORD dwtype, dwsize;
+ LRESULT lresult;
+
+ DEBUG("GetPPTViewerPath: start\n");
+ if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
+ if(RegOpenKeyEx(HKEY_CLASSES_ROOT, "Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)
+ return FALSE;
+ dwtype = REG_SZ;
+ dwsize = (DWORD)strsize;
+ lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pptviewerpath, &dwsize );
+ RegCloseKey(hkey);
+ if(lresult!=ERROR_SUCCESS)
+ return FALSE;
+ pptviewerpath[strlen(pptviewerpath)-4] = '\0'; // remove "%1" from end of key value
+ DEBUG("GetPPTViewerPath: exit ok\n");
+ return TRUE;
+}
+
+// Unhook the Windows hook
+void Unhook(int id)
+{
+ DEBUG("Unhook: start %d\n", id);
+ if(pptviewobj[id].hook!=NULL)
+ UnhookWindowsHookEx(pptviewobj[id].hook);
+ if(pptviewobj[id].mhook!=NULL)
+ UnhookWindowsHookEx(pptviewobj[id].mhook);
+ pptviewobj[id].hook = NULL;
+ pptviewobj[id].mhook = NULL;
+ DEBUG("Unhook: exit ok\n");
+}
+
+// Close the PowerPoint viewer, release resources
+DllExport void ClosePPT(int id)
+{
+ DEBUG("ClosePPT: start%d\n", id);
+ pptviewobj[id].state = PPT_CLOSED;
+ Unhook(id);
+ if(pptviewobj[id].hWnd==0)
+ TerminateThread(pptviewobj[id].hThread, 0);
+ else
+ PostMessage(pptviewobj[id].hWnd, WM_CLOSE, 0, 0);
+ CloseHandle(pptviewobj[id].hThread);
+ CloseHandle(pptviewobj[id].hProcess);
+ memset(&pptviewobj[id], 0, sizeof(PPTVIEWOBJ));
+ DEBUG("ClosePPT: exit ok\n");
+ return;
+}
+// Moves the show back onto the display
+DllExport void Resume(int id)
+{
+ DEBUG("Resume: %d\n", id);
+ MoveWindow(pptviewobj[id].hWnd, pptviewobj[id].rect.left, pptviewobj[id].rect.top,
+ pptviewobj[id].rect.right - pptviewobj[id].rect.left,
+ pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE);
+ Unblank(id);
+}
+// Moves the show off the screen so it can't be seen
+DllExport void Stop(int id)
+{
+ DEBUG("Stop:%d\n", id);
+ MoveWindow(pptviewobj[id].hWnd, -32000, -32000,
+ pptviewobj[id].rect.right - pptviewobj[id].rect.left,
+ pptviewobj[id].rect.bottom - pptviewobj[id].rect.top, TRUE);
+}
+
+// Return the total number of slides
+DllExport int GetSlideCount(int id)
+{
+ DEBUG("GetSlideCount:%d\n", id);
+ if(pptviewobj[id].state==0)
+ return -1;
+ else
+ return pptviewobj[id].slideCount;
+}
+
+// Return the number of the slide currently viewing
+DllExport int GetCurrentSlide(int id)
+{
+ DEBUG("GetCurrentSlide:%d\n", id);
+ if(pptviewobj[id].state==0)
+ return -1;
+ else
+ return pptviewobj[id].currentSlide;
+}
+
+// Take a step forwards through the show
+DllExport void NextStep(int id)
+{
+ DEBUG("NextStep:%d\n", id);
+ if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount)
+ return;
+ PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);
+}
+
+// Take a step backwards through the show
+DllExport void PrevStep(int id)
+{
+ DEBUG("PrevStep:%d\n", id);
+ PostMessage(pptviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);
+}
+
+// Blank the show (black screen)
+DllExport void Blank(int id)
+{
+ // B just toggles blank on/off. However pressing any key unblanks.
+ // So send random unmapped letter first (say 'A'), then we can
+ // better guarantee B will blank instead of trying to guess
+ // whether it was already blank or not.
+ DEBUG("Blank:%d\n", id);
+ HWND h1 = GetForegroundWindow();
+ HWND h2 = GetFocus();
+ SetForegroundWindow(pptviewobj[id].hWnd);
+ SetFocus(pptviewobj[id].hWnd);
+ Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
+ keybd_event((int)'A', 0, 0, 0);
+ keybd_event((int)'A', 0, KEYEVENTF_KEYUP, 0);
+ keybd_event((int)'B', 0, 0, 0);
+ keybd_event((int)'B', 0, KEYEVENTF_KEYUP, 0);
+ SetForegroundWindow(h1);
+ SetFocus(h2);
+ //PostMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'B', 0x00300001);
+ //PostMessage(pptviewobj[id].hWnd2, WM_CHAR, 'b', 0x00300001);
+ //PostMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'B', 0xC0300001);
+}
+// Unblank the show
+DllExport void Unblank(int id)
+{
+ DEBUG("Unblank:%d\n", id);
+ // Pressing any key resumes.
+ // For some reason SendMessage works for unblanking, but not blanking.
+// SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, 'A', 0);
+ SendMessage(pptviewobj[id].hWnd2, WM_CHAR, 'A', 0);
+// SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, 'A', 0);
+// HWND h1 = GetForegroundWindow();
+// HWND h2 = GetFocus();
+// Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
+// SetForegroundWindow(pptviewobj[id].hWnd);
+// SetFocus(pptviewobj[id].hWnd);
+// keybd_event((int)'A', 0, 0, 0);
+// SetForegroundWindow(h1);
+// SetFocus(h2);
+}
+
+// Go directly to a slide
+DllExport void GotoSlide(int id, int slideno)
+{
+ DEBUG("GotoSlide %i %i:\n", id, slideno);
+ // Did try WM_KEYDOWN/WM_CHAR/WM_KEYUP with SendMessage but didn't work
+ // perhaps I was sending to the wrong window? No idea.
+ // Anyway fall back to keybd_event, which is OK as long we makesure
+ // the slideshow has focus first
+ char ch[10];
+
+ if(slideno<0) return;
+ _itoa_s(slideno, ch, 10, 10);
+ HWND h1 = GetForegroundWindow();
+ HWND h2 = GetFocus();
+ SetForegroundWindow(pptviewobj[id].hWnd);
+ SetFocus(pptviewobj[id].hWnd);
+ Sleep(50); // slight pause, otherwise event triggering this call may grab focus back!
+ for(int i=0;i<10;i++)
+ {
+ if(ch[i]=='\0') break;
+ keybd_event((BYTE)ch[i], 0, 0, 0);
+ keybd_event((BYTE)ch[i], 0, KEYEVENTF_KEYUP, 0);
+ }
+ keybd_event(VK_RETURN, 0, 0, 0);
+ keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
+ SetForegroundWindow(h1);
+ SetFocus(h2);
+
+ //for(int i=0;i<10;i++)
+ //{
+ // if(ch[i]=='\0') break;
+ // SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, ch[i], 0);
+ // SendMessage(pptviewobj[id].hWnd2, WM_CHAR, ch[i], 0);
+ // SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, ch[i], 0);
+ //}
+ //SendMessage(pptviewobj[id].hWnd2, WM_KEYDOWN, VK_RETURN, 0);
+ //SendMessage(pptviewobj[id].hWnd2, WM_CHAR, VK_RETURN, 0);
+ //SendMessage(pptviewobj[id].hWnd2, WM_KEYUP, VK_RETURN, 0);
+ //keybd_event(VK_RETURN, 0, 0, 0);
+}
+
+// Restart the show from the beginning
+DllExport void RestartShow(int id)
+{
+ // If we just go direct to slide one, then it remembers that all other slides have
+ // been animated, so ends up just showing the completed slides of those slides that
+ // have been animated next time we advance.
+ // Only way I've found to get around this is to step backwards all the way through.
+ // Lets move the window out of the way first so the audience doesn't see this.
+ DEBUG("RestartShow:%d\n", id);
+ Stop(id);
+ GotoSlide(id, pptviewobj[id].slideCount);
+ while(pptviewobj[id].currentSlide>1)
+ {
+ PrevStep(id);
+ Sleep(10);
+ }
+ for(int i=0;i<=pptviewobj[id].firstSlideSteps;i++)
+ {
+ PrevStep(id);
+ Sleep(10);
+ }
+ Resume(id);
+}
+
+// This hook is started with the PPTVIEW.EXE process and waits for the
+// WM_CREATEWND message. At this point (and only this point) can the
+// window be resized to the correct size.
+// Release the hook as soon as we're complete to free up resources
+LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ HHOOK hook = globalhook;
+ if(nCode==HCBT_CREATEWND)
+ {
+ char csClassName[16];
+ HWND hCurrWnd = (HWND)wParam;
+ DWORD retProcId = NULL;
+ GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
+ if((strcmp(csClassName, "paneClassDC")==0)
+ ||(strcmp(csClassName, "screenClass")==0))
+ {
+ int id=-1;
+ DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
+ for(int i=0; i=0)
+ {
+ if(strcmp(csClassName, "paneClassDC")==0)
+ pptviewobj[id].hWnd2=hCurrWnd;
+ else
+ {
+ pptviewobj[id].hWnd=hCurrWnd;
+ CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
+ if(pptviewobj[id].hParentWnd!=NULL)
+ cw->lpcs->hwndParent = pptviewobj[id].hParentWnd;
+ cw->lpcs->cy=(pptviewobj[id].rect.bottom-pptviewobj[id].rect.top);
+ cw->lpcs->cx=(pptviewobj[id].rect.right-pptviewobj[id].rect.left);
+ cw->lpcs->y=-32000;
+ cw->lpcs->x=-32000;
+ }
+ if((pptviewobj[id].hWnd!=NULL)&&(pptviewobj[id].hWnd2!=NULL))
+ {
+ UnhookWindowsHookEx(globalhook);
+ globalhook=NULL;
+ pptviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pptviewobj[id].dwThreadId);
+ pptviewobj[id].mhook = SetWindowsHookEx(WH_GETMESSAGE,GetMsgProc,hInstance,pptviewobj[id].dwThreadId);
+ Sleep(10);
+ pptviewobj[id].state = PPT_OPENED;
+ }
+ }
+ }
+ }
+ return CallNextHookEx(hook,nCode,wParam,lParam);
+}
+
+// This hook exists whilst the slideshow is loading but only listens on the
+// slideshows thread. It listens out for mousewheel events
+LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ HHOOK hook = NULL;
+ MSG *pMSG = (MSG *)lParam;
+ DWORD windowthread = GetWindowThreadProcessId(pMSG->hwnd,NULL);
+ int id=-1;
+ for(int i=0; i=0&&nCode==HC_ACTION&&wParam==PM_REMOVE&&pMSG->message==WM_MOUSEWHEEL)
+ {
+ if(pptviewobj[id].state!=PPT_LOADED)
+ {
+ if(pptviewobj[id].currentSlide==1)
+ pptviewobj[id].firstSlideSteps++;
+ pptviewobj[id].steps++;
+ }
+ }
+ return CallNextHookEx(hook, nCode, wParam, lParam);
+}
+// This hook exists whilst the slideshow is running but only listens on the
+// slideshows thread. It listens out for slide changes, message WM_USER+22.
+LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
+ CWPSTRUCT *cwp;
+ cwp = (CWPSTRUCT *)lParam;
+ HHOOK hook = NULL;
+ char filename[MAX_PATH];
+
+ DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
+ int id=-1;
+ for(int i=0; i=0)&&(nCode==HC_ACTION))
+ {
+ if(cwp->message==WM_USER+22)
+ {
+ if(pptviewobj[id].state != PPT_LOADED)
+ {
+ if((pptviewobj[id].currentSlide>0)
+ && (pptviewobj[id].previewpath!=NULL&&strlen(pptviewobj[id].previewpath)>0))
+ {
+ sprintf_s(filename, MAX_PATH, "%s%i.bmp", pptviewobj[id].previewpath, pptviewobj[id].currentSlide);
+ CaptureAndSaveWindow(cwp->hwnd, filename);
+ }
+ }
+ if(cwp->wParam==0)
+ {
+ if(pptviewobj[id].currentSlide>0)
+ {
+ pptviewobj[id].state = PPT_LOADED;
+ pptviewobj[id].currentSlide = pptviewobj[id].slideCount+1;
+ }
+ }
+ else
+ {
+ pptviewobj[id].currentSlide = cwp->wParam - 255;
+ if(pptviewobj[id].currentSlide>pptviewobj[id].slideCount)
+ pptviewobj[id].slideCount = pptviewobj[id].currentSlide;
+ }
+ }
+ if((pptviewobj[id].state != PPT_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT))
+ pptviewobj[id].state = PPT_CLOSING;
+ }
+ return CallNextHookEx(hook,nCode,wParam,lParam);
+}
+
+VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename)
+{
+ HBITMAP hBmp;
+ if ((hBmp = CaptureWindow(hWnd)) == NULL)
+ return;
+
+ RECT client;
+ GetClientRect (hWnd, &client);
+ UINT uiBytesPerRow = 3 * client.right; // RGB takes 24 bits
+ UINT uiRemainderForPadding;
+
+ if ((uiRemainderForPadding = uiBytesPerRow % sizeof (DWORD)) > 0)
+ uiBytesPerRow += (sizeof (DWORD) - uiRemainderForPadding);
+
+ UINT uiBytesPerAllRows = uiBytesPerRow * client.bottom;
+ PBYTE pDataBits;
+
+ if ((pDataBits = new BYTE [uiBytesPerAllRows]) != NULL)
+ {
+ BITMAPINFOHEADER bmi = {0};
+ BITMAPFILEHEADER bmf = {0};
+
+ // Prepare to get the data out of HBITMAP:
+ bmi.biSize = sizeof (bmi);
+ bmi.biPlanes = 1;
+ bmi.biBitCount = 24;
+ bmi.biHeight = client.bottom;
+ bmi.biWidth = client.right;
+
+ // Get it:
+ HDC hDC = GetDC (hWnd);
+ GetDIBits (hDC, hBmp, 0, client.bottom, pDataBits,
+ (BITMAPINFO*) &bmi, DIB_RGB_COLORS);
+ ReleaseDC (hWnd, hDC);
+
+ // Fill the file header:
+ bmf.bfOffBits = sizeof (bmf) + sizeof (bmi);
+ bmf.bfSize = bmf.bfOffBits + uiBytesPerAllRows;
+ bmf.bfType = 0x4D42;
+
+ // Writing:
+ FILE* pFile;
+ int err = fopen_s(&pFile, filename, "wb");
+ if (err == 0)
+ {
+ fwrite (&bmf, sizeof (bmf), 1, pFile);
+ fwrite (&bmi, sizeof (bmi), 1, pFile);
+ fwrite (pDataBits, sizeof (BYTE), uiBytesPerAllRows, pFile);
+ fclose (pFile);
+ }
+ delete [] pDataBits;
+ }
+ DeleteObject (hBmp);
+}
+HBITMAP CaptureWindow (HWND hWnd) {
+ HDC hDC;
+ BOOL bOk = FALSE;
+ HBITMAP hImage = NULL;
+
+ hDC = GetDC (hWnd);
+ RECT rcClient;
+ GetClientRect (hWnd, &rcClient);
+ if ((hImage = CreateCompatibleBitmap (hDC, rcClient.right, rcClient.bottom)) != NULL)
+ {
+ HDC hMemDC;
+ HBITMAP hDCBmp;
+
+ if ((hMemDC = CreateCompatibleDC (hDC)) != NULL)
+ {
+ hDCBmp = (HBITMAP) SelectObject (hMemDC, hImage);
+ HMODULE hLib = LoadLibrary("User32");
+ // PrintWindow works for windows outside displayable area
+ // but was only introduced in WinXP. BitBlt requires the window to be topmost
+ // and within the viewable area of the display
+ if(GetProcAddress(hLib, "PrintWindow")==NULL)
+ {
+ SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE);
+ BitBlt (hMemDC, 0, 0, rcClient.right, rcClient.bottom, hDC, 0, 0, SRCCOPY);
+ SetWindowPos(hWnd, HWND_NOTOPMOST, -32000, -32000, 0, 0, SWP_NOSIZE);
+ }
+ else
+ {
+ PrintWindow(hWnd, hMemDC, 0);
+ }
+ SelectObject (hMemDC, hDCBmp);
+ DeleteDC (hMemDC);
+ bOk = TRUE;
+ }
+ }
+ ReleaseDC (hWnd, hDC);
+ if (! bOk)
+ {
+ if (hImage)
+ {
+ DeleteObject (hImage);
+ hImage = NULL;
+ }
+ }
+ return hImage;
+}
diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll
new file mode 100644
index 000000000..13ea7d182
Binary files /dev/null and b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.dll differ
diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h
new file mode 100644
index 000000000..a40f07cd3
--- /dev/null
+++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.h
@@ -0,0 +1,54 @@
+
+#define DllExport extern "C" __declspec( dllexport )
+
+enum PPTVIEWSTATE { PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED, PPT_CLOSING};
+
+DllExport int OpenPPT(char *filename, HWND hParentWnd, RECT rect, char *previewpath);
+DllExport void ClosePPT(int id);
+DllExport int GetCurrentSlide(int id);
+DllExport int GetSlideCount(int id);
+DllExport void NextStep(int id);
+DllExport void PrevStep(int id);
+DllExport void GotoSlide(int id, int slideno);
+DllExport void RestartShow(int id);
+DllExport void Blank(int id);
+DllExport void Unblank(int id);
+DllExport void Stop(int id);
+DllExport void Resume(int id);
+DllExport void SetDebug(BOOL onoff);
+
+LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
+BOOL GetPPTViewerPath(char *pptviewerpath, int strsize);
+HBITMAP CaptureWindow (HWND hWnd);
+VOID SaveBitmap (CHAR* filename, HBITMAP hBmp) ;
+VOID CaptureAndSaveWindow(HWND hWnd, CHAR* filename);
+BOOL GetPPTInfo(int id);
+BOOL SavePPTInfo(int id);
+
+
+void Unhook(int id);
+
+#define MAX_PPTOBJS 50
+
+struct PPTVIEWOBJ
+{
+ HHOOK hook;
+ HHOOK mhook;
+ HWND hWnd;
+ HWND hWnd2;
+ HWND hParentWnd;
+ HANDLE hProcess;
+ HANDLE hThread;
+ DWORD dwProcessId;
+ DWORD dwThreadId;
+ RECT rect;
+ int slideCount;
+ int currentSlide;
+ int firstSlideSteps;
+ int steps;
+ char filename[MAX_PATH];
+ char previewpath[MAX_PATH];
+ PPTVIEWSTATE state;
+};
\ No newline at end of file
diff --git a/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj
new file mode 100644
index 000000000..13a9e4282
--- /dev/null
+++ b/openlp/plugins/presentations/lib/pptviewlib/pptviewlib.vcproj
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openlp/plugins/presentations/lib/pptviewlib/test.ppt b/openlp/plugins/presentations/lib/pptviewlib/test.ppt
new file mode 100644
index 000000000..1d90168b1
Binary files /dev/null and b/openlp/plugins/presentations/lib/pptviewlib/test.ppt differ