panda3dw.exe, and file-associations for windows

This commit is contained in:
David Rose 2009-10-05 22:35:50 +00:00
parent 6bd5ec1c5a
commit 216211343f
5 changed files with 365 additions and 29 deletions

View File

@ -0,0 +1,190 @@
/*
_____________________________________________________________________________
File Association
_____________________________________________________________________________
Based on code taken from http://nsis.sourceforge.net/File_Association
Usage in script:
1. !include "FileAssociation.nsh"
2. [Section|Function]
${FileAssociationFunction} "Param1" "Param2" "..." $var
[SectionEnd|FunctionEnd]
FileAssociationFunction=[RegisterExtension|UnRegisterExtension]
_____________________________________________________________________________
${RegisterExtension} "[executable]" "[extension]" "[description]"
"[executable]" ; executable which opens the file format
;
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
${UnRegisterExtension} "[extension]" "[description]"
"[extension]" ; extension, which represents the file format to open
;
"[description]" ; description for the extension. This will be display in Windows Explorer.
;
_____________________________________________________________________________
Macros
_____________________________________________________________________________
Change log window verbosity (default: 3=no script)
Example:
!include "FileAssociation.nsh"
!insertmacro RegisterExtension
${FileAssociation_VERBOSE} 4 # all verbosity
!insertmacro UnRegisterExtension
${FileAssociation_VERBOSE} 3 # no script
*/
!ifndef FileAssociation_INCLUDED
!define FileAssociation_INCLUDED
!include Util.nsh
!verbose push
!verbose 3
!ifndef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE 3
!endif
!verbose ${_FileAssociation_VERBOSE}
!define FileAssociation_VERBOSE `!insertmacro FileAssociation_VERBOSE`
!verbose pop
!macro FileAssociation_VERBOSE _VERBOSE
!verbose push
!verbose 3
!undef _FileAssociation_VERBOSE
!define _FileAssociation_VERBOSE ${_VERBOSE}
!verbose pop
!macroend
!macro RegisterExtensionCall _EXECUTABLE _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_DESCRIPTION}`
Push `${_EXTENSION}`
Push `${_EXECUTABLE}`
${CallArtificialFunction} RegisterExtension_
!verbose pop
!macroend
!macro UnRegisterExtensionCall _EXTENSION _DESCRIPTION
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Push `${_EXTENSION}`
Push `${_DESCRIPTION}`
${CallArtificialFunction} UnRegisterExtension_
!verbose pop
!macroend
!define RegisterExtension `!insertmacro RegisterExtensionCall`
!define un.RegisterExtension `!insertmacro RegisterExtensionCall`
!macro RegisterExtension
!macroend
!macro un.RegisterExtension
!macroend
!macro RegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R2 ;exe
Exch
Exch $R1 ;ext
Exch
Exch 2
Exch $R0 ;desc
Exch 2
Push $0
Push $1
ReadRegStr $1 HKCR $R1 "" ; read current file association
StrCmp "$1" "" NoBackup ; is it empty
StrCmp "$1" "$R0" NoBackup ; is it our own
WriteRegStr HKCR $R1 "backup_val" "$1" ; backup current value
NoBackup:
WriteRegStr HKCR $R1 "" "$R0" ; set our file association
ReadRegStr $0 HKCR $R0 ""
StrCmp $0 "" 0 Skip
WriteRegStr HKCR "$R0" "" "$R0"
WriteRegStr HKCR "$R0\shell" "" "open"
WriteRegStr HKCR "$R0\DefaultIcon" "" "$R2,0"
Skip:
WriteRegStr HKCR "$R0\shell\open\command" "" '"$R2" "%1"'
WriteRegStr HKCR "$R0\shell\edit" "" "Edit $R0"
WriteRegStr HKCR "$R0\shell\edit\command" "" '"$R2" "%1"'
Pop $1
Pop $0
Pop $R2
Pop $R1
Pop $R0
!verbose pop
!macroend
!define UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!define un.UnRegisterExtension `!insertmacro UnRegisterExtensionCall`
!macro UnRegisterExtension
!macroend
!macro un.UnRegisterExtension
!macroend
!macro UnRegisterExtension_
!verbose push
!verbose ${_FileAssociation_VERBOSE}
Exch $R1 ;desc
Exch
Exch $R0 ;ext
Exch
Push $0
Push $1
ReadRegStr $1 HKCR $R0 ""
StrCmp $1 $R1 0 NoOwn ; only do this if we own it
ReadRegStr $1 HKCR $R0 "backup_val"
StrCmp $1 "" 0 Restore ; if backup="" then delete the whole key
DeleteRegKey HKCR $R0
Goto NoOwn
Restore:
WriteRegStr HKCR $R0 "" $1
DeleteRegValue HKCR $R0 "backup_val"
DeleteRegKey HKCR $R1 ;Delete key with association name settings
NoOwn:
Pop $1
Pop $0
Pop $R1
Pop $R0
!verbose pop
!macroend
!endif # !FileAssociation_INCLUDED

View File

@ -125,21 +125,66 @@ def parseDependenciesWindows(tempFile):
# At least we got some data.
return filenames
def addDependencies(path, pathname, file, pluginDependencies, dependentFiles):
""" Checks the named file for DLL dependencies, and adds any
appropriate dependencies found into pluginDependencies and
dependentFiles. """
tempFile = Filename.temporary('', 'p3d_', '.txt')
command = 'dumpbin /dependents "%s" >"%s"' % (
pathname.toOsSpecific(),
tempFile.toOsSpecific())
try:
os.system(command)
except:
pass
filenames = None
if tempFile.exists():
filenames = parseDependenciesWindows(tempFile)
tempFile.unlink()
if filenames is None:
sys.exit("Unable to determine dependencies from %s" % (pathname))
# Look for MSVC[RP]*.dll, and MFC*.dll. These dependent files
# have to be included too. Also, any Panda-based libraries, or
# the Python DLL, should be included, in case panda3d.exe wasn't
# built static. The Panda-based libraries begin with "lib" and
# are all lowercase.
for dfile in filenames:
dfilelower = dfile.lower()
if dfilelower not in dependentFiles:
if dfilelower.startswith('msvc') or \
dfilelower.startswith('mfc') or \
(dfile.startswith('lib') and dfile == dfilelower) or \
dfilelower.startswith('python'):
pathname = path.findFile(dfile)
if not pathname:
sys.exit("Couldn't find %s." % (dfile))
dependentFiles[dfilelower] = pathname.toOsSpecific()
# Also recurse.
addDependencies(path, pathname, file, pluginDependencies, dependentFiles)
if dfilelower in dependentFiles:
pluginDependencies[file].append(dfilelower)
def makeInstaller():
# Locate the plugin(s).
pluginFiles = {}
pluginDependencies = {}
dependentFiles = {}
# These are the three primary files that make up the
# These are the four primary files that make up the
# plugin/runtime.
ocx = 'p3dactivex.ocx'
npapi = 'nppanda3d.dll'
panda3d = 'panda3d.exe'
panda3dw = 'panda3dw.exe'
path = DSearchPath()
path.appendPath(os.environ['PATH'])
for file in [ocx, npapi, panda3d]:
for file in [ocx, npapi, panda3d, panda3dw]:
pathname = path.findFile(file)
if not pathname:
sys.exit("Couldn't find %s." % (file))
@ -148,32 +193,7 @@ def makeInstaller():
pluginDependencies[file] = []
# Also look for the dll's that these plugins reference.
tempFile = Filename.temporary('', 'p3d_', '.txt')
command = 'dumpbin /dependents "%s" >"%s"' % (
pathname.toOsSpecific(),
tempFile.toOsSpecific())
try:
os.system(command)
except:
pass
filenames = None
if tempFile.exists():
filenames = parseDependenciesWindows(tempFile)
tempFile.unlink()
if filenames is None:
sys.exit("Unable to determine dependencies from %s" % (pathname))
# Look for MSVC[RP]*.dll, and MFC*.dll. These dependent files
# have to be included too.
for dfile in filenames:
dfile = dfile.lower()
if dfile.startswith('msvc') or dfile.startswith('mfc'):
pathname = path.findFile(dfile)
if not pathname:
sys.exit("Couldn't find %s." % (dfile))
pluginDependencies[file].append(dfile)
dependentFiles[dfile] = pathname.toOsSpecific()
addDependencies(path, pathname, file, pluginDependencies, dependentFiles)
welcomeBitmap = None
if options.welcome_image:
@ -216,6 +236,8 @@ def makeInstaller():
CMD += '/DNPAPI_PATH="' + pluginFiles[npapi] + '" '
CMD += '/DPANDA3D="' + panda3d + '" '
CMD += '/DPANDA3D_PATH="' + pluginFiles[panda3d] + '" '
CMD += '/DPANDA3DW="' + panda3dw + '" '
CMD += '/DPANDA3DW_PATH="' + pluginFiles[panda3dw] + '" '
dependencies = dependentFiles.items()
for i in range(len(dependencies)):

View File

@ -1,6 +1,7 @@
!include "MUI.nsh"
!include LogicLib.nsh
!include FileFunc.nsh
!include FileAssociation.nsh
; Several variables are assumed to be pre-defined by the caller. See
; make_installer.py in this directory.
@ -73,6 +74,7 @@ Section "MainSection" SEC01
File "${OCX_PATH}"
File "${NPAPI_PATH}"
File "${PANDA3D_PATH}"
File "${PANDA3DW_PATH}"
; Auto-detected dependencies on the above executables. Python
; computes these values for us.
@ -91,7 +93,15 @@ Section "MainSection" SEC01
!ifdef DEP4P
File "${DEP4P}"
!endif
!ifdef DEP5P
File "${DEP5P}"
!endif
!ifdef DEP6P
File "${DEP6P}"
!endif
${registerExtension} "$INSTDIR\${PANDA3DW}" ".p3d" "Panda3D applet"
!ifdef ADD_START_MENU
; Start->Programs links
CreateDirectory "$SMPROGRAMS\${PROG_GROUPNAME}"
@ -166,6 +176,12 @@ Mozilla-Install-Loop:
!endif
!ifdef NPAPI_DEP4
CopyFiles $INSTDIR\${NPAPI_DEP4} "$2"
!endif
!ifdef NPAPI_DEP5
CopyFiles $INSTDIR\${NPAPI_DEP5} "$2"
!endif
!ifdef NPAPI_DEP6
CopyFiles $INSTDIR\${NPAPI_DEP6} "$2"
!endif
${EndIf}
@ -183,6 +199,7 @@ Section Uninstall
Delete "$INSTDIR\${OCX}"
Delete "$INSTDIR\${NPAPI}"
Delete "$INSTDIR\${PANDA3D}"
Delete "$INSTDIR\${PANDA3DW}"
!ifdef DEP0
Delete "$INSTDIR\${DEP0}"
!endif
@ -198,6 +215,12 @@ Section Uninstall
!ifdef DEP4
Delete "$INSTDIR\${DEP4}"
!endif
!ifdef DEP5
Delete "$INSTDIR\${DEP5}"
!endif
!ifdef DEP6
Delete "$INSTDIR\${DEP6}"
!endif
StrCpy $1 "0"
Mozilla-Uninstall-Loop:
@ -213,7 +236,7 @@ Mozilla-Uninstall-Loop:
goto Mozilla-Uninstall-Loop
Mozilla-Uninstall-End:
ReadRegDWORD $0 HKLM SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System EnableLUA
${unregisterExtension} ".p3d" "Panda3D applet"
# Remove the user's "Panda3D" directory, where all of the downloaded
# contents are installed. Too bad we can't do this for every system

View File

@ -26,3 +26,29 @@
#endif
#end bin_target
#begin bin_target
// On Windows, we also need to build panda3dw.exe, the non-console
// version of panda3d.exe.
#define BUILD_TARGET $[WINDOWS_PLATFORM]
#define USE_PACKAGES openssl zlib
#define TARGET panda3dw
#define EXTRA_CDEFS NON_CONSOLE
#define LOCAL_LIBS plugin_common
#define OTHER_LIBS \
prc:c dtoolutil:c dtoolbase:c dtool:m \
interrogatedb:c dconfig:c dtoolconfig:m \
express:c downloader:c pandaexpress:m \
pystub
#define OSX_SYS_FRAMEWORKS Foundation AppKit Carbon
#define SOURCES \
panda3d.cxx panda3d.h panda3d.I
#define WIN_SYS_LIBS user32.lib gdi32.lib shell32.lib ole32.lib
#end bin_target

View File

@ -52,6 +52,12 @@ Panda3D() {
_root_dir = find_root_dir();
_reporting_download = false;
_enable_security = false;
#ifdef NON_CONSOLE
// For the desktop version of this program, let's always assume -S
// is in effect.
_enable_security = true;
#endif
}
////////////////////////////////////////////////////////////////////
@ -1126,8 +1132,77 @@ run() {
}
#if defined(_WIN32) && defined(NON_CONSOLE)
// On Windows, we may need to build panda3dw.exe, a non-console
// version of this program.
// Returns a newly-allocated string representing the quoted argument
// beginning at p. Advances p to the first character following the
// close quote.
static char *
parse_quoted_arg(char *&p) {
char quote = *p;
++p;
string result;
while (*p != '\0' && *p != quote) {
// TODO: handle escape characters? Not sure if we need to.
result += *p;
++p;
}
if (*p == quote) {
++p;
}
return strdup(result.c_str());
}
// Returns a newly-allocated string representing the unquoted argument
// beginning at p. Advances p to the first whitespace following the
// argument.
static char *
parse_unquoted_arg(char *&p) {
string result;
while (*p != '\0' && !isspace(*p)) {
result += *p;
++p;
}
return strdup(result.c_str());
}
WINAPI
WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
char *command_line = GetCommandLine();
vector<char *> argv;
char *p = command_line;
while (*p != '\0') {
if (*p == '"') {
char *arg = parse_quoted_arg(p);
argv.push_back(arg);
} else {
char *arg = parse_unquoted_arg(p);
argv.push_back(arg);
}
// Skip whitespace.
while (*p != '\0' && isspace(*p)) {
++p;
}
}
assert(!argv.empty());
Panda3D program;
return program.run(argv.size(), &argv[0]);
}
#else // NON_CONSOLE
// The normal, "console" program.
int
main(int argc, char *argv[]) {
Panda3D program;
return program.run(argc, argv);
}
#endif // NON_CONSOLE