forked from openlp/openlp
remove ppt viewer
This commit is contained in:
parent
cffd8e603d
commit
f7169ee708
@ -259,7 +259,8 @@ class Settings(QtCore.QSettings):
|
||||
('media/last directory', 'media/last directory', [(str_to_path, None)]),
|
||||
('songuasge/db password', 'songusage/db password', []),
|
||||
('songuasge/db hostname', 'songusage/db hostname', []),
|
||||
('songuasge/db database', 'songusage/db database', [])
|
||||
('songuasge/db database', 'songusage/db database', []),
|
||||
('presentations / Powerpoint Viewer', '', [])
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
|
@ -98,7 +98,7 @@ class UiAboutDialog(object):
|
||||
'OpenLP is free church presentation software, or lyrics '
|
||||
'projection software, used to display slides of songs, Bible '
|
||||
'verses, videos, images, and even presentations (if '
|
||||
'Impress, PowerPoint or PowerPoint Viewer is installed) '
|
||||
'Impress or PowerPoint is installed) '
|
||||
'for church worship using a computer and a data projector.\n'
|
||||
'\n'
|
||||
'Find out more about OpenLP: http://openlp.org/\n'
|
||||
|
@ -1,307 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2018 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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; version 2 of the License. #
|
||||
# #
|
||||
# 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, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
import logging
|
||||
import re
|
||||
import zipfile
|
||||
from xml.etree import ElementTree
|
||||
|
||||
from openlp.core.common import is_win
|
||||
from openlp.core.common.applocation import AppLocation
|
||||
from openlp.core.display.screens import ScreenList
|
||||
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
|
||||
|
||||
if is_win():
|
||||
from ctypes import cdll
|
||||
from ctypes.wintypes import RECT
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PptviewController(PresentationController):
|
||||
"""
|
||||
Class to control interactions with PowerPoint Viewer Presentations. It creates the runtime Environment , Loads the
|
||||
and Closes the Presentation. As well as triggering the correct activities based on the users input
|
||||
"""
|
||||
log.info('PPTViewController loaded')
|
||||
|
||||
def __init__(self, plugin):
|
||||
"""
|
||||
Initialise the class
|
||||
"""
|
||||
log.debug('Initialising')
|
||||
self.process = None
|
||||
super(PptviewController, self).__init__(plugin, 'Powerpoint Viewer', PptviewDocument)
|
||||
self.supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm']
|
||||
|
||||
def check_available(self):
|
||||
"""
|
||||
PPT Viewer is able to run on this machine.
|
||||
"""
|
||||
log.debug('check_available')
|
||||
if not is_win():
|
||||
return False
|
||||
return self.check_installed()
|
||||
|
||||
if is_win():
|
||||
def check_installed(self):
|
||||
"""
|
||||
Check the viewer is installed.
|
||||
"""
|
||||
log.debug('Check installed')
|
||||
try:
|
||||
self.start_process()
|
||||
return self.process.CheckInstalled()
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
def start_process(self):
|
||||
"""
|
||||
Loads the PPTVIEWLIB library.
|
||||
"""
|
||||
if self.process:
|
||||
return
|
||||
log.debug('start PPTView')
|
||||
dll_path = AppLocation.get_directory(AppLocation.AppDir) \
|
||||
/ 'plugins' / 'presentations' / 'lib' / 'pptviewlib' / 'pptviewlib.dll'
|
||||
self.process = cdll.LoadLibrary(str(dll_path))
|
||||
if log.isEnabledFor(logging.DEBUG):
|
||||
self.process.SetDebug(1)
|
||||
|
||||
def kill(self):
|
||||
"""
|
||||
Called at system exit to clean up any running presentations
|
||||
"""
|
||||
log.debug('Kill pptviewer')
|
||||
while self.docs:
|
||||
self.docs[0].close_presentation()
|
||||
|
||||
|
||||
class PptviewDocument(PresentationDocument):
|
||||
"""
|
||||
Class which holds information and controls a single presentation.
|
||||
"""
|
||||
def __init__(self, controller, document_path):
|
||||
"""
|
||||
Constructor, store information about the file and initialise.
|
||||
|
||||
:param openlp.core.common.path.Path document_path: File path to the document to load
|
||||
:rtype: None
|
||||
"""
|
||||
log.debug('Init Presentation PowerPoint')
|
||||
super().__init__(controller, document_path)
|
||||
self.presentation = None
|
||||
self.ppt_id = None
|
||||
self.blanked = False
|
||||
self.hidden = False
|
||||
|
||||
def load_presentation(self):
|
||||
"""
|
||||
Called when a presentation is added to the SlideController. It builds the environment, starts communication with
|
||||
the background PptView task started earlier.
|
||||
"""
|
||||
log.debug('LoadPresentation')
|
||||
temp_path = self.get_temp_folder()
|
||||
size = ScreenList().current['size']
|
||||
rect = RECT(size.x(), size.y(), size.right(), size.bottom())
|
||||
preview_path = temp_path / 'slide'
|
||||
# Ensure that the paths are null terminated
|
||||
file_path_utf16 = str(self.file_path).encode('utf-16-le') + b'\0'
|
||||
preview_path_utf16 = str(preview_path).encode('utf-16-le') + b'\0'
|
||||
if not temp_path.is_dir():
|
||||
temp_path.mkdir(parents=True)
|
||||
self.ppt_id = self.controller.process.OpenPPT(file_path_utf16, None, rect, preview_path_utf16)
|
||||
if self.ppt_id >= 0:
|
||||
self.create_thumbnails()
|
||||
self.stop_presentation()
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def create_thumbnails(self):
|
||||
"""
|
||||
PPTviewLib creates large BMP's, but we want small PNG's for consistency. Convert them here.
|
||||
"""
|
||||
log.debug('create_thumbnails')
|
||||
if self.check_thumbnails():
|
||||
return
|
||||
log.debug('create_thumbnails proceeding')
|
||||
for idx in range(self.get_slide_count()):
|
||||
path = self.get_temp_folder() / 'slide{index:d}.bmp'.format(index=idx + 1)
|
||||
self.convert_thumbnail(path, idx + 1)
|
||||
|
||||
def create_titles_and_notes(self):
|
||||
"""
|
||||
Extracts the titles and notes from the zipped file
|
||||
and writes the list of titles (one per slide)
|
||||
to 'titles.txt'
|
||||
and the notes to 'slideNotes[x].txt'
|
||||
in the thumbnails directory
|
||||
"""
|
||||
titles = None
|
||||
notes = None
|
||||
# let's make sure we have a valid zipped presentation
|
||||
if self.file_path.exists() and zipfile.is_zipfile(str(self.file_path)):
|
||||
namespaces = {"p": "http://schemas.openxmlformats.org/presentationml/2006/main",
|
||||
"a": "http://schemas.openxmlformats.org/drawingml/2006/main"}
|
||||
# open the file
|
||||
with zipfile.ZipFile(str(self.file_path)) as zip_file:
|
||||
# find the presentation.xml to get the slide count
|
||||
with zip_file.open('ppt/presentation.xml') as pres:
|
||||
tree = ElementTree.parse(pres)
|
||||
nodes = tree.getroot().findall(".//p:sldIdLst/p:sldId", namespaces=namespaces)
|
||||
# initialize the lists
|
||||
titles = ['' for i in range(len(nodes))]
|
||||
notes = ['' for i in range(len(nodes))]
|
||||
# loop thru the file list to find slides and notes
|
||||
for zip_info in zip_file.infolist():
|
||||
node_type = ''
|
||||
index = -1
|
||||
list_to_add = None
|
||||
# check if it is a slide
|
||||
match = re.search(r'slides/slide(.+)\.xml', zip_info.filename)
|
||||
if match:
|
||||
index = int(match.group(1)) - 1
|
||||
node_type = 'ctrTitle'
|
||||
list_to_add = titles
|
||||
# or a note
|
||||
match = re.search(r'notesSlides/notesSlide(.+)\.xml', zip_info.filename)
|
||||
if match:
|
||||
index = int(match.group(1)) - 1
|
||||
node_type = 'body'
|
||||
list_to_add = notes
|
||||
# if it is one of our files, index shouldn't be -1
|
||||
if index >= 0:
|
||||
with zip_file.open(zip_info) as zipped_file:
|
||||
tree = ElementTree.parse(zipped_file)
|
||||
text = ''
|
||||
nodes = tree.getroot().findall(".//p:ph[@type='" + node_type + "']../../..//p:txBody//a:t",
|
||||
namespaces=namespaces)
|
||||
# if we found any content
|
||||
if nodes and len(nodes) > 0:
|
||||
for node in nodes:
|
||||
if len(text) > 0:
|
||||
text += '\n'
|
||||
text += node.text
|
||||
# Let's remove the \n from the titles and
|
||||
# just add one at the end
|
||||
if node_type == 'ctrTitle':
|
||||
text = text.replace('\n', ' ').replace('\x0b', ' ') + '\n'
|
||||
list_to_add[index] = text
|
||||
# now let's write the files
|
||||
self.save_titles_and_notes(titles, notes)
|
||||
|
||||
def close_presentation(self):
|
||||
"""
|
||||
Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being
|
||||
shut down.
|
||||
"""
|
||||
log.debug('ClosePresentation')
|
||||
if self.controller.process:
|
||||
self.controller.process.ClosePPT(self.ppt_id)
|
||||
self.ppt_id = -1
|
||||
self.controller.remove_doc(self)
|
||||
|
||||
def is_loaded(self):
|
||||
"""
|
||||
Returns true if a presentation is loaded.
|
||||
"""
|
||||
if self.ppt_id < 0:
|
||||
return False
|
||||
if self.get_slide_count() < 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
Returns true if a presentation is currently active.
|
||||
"""
|
||||
return self.is_loaded() and not self.hidden
|
||||
|
||||
def blank_screen(self):
|
||||
"""
|
||||
Blanks the screen.
|
||||
"""
|
||||
self.controller.process.Blank(self.ppt_id)
|
||||
self.blanked = True
|
||||
|
||||
def unblank_screen(self):
|
||||
"""
|
||||
Unblanks (restores) the presentation.
|
||||
"""
|
||||
self.controller.process.Unblank(self.ppt_id)
|
||||
self.blanked = False
|
||||
|
||||
def is_blank(self):
|
||||
"""
|
||||
Returns true if screen is blank.
|
||||
"""
|
||||
log.debug('is blank OpenOffice')
|
||||
return self.blanked
|
||||
|
||||
def stop_presentation(self):
|
||||
"""
|
||||
Stops the current presentation and hides the output.
|
||||
"""
|
||||
self.hidden = True
|
||||
self.controller.process.Stop(self.ppt_id)
|
||||
|
||||
def start_presentation(self):
|
||||
"""
|
||||
Starts a presentation from the beginning.
|
||||
"""
|
||||
if self.hidden:
|
||||
self.hidden = False
|
||||
self.controller.process.Resume(self.ppt_id)
|
||||
else:
|
||||
self.controller.process.RestartShow(self.ppt_id)
|
||||
|
||||
def get_slide_number(self):
|
||||
"""
|
||||
Returns the current slide number.
|
||||
"""
|
||||
return self.controller.process.GetCurrentSlide(self.ppt_id)
|
||||
|
||||
def get_slide_count(self):
|
||||
"""
|
||||
Returns total number of slides.
|
||||
"""
|
||||
return self.controller.process.GetSlideCount(self.ppt_id)
|
||||
|
||||
def goto_slide(self, slide_no):
|
||||
"""
|
||||
Moves to a specific slide in the presentation.
|
||||
|
||||
:param slide_no: The slide the text is required for, starting at 1
|
||||
"""
|
||||
self.controller.process.GotoSlide(self.ppt_id, slide_no)
|
||||
|
||||
def next_step(self):
|
||||
"""
|
||||
Triggers the next effect of slide on the running presentation.
|
||||
"""
|
||||
self.controller.process.NextStep(self.ppt_id)
|
||||
|
||||
def previous_step(self):
|
||||
"""
|
||||
Triggers the previous slide on the running presentation.
|
||||
"""
|
||||
self.controller.process.PrevStep(self.ppt_id)
|
@ -1,121 +0,0 @@
|
||||
|
||||
PPTVIEWLIB - Control PowerPoint Viewer 2003/2007 (for openlp.org)
|
||||
Copyright (C) 2008-2018 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.
|
||||
|
||||
This project can be built with the free Microsoft Visual C++ 2008 Express Edition.
|
||||
|
||||
USAGE
|
||||
-----
|
||||
BOOL CheckInstalled(void);
|
||||
Returns TRUE if PowerPointViewer is installed. FALSE if not.
|
||||
|
||||
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.
|
||||
|
@ -1,210 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2018 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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; version 2 of the License. #
|
||||
# #
|
||||
# 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, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
|
||||
import sys
|
||||
from ctypes import *
|
||||
from ctypes.wintypes import RECT
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
|
||||
class PPTViewer(QtWidgets.QWidget):
|
||||
"""
|
||||
Standalone Test Harness for the pptviewlib library
|
||||
"""
|
||||
def __init__(self, parent=None):
|
||||
super(PPTViewer, self).__init__(parent)
|
||||
self.pptid = -1
|
||||
self.setWindowTitle('PowerPoint Viewer Test')
|
||||
|
||||
ppt_label = QtWidgets.QLabel('Open PowerPoint file')
|
||||
slide_label = QtWidgets.QLabel('Go to slide #')
|
||||
self.pptEdit = QtWidgets.QLineEdit()
|
||||
self.slideEdit = QtWidgets.QLineEdit()
|
||||
x_label = QtWidgets.QLabel('X pos')
|
||||
y_label = QtWidgets.QLabel('Y pos')
|
||||
width_label = QtWidgets.QLabel('Width')
|
||||
height_label = QtWidgets.QLabel('Height')
|
||||
self.xEdit = QtWidgets.QLineEdit('100')
|
||||
self.yEdit = QtWidgets.QLineEdit('100')
|
||||
self.widthEdit = QtWidgets.QLineEdit('900')
|
||||
self.heightEdit = QtWidgets.QLineEdit('700')
|
||||
self.total = QtWidgets.QLabel()
|
||||
ppt_btn = QtWidgets.QPushButton('Open')
|
||||
ppt_dlg_btn = QtWidgets.QPushButton('...')
|
||||
folder_label = QtWidgets.QLabel('Slide .bmp path')
|
||||
self.folderEdit = QtWidgets.QLineEdit('slide')
|
||||
slide_btn = QtWidgets.QPushButton('Go')
|
||||
prev = QtWidgets.QPushButton('Prev')
|
||||
next = QtWidgets.QPushButton('Next')
|
||||
blank = QtWidgets.QPushButton('Blank')
|
||||
unblank = QtWidgets.QPushButton('Unblank')
|
||||
restart = QtWidgets.QPushButton('Restart')
|
||||
close = QtWidgets.QPushButton('Close')
|
||||
resume = QtWidgets.QPushButton('Resume')
|
||||
stop = QtWidgets.QPushButton('Stop')
|
||||
grid = QtWidgets.QGridLayout()
|
||||
row = 0
|
||||
grid.addWidget(folder_label, 0, 0)
|
||||
grid.addWidget(self.folderEdit, 0, 1)
|
||||
row += 1
|
||||
grid.addWidget(x_label, row, 0)
|
||||
grid.addWidget(self.xEdit, row, 1)
|
||||
grid.addWidget(y_label, row, 2)
|
||||
grid.addWidget(self.yEdit, row, 3)
|
||||
row += 1
|
||||
grid.addWidget(width_label, row, 0)
|
||||
grid.addWidget(self.widthEdit, row, 1)
|
||||
grid.addWidget(height_label, row, 2)
|
||||
grid.addWidget(self.heightEdit, row, 3)
|
||||
row += 1
|
||||
grid.addWidget(ppt_label, row, 0)
|
||||
grid.addWidget(self.pptEdit, row, 1)
|
||||
grid.addWidget(ppt_dlg_btn, row, 2)
|
||||
grid.addWidget(ppt_btn, row, 3)
|
||||
row += 1
|
||||
grid.addWidget(slide_label, row, 0)
|
||||
grid.addWidget(self.slideEdit, row, 1)
|
||||
grid.addWidget(slide_btn, row, 2)
|
||||
row += 1
|
||||
grid.addWidget(prev, row, 0)
|
||||
grid.addWidget(next, row, 1)
|
||||
row += 1
|
||||
grid.addWidget(blank, row, 0)
|
||||
grid.addWidget(unblank, row, 1)
|
||||
row += 1
|
||||
grid.addWidget(restart, row, 0)
|
||||
grid.addWidget(close, row, 1)
|
||||
row += 1
|
||||
grid.addWidget(stop, row, 0)
|
||||
grid.addWidget(resume, row, 1)
|
||||
ppt_btn.clicked.connect(self.openClick)
|
||||
ppt_dlg_btn.clicked.connect(self.openDialog)
|
||||
slide_btn.clicked.connect(self.gotoClick)
|
||||
prev.clicked.connect(self.prevClick)
|
||||
next.clicked.connect(self.nextClick)
|
||||
blank.clicked.connect(self.blankClick)
|
||||
unblank.clicked.connect(self.unblankClick)
|
||||
restart.clicked.connect(self.restartClick)
|
||||
close.clicked.connect(self.closeClick)
|
||||
stop.clicked.connect(self.stopClick)
|
||||
resume.clicked.connect(self.resumeClick)
|
||||
self.setLayout(grid)
|
||||
self.resize(300, 150)
|
||||
|
||||
def prevClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.PrevStep(self.pptid)
|
||||
self.updateCurrSlide()
|
||||
app.processEvents()
|
||||
|
||||
def nextClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.NextStep(self.pptid)
|
||||
self.updateCurrSlide()
|
||||
app.processEvents()
|
||||
|
||||
def blankClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.Blank(self.pptid)
|
||||
app.processEvents()
|
||||
|
||||
def unblankClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.Unblank(self.pptid)
|
||||
app.processEvents()
|
||||
|
||||
def restartClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.RestartShow(self.pptid)
|
||||
self.updateCurrSlide()
|
||||
app.processEvents()
|
||||
|
||||
def stopClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.Stop(self.pptid)
|
||||
app.processEvents()
|
||||
|
||||
def resumeClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.Resume(self.pptid)
|
||||
app.processEvents()
|
||||
|
||||
def closeClick(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
self.pptdll.ClosePPT(self.pptid)
|
||||
self.pptid = -1
|
||||
app.processEvents()
|
||||
|
||||
def openClick(self):
|
||||
oldid = self.pptid
|
||||
rect = RECT(int(self.xEdit.text()), int(self.yEdit.text()),
|
||||
int(self.widthEdit.text()), int(self.heightEdit.text()))
|
||||
filename = str(self.pptEdit.text().replace('/', '\\'))
|
||||
folder = str(self.folderEdit.text().replace('/', '\\'))
|
||||
print(filename, folder)
|
||||
self.pptid = self.pptdll.OpenPPT(filename, None, rect, folder)
|
||||
print('id: ' + str(self.pptid))
|
||||
if oldid >= 0:
|
||||
self.pptdll.ClosePPT(oldid)
|
||||
slides = self.pptdll.GetSlideCount(self.pptid)
|
||||
print('slidecount: ' + str(slides))
|
||||
self.total.setNum(self.pptdll.GetSlideCount(self.pptid))
|
||||
self.updateCurrSlide()
|
||||
|
||||
def updateCurrSlide(self):
|
||||
if self.pptid < 0:
|
||||
return
|
||||
slide = str(self.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())
|
||||
self.pptdll.GotoSlide(self.pptid, int(self.slideEdit.text()))
|
||||
self.updateCurrSlide()
|
||||
app.processEvents()
|
||||
|
||||
def openDialog(self):
|
||||
self.pptEdit.setText(QtWidgets.QFileDialog.getOpenFileName(self, 'Open file')[0])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pptdll = cdll.LoadLibrary(r'pptviewlib.dll')
|
||||
pptdll.SetDebug(1)
|
||||
print('Begin...')
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
window = PPTViewer()
|
||||
window.pptdll = pptdll
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
@ -1,920 +0,0 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2018 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* 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; version 2 of the License. *
|
||||
* *
|
||||
* 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, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#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")
|
||||
PPTVIEW pptView[MAX_PPTS] = {NULL};
|
||||
HHOOK globalHook = NULL;
|
||||
BOOL debug = FALSE;
|
||||
#pragma data_seg()
|
||||
#pragma comment(linker, "/SECTION:.PPTVIEWLIB,RWS")
|
||||
|
||||
HINSTANCE hInstance = NULL;
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReasonForCall,
|
||||
LPVOID lpReserved)
|
||||
{
|
||||
hInstance = (HINSTANCE)hModule;
|
||||
switch(ulReasonForCall)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DEBUG(L"PROCESS_ATTACH\n");
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
//DEBUG(L"THREAD_ATTACH\n");
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
//DEBUG(L"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(L"PROCESS_DETACH\n");
|
||||
for (int i = 0; i < MAX_PPTS; i++)
|
||||
ClosePPT(i);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DllExport void SetDebug(BOOL onOff)
|
||||
{
|
||||
printf("SetDebug\n");
|
||||
debug = onOff;
|
||||
DEBUG(L"enabled\n");
|
||||
}
|
||||
|
||||
DllExport BOOL CheckInstalled()
|
||||
{
|
||||
wchar_t cmdLine[MAX_PATH * 2];
|
||||
|
||||
DEBUG(L"CheckInstalled\n");
|
||||
BOOL found = GetPPTViewerPath(cmdLine, sizeof(cmdLine));
|
||||
if(found)
|
||||
{
|
||||
DEBUG(L"Exe: %s\n", cmdLine);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// Open the PointPoint, count the slides and take a snapshot of each slide
|
||||
// for use in previews
|
||||
// previewpath is a prefix for the location to put preview images of each slide.
|
||||
// "<n>.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(wchar_t *filename, HWND hParentWnd, RECT rect,
|
||||
wchar_t *previewPath)
|
||||
{
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
wchar_t cmdLine[MAX_PATH * 2];
|
||||
int id;
|
||||
|
||||
DEBUG(L"OpenPPT start: %s; %s\n", filename, previewPath);
|
||||
DEBUG(L"OpenPPT start: %u; %i, %i, %i, %i\n", hParentWnd, rect.top,
|
||||
rect.left, rect.bottom, rect.right);
|
||||
if (GetPPTViewerPath(cmdLine, sizeof(cmdLine)) == FALSE)
|
||||
{
|
||||
DEBUG(L"OpenPPT: GetPPTViewerPath failed\n");
|
||||
return -1;
|
||||
}
|
||||
id = -1;
|
||||
for (int i = 0; i < MAX_PPTS; i++)
|
||||
{
|
||||
if (pptView[i].state == PPT_CLOSED)
|
||||
{
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id < 0)
|
||||
{
|
||||
DEBUG(L"OpenPPT: Too many PPTs\n");
|
||||
return -1;
|
||||
}
|
||||
memset(&pptView[id], 0, sizeof(PPTVIEW));
|
||||
wcscpy_s(pptView[id].filename, MAX_PATH, filename);
|
||||
wcscpy_s(pptView[id].previewPath, MAX_PATH, previewPath);
|
||||
pptView[id].state = PPT_CLOSED;
|
||||
pptView[id].slideCount = 0;
|
||||
pptView[id].currentSlide = 0;
|
||||
pptView[id].firstSlideSteps = 0;
|
||||
pptView[id].lastSlideSteps = 0;
|
||||
pptView[id].guess = 0;
|
||||
pptView[id].hParentWnd = hParentWnd;
|
||||
pptView[id].hWnd = NULL;
|
||||
pptView[id].hWnd2 = NULL;
|
||||
for (int i = 0; i < MAX_SLIDES; i++)
|
||||
{
|
||||
pptView[id].slideNos[i] = 0;
|
||||
}
|
||||
if (hParentWnd != NULL && rect.top == 0 && rect.bottom == 0
|
||||
&& rect.left == 0 && rect.right == 0)
|
||||
{
|
||||
LPRECT windowRect = NULL;
|
||||
GetWindowRect(hParentWnd, windowRect);
|
||||
pptView[id].rect.top = 0;
|
||||
pptView[id].rect.left = 0;
|
||||
pptView[id].rect.bottom = windowRect->bottom - windowRect->top;
|
||||
pptView[id].rect.right = windowRect->right - windowRect->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
pptView[id].rect.top = rect.top;
|
||||
pptView[id].rect.left = rect.left;
|
||||
pptView[id].rect.bottom = rect.bottom;
|
||||
pptView[id].rect.right = rect.right;
|
||||
}
|
||||
wcscat_s(cmdLine, MAX_PATH * 2, L" /F /S \"");
|
||||
wcscat_s(cmdLine, MAX_PATH * 2, filename);
|
||||
wcscat_s(cmdLine, MAX_PATH * 2, L"\"");
|
||||
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(L"OpenPPT: SetWindowsHookEx failed\n");
|
||||
ClosePPT(id);
|
||||
return -1;
|
||||
}
|
||||
pptView[id].state = PPT_STARTED;
|
||||
Sleep(10);
|
||||
if (!CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
|
||||
{
|
||||
DEBUG(L"OpenPPT: CreateProcess failed: %s\n", cmdLine);
|
||||
ClosePPT(id);
|
||||
return -1;
|
||||
}
|
||||
pptView[id].dwProcessId = pi.dwProcessId;
|
||||
pptView[id].dwThreadId = pi.dwThreadId;
|
||||
pptView[id].hThread = pi.hThread;
|
||||
pptView[id].hProcess = pi.hProcess;
|
||||
while (pptView[id].state == PPT_STARTED)
|
||||
Sleep(10);
|
||||
if (gotInfo)
|
||||
{
|
||||
DEBUG(L"OpenPPT: Info loaded, no refresh\n");
|
||||
pptView[id].state = PPT_LOADED;
|
||||
Resume(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG(L"OpenPPT: Get info\n");
|
||||
pptView[id].steps = 0;
|
||||
int steps = 0;
|
||||
while (pptView[id].state == PPT_OPENED)
|
||||
{
|
||||
if (steps <= pptView[id].steps)
|
||||
{
|
||||
Sleep(100);
|
||||
DEBUG(L"OpenPPT: Step %d/%d\n", steps, pptView[id].steps);
|
||||
steps++;
|
||||
NextStep(id);
|
||||
}
|
||||
Sleep(10);
|
||||
}
|
||||
DEBUG(L"OpenPPT: Slides %d, Steps %d, first slide steps %d\n",
|
||||
pptView[id].slideCount, pptView[id].steps,
|
||||
pptView[id].firstSlideSteps);
|
||||
for(int i = 1; i <= pptView[id].slideCount; i++)
|
||||
{
|
||||
DEBUG(L"OpenPPT: Slide %d = %d\n", i, pptView[id].slideNos[i]);
|
||||
}
|
||||
SavePPTInfo(id);
|
||||
if (pptView[id].state == PPT_CLOSING
|
||||
|| pptView[id].slideCount <= 0)
|
||||
{
|
||||
ClosePPT(id);
|
||||
id=-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
RestartShow(id);
|
||||
}
|
||||
}
|
||||
if (id >= 0)
|
||||
{
|
||||
if (pptView[id].msgHook != NULL)
|
||||
{
|
||||
UnhookWindowsHookEx(pptView[id].msgHook);
|
||||
}
|
||||
pptView[id].msgHook = NULL;
|
||||
}
|
||||
DEBUG(L"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;
|
||||
wchar_t info[MAX_PATH];
|
||||
FILE* pFile;
|
||||
wchar_t buf[100];
|
||||
|
||||
DEBUG(L"GetPPTInfo: start\n");
|
||||
if (_wstat(pptView[id].filename, &fileStats) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
swprintf_s(info, MAX_PATH, L"%sinfo.txt", pptView[id].previewPath);
|
||||
int err = _wfopen_s(&pFile, info, L"r");
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUG(L"GetPPTInfo: file open failed - %d\n", err);
|
||||
return FALSE;
|
||||
}
|
||||
fgetws(buf, 100, pFile); // version == 1
|
||||
fgetws(buf, 100, pFile);
|
||||
if (fileStats.st_mtime != _wtoi(buf))
|
||||
{
|
||||
DEBUG(L"GetPPTInfo: date changed\n");
|
||||
fclose (pFile);
|
||||
return FALSE;
|
||||
}
|
||||
fgetws(buf, 100, pFile);
|
||||
if (fileStats.st_size != _wtoi(buf))
|
||||
{
|
||||
DEBUG(L"GetPPTInfo: size changed\n");
|
||||
fclose (pFile);
|
||||
return FALSE;
|
||||
}
|
||||
fgetws(buf, 100, pFile); // slidecount
|
||||
int slideCount = _wtoi(buf);
|
||||
fgetws(buf, 100, pFile); // first slide steps
|
||||
int firstSlideSteps = _wtoi(buf);
|
||||
// check all the preview images still exist
|
||||
for (int i = 1; i <= slideCount; i++)
|
||||
{
|
||||
swprintf_s(info, MAX_PATH, L"%s%i.bmp", pptView[id].previewPath, i);
|
||||
if (GetFileAttributes(info) == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
DEBUG(L"GetPPTInfo: bmp not found\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
fclose(pFile);
|
||||
pptView[id].slideCount = slideCount;
|
||||
pptView[id].firstSlideSteps = firstSlideSteps;
|
||||
DEBUG(L"GetPPTInfo: exit ok\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL SavePPTInfo(int id)
|
||||
{
|
||||
struct _stat fileStats;
|
||||
wchar_t info[MAX_PATH];
|
||||
FILE* pFile;
|
||||
|
||||
DEBUG(L"SavePPTInfo: start\n");
|
||||
if (_wstat(pptView[id].filename, &fileStats) != 0)
|
||||
{
|
||||
DEBUG(L"SavePPTInfo: stat of %s failed\n", pptView[id].filename);
|
||||
return FALSE;
|
||||
}
|
||||
swprintf_s(info, MAX_PATH, L"%sinfo.txt", pptView[id].previewPath);
|
||||
int err = _wfopen_s(&pFile, info, L"w");
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUG(L"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", pptView[id].slideCount);
|
||||
fprintf(pFile, "%u\n", pptView[id].firstSlideSteps);
|
||||
fclose(pFile);
|
||||
DEBUG(L"SavePPTInfo: exit ok\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Get the path of the PowerPoint viewer from the registry
|
||||
BOOL GetPPTViewerPath(wchar_t *pptViewerPath, int stringSize)
|
||||
{
|
||||
wchar_t cwd[MAX_PATH];
|
||||
|
||||
DEBUG(L"GetPPTViewerPath: start\n");
|
||||
if(GetPPTViewerPathFromReg(pptViewerPath, stringSize))
|
||||
{
|
||||
if(_waccess(pptViewerPath, 0) != -1)
|
||||
{
|
||||
DEBUG(L"GetPPTViewerPath: exit registry\n");
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
// This is where it gets ugly. PPT2007 it seems no longer stores its
|
||||
// location in the registry. So we have to use the defaults which will
|
||||
// upset those who like to put things somewhere else
|
||||
|
||||
// Viewer 2007 in 64bit Windows:
|
||||
if(_waccess(L"C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE",
|
||||
0) != -1)
|
||||
{
|
||||
wcscpy_s(
|
||||
L"C:\\Program Files (x86)\\Microsoft Office\\Office12\\PPTVIEW.EXE",
|
||||
stringSize, pptViewerPath);
|
||||
DEBUG(L"GetPPTViewerPath: exit 64bit 2007\n");
|
||||
return TRUE;
|
||||
}
|
||||
// Viewer 2007 in 32bit Windows:
|
||||
if(_waccess(L"C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE", 0)
|
||||
!= -1)
|
||||
{
|
||||
wcscpy_s(L"C:\\Program Files\\Microsoft Office\\Office12\\PPTVIEW.EXE",
|
||||
stringSize, pptViewerPath);
|
||||
DEBUG(L"GetPPTViewerPath: exit 32bit 2007\n");
|
||||
return TRUE;
|
||||
}
|
||||
// Give them the opportunity to place it in the same folder as the app
|
||||
_wgetcwd(cwd, MAX_PATH);
|
||||
wcscat_s(cwd, MAX_PATH, L"\\PPTVIEW.EXE");
|
||||
if(_waccess(cwd, 0) != -1)
|
||||
{
|
||||
wcscpy_s(pptViewerPath, stringSize, cwd);
|
||||
DEBUG(L"GetPPTViewerPath: exit local\n");
|
||||
return TRUE;
|
||||
}
|
||||
DEBUG(L"GetPPTViewerPath: exit fail\n");
|
||||
return FALSE;
|
||||
}
|
||||
BOOL GetPPTViewerPathFromReg(wchar_t *pptViewerPath, int stringSize)
|
||||
{
|
||||
HKEY hKey;
|
||||
DWORD dwType, dwSize;
|
||||
LRESULT lResult;
|
||||
|
||||
// The following registry settings are for, respectively, (I think)
|
||||
// PPT Viewer 2007 (older versions. Latest not in registry) & PPT Viewer 2010
|
||||
// PPT Viewer 2003 (recent versions)
|
||||
// PPT Viewer 2003 (older versions)
|
||||
// PPT Viewer 97
|
||||
if ((RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
||||
L"PowerPointViewer.Show.12\\shell\\Show\\command", 0, KEY_READ, &hKey)
|
||||
!= ERROR_SUCCESS)
|
||||
&& (RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
||||
L"PowerPointViewer.Show.11\\shell\\Show\\command", 0, KEY_READ, &hKey)
|
||||
!= ERROR_SUCCESS)
|
||||
&& (RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
||||
L"Applications\\PPTVIEW.EXE\\shell\\open\\command", 0, KEY_READ, &hKey)
|
||||
!= ERROR_SUCCESS)
|
||||
&& (RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
||||
L"Applications\\PPTVIEW.EXE\\shell\\Show\\command", 0, KEY_READ, &hKey)
|
||||
!= ERROR_SUCCESS))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
dwType = REG_SZ;
|
||||
dwSize = (DWORD)stringSize;
|
||||
lResult = RegQueryValueEx(hKey, NULL, NULL, &dwType, (LPBYTE)pptViewerPath,
|
||||
&dwSize);
|
||||
RegCloseKey(hKey);
|
||||
if (lResult != ERROR_SUCCESS)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
// remove "%1" from end of key value
|
||||
pptViewerPath[wcslen(pptViewerPath) - 4] = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Unhook the Windows hook
|
||||
void Unhook(int id)
|
||||
{
|
||||
DEBUG(L"Unhook: start %d\n", id);
|
||||
if (pptView[id].hook != NULL)
|
||||
{
|
||||
UnhookWindowsHookEx(pptView[id].hook);
|
||||
}
|
||||
if (pptView[id].msgHook != NULL)
|
||||
{
|
||||
UnhookWindowsHookEx(pptView[id].msgHook);
|
||||
}
|
||||
pptView[id].hook = NULL;
|
||||
pptView[id].msgHook = NULL;
|
||||
DEBUG(L"Unhook: exit ok\n");
|
||||
}
|
||||
|
||||
// Close the PowerPoint viewer, release resources
|
||||
DllExport void ClosePPT(int id)
|
||||
{
|
||||
DEBUG(L"ClosePPT: start%d\n", id);
|
||||
pptView[id].state = PPT_CLOSED;
|
||||
Unhook(id);
|
||||
if (pptView[id].hWnd == 0)
|
||||
{
|
||||
TerminateThread(pptView[id].hThread, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PostMessage(pptView[id].hWnd, WM_CLOSE, 0, 0);
|
||||
}
|
||||
CloseHandle(pptView[id].hThread);
|
||||
CloseHandle(pptView[id].hProcess);
|
||||
memset(&pptView[id], 0, sizeof(PPTVIEW));
|
||||
DEBUG(L"ClosePPT: exit ok\n");
|
||||
return;
|
||||
}
|
||||
// Moves the show back onto the display
|
||||
DllExport void Resume(int id)
|
||||
{
|
||||
DEBUG(L"Resume: %d\n", id);
|
||||
MoveWindow(pptView[id].hWnd, pptView[id].rect.left,
|
||||
pptView[id].rect.top,
|
||||
pptView[id].rect.right - pptView[id].rect.left,
|
||||
pptView[id].rect.bottom - pptView[id].rect.top, TRUE);
|
||||
Unblank(id);
|
||||
}
|
||||
// Moves the show off the screen so it can't be seen
|
||||
DllExport void Stop(int id)
|
||||
{
|
||||
DEBUG(L"Stop:%d\n", id);
|
||||
MoveWindow(pptView[id].hWnd, -32000, -32000,
|
||||
pptView[id].rect.right - pptView[id].rect.left,
|
||||
pptView[id].rect.bottom - pptView[id].rect.top, TRUE);
|
||||
}
|
||||
|
||||
// Return the total number of slides
|
||||
DllExport int GetSlideCount(int id)
|
||||
{
|
||||
DEBUG(L"GetSlideCount:%d\n", id);
|
||||
if (pptView[id].state == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pptView[id].slideCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the number of the slide currently viewing
|
||||
DllExport int GetCurrentSlide(int id)
|
||||
{
|
||||
DEBUG(L"GetCurrentSlide:%d\n", id);
|
||||
if (pptView[id].state == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pptView[id].currentSlide;
|
||||
}
|
||||
}
|
||||
|
||||
// Take a step forwards through the show
|
||||
DllExport void NextStep(int id)
|
||||
{
|
||||
DEBUG(L"NextStep:%d (%d)\n", id, pptView[id].currentSlide);
|
||||
if (pptView[id].currentSlide > pptView[id].slideCount) return;
|
||||
if (pptView[id].currentSlide < pptView[id].slideCount)
|
||||
{
|
||||
pptView[id].guess = pptView[id].currentSlide + 1;
|
||||
}
|
||||
PostMessage(pptView[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA),
|
||||
0);
|
||||
}
|
||||
|
||||
// Take a step backwards through the show
|
||||
DllExport void PrevStep(int id)
|
||||
{
|
||||
DEBUG(L"PrevStep:%d (%d)\n", id, pptView[id].currentSlide);
|
||||
if (pptView[id].currentSlide > 1)
|
||||
{
|
||||
pptView[id].guess = pptView[id].currentSlide - 1;
|
||||
}
|
||||
PostMessage(pptView[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(L"Blank:%d\n", id);
|
||||
HWND h1 = GetForegroundWindow();
|
||||
HWND h2 = GetFocus();
|
||||
SetForegroundWindow(pptView[id].hWnd);
|
||||
SetFocus(pptView[id].hWnd);
|
||||
// slight pause, otherwise event triggering this call may grab focus back!
|
||||
Sleep(50);
|
||||
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);
|
||||
}
|
||||
// Unblank the show
|
||||
DllExport void Unblank(int id)
|
||||
{
|
||||
DEBUG(L"Unblank:%d\n", id);
|
||||
// Pressing any key resumes.
|
||||
// For some reason SendMessage works for unblanking, but not blanking.
|
||||
SendMessage(pptView[id].hWnd2, WM_CHAR, 'A', 0);
|
||||
}
|
||||
|
||||
// Go directly to a slide
|
||||
DllExport void GotoSlide(int id, int slideNo)
|
||||
{
|
||||
DEBUG(L"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;
|
||||
pptView[id].guess = slideNo;
|
||||
_itoa_s(slideNo, ch, 10, 10);
|
||||
HWND h1 = GetForegroundWindow();
|
||||
HWND h2 = GetFocus();
|
||||
SetForegroundWindow(pptView[id].hWnd);
|
||||
SetFocus(pptView[id].hWnd);
|
||||
// slight pause, otherwise event triggering this call may grab focus back!
|
||||
Sleep(50);
|
||||
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);
|
||||
}
|
||||
|
||||
// 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(L"RestartShow:%d\n", id);
|
||||
Stop(id);
|
||||
GotoSlide(id, pptView[id].slideCount);
|
||||
for (int i=0; i <= pptView[id].steps - pptView[id].lastSlideSteps; i++)
|
||||
{
|
||||
PrevStep(id);
|
||||
Sleep(10);
|
||||
}
|
||||
int i = 0;
|
||||
while ((pptView[id].currentSlide > 1) && (i++ < 30000))
|
||||
{
|
||||
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)
|
||||
{
|
||||
wchar_t csClassName[32];
|
||||
HWND hCurrWnd = (HWND)wParam;
|
||||
DWORD retProcId = NULL;
|
||||
GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
|
||||
if ((wcscmp(csClassName, L"paneClassDC") == 0)
|
||||
||(wcscmp(csClassName, L"screenClass") == 0))
|
||||
{
|
||||
int id = -1;
|
||||
DWORD windowThread = GetWindowThreadProcessId(hCurrWnd, NULL);
|
||||
for (int i=0; i < MAX_PPTS; i++)
|
||||
{
|
||||
if (pptView[i].dwThreadId == windowThread)
|
||||
{
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id >= 0)
|
||||
{
|
||||
if (wcscmp(csClassName, L"paneClassDC") == 0)
|
||||
{
|
||||
pptView[id].hWnd2 = hCurrWnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
pptView[id].hWnd = hCurrWnd;
|
||||
CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
|
||||
if (pptView[id].hParentWnd != NULL)
|
||||
{
|
||||
cw->lpcs->hwndParent = pptView[id].hParentWnd;
|
||||
}
|
||||
cw->lpcs->cy = pptView[id].rect.bottom
|
||||
- pptView[id].rect.top;
|
||||
cw->lpcs->cx = pptView[id].rect.right
|
||||
- pptView[id].rect.left;
|
||||
cw->lpcs->y = -32000;
|
||||
cw->lpcs->x = -32000;
|
||||
}
|
||||
if ((pptView[id].hWnd != NULL) && (pptView[id].hWnd2 != NULL))
|
||||
{
|
||||
UnhookWindowsHookEx(globalHook);
|
||||
globalHook = NULL;
|
||||
pptView[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,
|
||||
CwpProc, hInstance, pptView[id].dwThreadId);
|
||||
pptView[id].msgHook = SetWindowsHookEx(WH_GETMESSAGE,
|
||||
GetMsgProc, hInstance, pptView[id].dwThreadId);
|
||||
Sleep(10);
|
||||
pptView[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 < MAX_PPTS; i++)
|
||||
{
|
||||
if (pptView[i].dwThreadId == windowThread)
|
||||
{
|
||||
id = i;
|
||||
hook = pptView[id].msgHook;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id >= 0 && nCode == HC_ACTION && wParam == PM_REMOVE
|
||||
&& pMSG->message == WM_MOUSEWHEEL)
|
||||
{
|
||||
if (pptView[id].state != PPT_LOADED)
|
||||
{
|
||||
if (pptView[id].currentSlide == 1)
|
||||
{
|
||||
pptView[id].firstSlideSteps++;
|
||||
}
|
||||
pptView[id].steps++;
|
||||
pptView[id].lastSlideSteps++;
|
||||
}
|
||||
}
|
||||
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;
|
||||
wchar_t filename[MAX_PATH];
|
||||
|
||||
DWORD windowThread = GetWindowThreadProcessId(cwp->hwnd, NULL);
|
||||
int id = -1;
|
||||
for (int i = 0; i < MAX_PPTS; i++)
|
||||
{
|
||||
if (pptView[i].dwThreadId == windowThread)
|
||||
{
|
||||
id = i;
|
||||
hook = pptView[id].hook;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((id >= 0) && (nCode == HC_ACTION))
|
||||
{
|
||||
if (cwp->message == WM_USER + 22)
|
||||
{
|
||||
if (pptView[id].state != PPT_LOADED)
|
||||
{
|
||||
if ((pptView[id].currentSlide > 0)
|
||||
&& (pptView[id].previewPath != NULL
|
||||
&& wcslen(pptView[id].previewPath) > 0))
|
||||
{
|
||||
swprintf_s(filename, MAX_PATH, L"%s%i.bmp",
|
||||
pptView[id].previewPath,
|
||||
pptView[id].currentSlide);
|
||||
CaptureAndSaveWindow(cwp->hwnd, filename);
|
||||
}
|
||||
if (((cwp->wParam == 0)
|
||||
|| (pptView[id].slideNos[1] == cwp->wParam))
|
||||
&& (pptView[id].currentSlide > 0))
|
||||
{
|
||||
pptView[id].state = PPT_LOADED;
|
||||
pptView[id].currentSlide = pptView[id].slideCount + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cwp->wParam > 0)
|
||||
{
|
||||
pptView[id].currentSlide = pptView[id].currentSlide + 1;
|
||||
pptView[id].slideNos[pptView[id].currentSlide]
|
||||
= cwp->wParam;
|
||||
pptView[id].slideCount = pptView[id].currentSlide;
|
||||
pptView[id].lastSlideSteps = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cwp->wParam > 0)
|
||||
{
|
||||
if(pptView[id].guess > 0
|
||||
&& pptView[id].slideNos[pptView[id].guess] == 0)
|
||||
{
|
||||
pptView[id].currentSlide = 0;
|
||||
}
|
||||
for(int i = 1; i <= pptView[id].slideCount; i++)
|
||||
{
|
||||
if(pptView[id].slideNos[i] == cwp->wParam)
|
||||
{
|
||||
pptView[id].currentSlide = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(pptView[id].currentSlide == 0)
|
||||
{
|
||||
pptView[id].slideNos[pptView[id].guess] = cwp->wParam;
|
||||
pptView[id].currentSlide = pptView[id].guess;
|
||||
}
|
||||
pptView[id].guess = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((pptView[id].state != PPT_CLOSED)
|
||||
|
||||
&&(cwp->message == WM_CLOSE || cwp->message == WM_QUIT))
|
||||
{
|
||||
pptView[id].state = PPT_CLOSING;
|
||||
}
|
||||
}
|
||||
return CallNextHookEx(hook, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
VOID CaptureAndSaveWindow(HWND hWnd, wchar_t* 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 = _wfopen_s(&pFile, filename, L"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(L"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;
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2018 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* 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; version 2 of the License. *
|
||||
* *
|
||||
* 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, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
|
||||
#define DllExport extern "C" __declspec( dllexport )
|
||||
|
||||
#define DEBUG(...) if (debug) wprintf(__VA_ARGS__)
|
||||
|
||||
enum PPTVIEWSTATE {PPT_CLOSED, PPT_STARTED, PPT_OPENED, PPT_LOADED,
|
||||
PPT_CLOSING};
|
||||
|
||||
DllExport int OpenPPT(wchar_t *filename, HWND hParentWnd, RECT rect,
|
||||
wchar_t *previewPath);
|
||||
DllExport BOOL CheckInstalled();
|
||||
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 slide_no);
|
||||
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(wchar_t *pptViewerPath, int stringSize);
|
||||
BOOL GetPPTViewerPathFromReg(wchar_t *pptViewerPath, int stringSize);
|
||||
HBITMAP CaptureWindow(HWND hWnd);
|
||||
VOID SaveBitmap(wchar_t* filename, HBITMAP hBmp) ;
|
||||
VOID CaptureAndSaveWindow(HWND hWnd, wchar_t* filename);
|
||||
BOOL GetPPTInfo(int id);
|
||||
BOOL SavePPTInfo(int id);
|
||||
void Unhook(int id);
|
||||
|
||||
#define MAX_PPTS 16
|
||||
#define MAX_SLIDES 256
|
||||
|
||||
struct PPTVIEW
|
||||
{
|
||||
HHOOK hook;
|
||||
HHOOK msgHook;
|
||||
HWND hWnd;
|
||||
HWND hWnd2;
|
||||
HWND hParentWnd;
|
||||
HANDLE hProcess;
|
||||
HANDLE hThread;
|
||||
DWORD dwProcessId;
|
||||
DWORD dwThreadId;
|
||||
RECT rect;
|
||||
int slideCount;
|
||||
int currentSlide;
|
||||
int firstSlideSteps;
|
||||
int lastSlideSteps;
|
||||
int steps;
|
||||
int guess;
|
||||
wchar_t filename[MAX_PATH];
|
||||
wchar_t previewPath[MAX_PATH];
|
||||
int slideNos[MAX_SLIDES];
|
||||
PPTVIEWSTATE state;
|
||||
};
|
@ -1,202 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="pptviewlib"
|
||||
ProjectGUID="{04CC20D1-DC5A-4189-8181-4011E3C21DCF}"
|
||||
RootNamespace="pptviewlib"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
ModuleDefinitionFile=""
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;PPTVIEWLIB_EXPORTS"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\pptviewlib.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\README.TXT"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\pptviewlib.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
Binary file not shown.
Binary file not shown.
@ -44,7 +44,6 @@ __default_settings__ = {'presentations/override app': QtCore.Qt.Unchecked,
|
||||
'presentations/pdf_program': None,
|
||||
'presentations/Impress': QtCore.Qt.Checked,
|
||||
'presentations/Powerpoint': QtCore.Qt.Checked,
|
||||
'presentations/Powerpoint Viewer': QtCore.Qt.Checked,
|
||||
'presentations/Pdf': QtCore.Qt.Checked,
|
||||
'presentations/presentations files': [],
|
||||
'presentations/thumbnail_scheme': '',
|
||||
@ -57,7 +56,7 @@ __default_settings__ = {'presentations/override app': QtCore.Qt.Unchecked,
|
||||
class PresentationPlugin(Plugin):
|
||||
"""
|
||||
This plugin allowed a Presentation to be opened, controlled and displayed on the output display. The plugin controls
|
||||
third party applications such as OpenOffice.org Impress, Microsoft PowerPoint and the PowerPoint viewer.
|
||||
third party applications such as OpenOffice.org Impress, and Microsoft PowerPoint.
|
||||
"""
|
||||
log = logging.getLogger('PresentationPlugin')
|
||||
|
||||
|
@ -1,226 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2018 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# 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; version 2 of the License. #
|
||||
# #
|
||||
# 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, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
"""
|
||||
This module contains tests for the pptviewcontroller module of the Presentations plugin.
|
||||
"""
|
||||
import shutil
|
||||
from tempfile import mkdtemp
|
||||
from unittest import TestCase, skipIf
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from openlp.core.common import is_win
|
||||
from openlp.core.common.path import Path
|
||||
from openlp.plugins.presentations.lib.pptviewcontroller import PptviewDocument, PptviewController
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
from tests.utils.constants import RESOURCE_PATH
|
||||
|
||||
|
||||
class TestPptviewController(TestCase, TestMixin):
|
||||
"""
|
||||
Test the PptviewController Class
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up the patches and mocks need for all tests.
|
||||
"""
|
||||
self.setup_application()
|
||||
self.build_settings()
|
||||
self.mock_plugin = MagicMock()
|
||||
self.temp_folder = mkdtemp()
|
||||
self.mock_plugin.settings_section = self.temp_folder
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Stop the patches
|
||||
"""
|
||||
self.destroy_settings()
|
||||
shutil.rmtree(self.temp_folder)
|
||||
|
||||
def test_constructor(self):
|
||||
"""
|
||||
Test the Constructor from the PptViewController
|
||||
"""
|
||||
# GIVEN: No presentation controller
|
||||
controller = None
|
||||
|
||||
# WHEN: The presentation controller object is created
|
||||
controller = PptviewController(plugin=self.mock_plugin)
|
||||
|
||||
# THEN: The name of the presentation controller should be correct
|
||||
assert 'Powerpoint Viewer' == controller.name, 'The name of the presentation controller should be correct'
|
||||
|
||||
def test_check_available(self):
|
||||
"""
|
||||
Test check_available / check_installed
|
||||
"""
|
||||
# GIVEN: A mocked dll loader and a controller
|
||||
with patch('ctypes.cdll.LoadLibrary') as mocked_load_library:
|
||||
mocked_process = MagicMock()
|
||||
mocked_process.CheckInstalled.return_value = True
|
||||
mocked_load_library.return_value = mocked_process
|
||||
controller = PptviewController(plugin=self.mock_plugin)
|
||||
|
||||
# WHEN: check_available is called
|
||||
available = controller.check_available()
|
||||
|
||||
# THEN: On windows it should return True, on other platforms False
|
||||
if is_win():
|
||||
assert available is True, 'check_available should return True on windows.'
|
||||
else:
|
||||
assert available is False, 'check_available should return False when not on windows.'
|
||||
|
||||
|
||||
class TestPptviewDocument(TestCase):
|
||||
"""
|
||||
Test the PptviewDocument Class
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Set up the patches and mocks need for all tests.
|
||||
"""
|
||||
self.pptview_document_create_thumbnails_patcher = patch(
|
||||
'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.create_thumbnails')
|
||||
self.pptview_document_stop_presentation_patcher = patch(
|
||||
'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.stop_presentation')
|
||||
self.presentation_document_get_temp_folder_patcher = patch(
|
||||
'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument.get_temp_folder')
|
||||
self.presentation_document_setup_patcher = patch(
|
||||
'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument._setup')
|
||||
self.screen_list_patcher = patch('openlp.plugins.presentations.lib.pptviewcontroller.ScreenList')
|
||||
self.rect_patcher = MagicMock()
|
||||
self.mock_pptview_document_create_thumbnails = self.pptview_document_create_thumbnails_patcher.start()
|
||||
self.mock_pptview_document_stop_presentation = self.pptview_document_stop_presentation_patcher.start()
|
||||
self.mock_presentation_document_get_temp_folder = self.presentation_document_get_temp_folder_patcher.start()
|
||||
self.mock_presentation_document_setup = self.presentation_document_setup_patcher.start()
|
||||
self.mock_rect = self.rect_patcher.start()
|
||||
self.mock_screen_list = self.screen_list_patcher.start()
|
||||
self.mock_controller = MagicMock()
|
||||
self.mock_presentation = MagicMock()
|
||||
self.temp_folder = mkdtemp()
|
||||
self.mock_presentation_document_get_temp_folder.return_value = self.temp_folder
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Stop the patches
|
||||
"""
|
||||
self.pptview_document_create_thumbnails_patcher.stop()
|
||||
self.pptview_document_stop_presentation_patcher.stop()
|
||||
self.presentation_document_get_temp_folder_patcher.stop()
|
||||
self.presentation_document_setup_patcher.stop()
|
||||
self.rect_patcher.stop()
|
||||
self.screen_list_patcher.stop()
|
||||
shutil.rmtree(self.temp_folder)
|
||||
|
||||
@skipIf(not is_win(), 'Not Windows')
|
||||
def test_load_presentation_succesful(self):
|
||||
"""
|
||||
Test the PptviewDocument.load_presentation() method when the PPT is successfully opened
|
||||
"""
|
||||
# GIVEN: A reset mocked_os
|
||||
self.mock_controller.process.OpenPPT.return_value = 0
|
||||
instance = PptviewDocument(self.mock_controller, self.mock_presentation)
|
||||
instance.file_path = 'test\path.ppt'
|
||||
|
||||
# WHEN: The temporary directory exists and OpenPPT returns successfully (not -1)
|
||||
result = instance.load_presentation()
|
||||
|
||||
# THEN: PptviewDocument.load_presentation should return True
|
||||
assert result is True
|
||||
|
||||
@skipIf(not is_win(), 'Not Windows')
|
||||
def test_load_presentation_un_succesful(self):
|
||||
"""
|
||||
Test the PptviewDocument.load_presentation() method when the temporary directory does not exist and the PPT is
|
||||
not successfully opened
|
||||
"""
|
||||
# GIVEN: A reset mock_os_isdir
|
||||
self.mock_controller.process.OpenPPT.return_value = -1
|
||||
instance = PptviewDocument(self.mock_controller, self.mock_presentation)
|
||||
instance.file_path = 'test\path.ppt'
|
||||
|
||||
# WHEN: The temporary directory does not exist and OpenPPT returns unsuccessfully (-1)
|
||||
with patch.object(instance, 'get_temp_folder') as mocked_get_folder:
|
||||
mocked_get_folder.return_value = MagicMock(spec=Path)
|
||||
result = instance.load_presentation()
|
||||
|
||||
# THEN: The temp folder should be created and PptviewDocument.load_presentation should return False
|
||||
assert result is False
|
||||
|
||||
def test_create_titles_and_notes(self):
|
||||
"""
|
||||
Test PowerpointController.create_titles_and_notes
|
||||
"""
|
||||
# GIVEN: mocked PresentationController.save_titles_and_notes and a pptx file
|
||||
doc = PptviewDocument(self.mock_controller, self.mock_presentation)
|
||||
doc.file_path = RESOURCE_PATH / 'presentations' / 'test.pptx'
|
||||
doc.save_titles_and_notes = MagicMock()
|
||||
|
||||
# WHEN reading the titles and notes
|
||||
doc.create_titles_and_notes()
|
||||
|
||||
# THEN save_titles_and_notes should have been called once with empty arrays
|
||||
doc.save_titles_and_notes.assert_called_once_with(['Test 1\n', '\n', 'Test 2\n', 'Test 4\n', 'Test 3\n'],
|
||||
['Notes for slide 1', 'Inserted', 'Notes for slide 2',
|
||||
'Notes \nfor slide 4', 'Notes for slide 3'])
|
||||
|
||||
def test_create_titles_and_notes_nonexistent_file(self):
|
||||
"""
|
||||
Test PowerpointController.create_titles_and_notes with nonexistent file
|
||||
"""
|
||||
# GIVEN: mocked PresentationController.save_titles_and_notes and an nonexistent file
|
||||
with patch('builtins.open') as mocked_open, \
|
||||
patch.object(Path, 'exists') as mocked_path_exists, \
|
||||
patch('openlp.plugins.presentations.lib.presentationcontroller.create_paths') as \
|
||||
mocked_dir_exists:
|
||||
mocked_path_exists.return_value = False
|
||||
mocked_dir_exists.return_value = False
|
||||
doc = PptviewDocument(self.mock_controller, self.mock_presentation)
|
||||
doc.file_path = Path('Idontexist.pptx')
|
||||
doc.save_titles_and_notes = MagicMock()
|
||||
|
||||
# WHEN: Reading the titles and notes
|
||||
doc.create_titles_and_notes()
|
||||
|
||||
# THEN: File existens should have been checked, and not have been opened.
|
||||
doc.save_titles_and_notes.assert_called_once_with(None, None)
|
||||
mocked_path_exists.assert_called_with()
|
||||
assert mocked_open.call_count == 0, 'There should be no calls to open a file.'
|
||||
|
||||
def test_create_titles_and_notes_invalid_file(self):
|
||||
"""
|
||||
Test PowerpointController.create_titles_and_notes with invalid file
|
||||
"""
|
||||
# GIVEN: mocked PresentationController.save_titles_and_notes and an invalid file
|
||||
with patch('builtins.open') as mocked_open, \
|
||||
patch('openlp.plugins.presentations.lib.pptviewcontroller.zipfile.is_zipfile') as mocked_is_zf:
|
||||
mocked_is_zf.return_value = False
|
||||
mocked_open.filesize = 10
|
||||
doc = PptviewDocument(self.mock_controller, self.mock_presentation)
|
||||
doc.file_path = RESOURCE_PATH / 'presentations' / 'test.ppt'
|
||||
doc.save_titles_and_notes = MagicMock()
|
||||
|
||||
# WHEN: reading the titles and notes
|
||||
doc.create_titles_and_notes()
|
||||
|
||||
# THEN:
|
||||
doc.save_titles_and_notes.assert_called_once_with(None, None)
|
||||
assert mocked_is_zf.call_count == 1, 'is_zipfile should have been called once'
|
Loading…
Reference in New Issue
Block a user