Explorar el Código

panda3dw.exe, and file-associations for windows

David Rose hace 16 años
padre
commit
216211343f

+ 190 - 0
direct/src/plugin_installer/FileAssociation.nsh

@@ -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

+ 50 - 28
direct/src/plugin_installer/make_installer.py

@@ -125,21 +125,66 @@ def parseDependenciesWindows(tempFile):
     # At least we got some data.
     # At least we got some data.
     return filenames
     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():
 def makeInstaller():
     # Locate the plugin(s).
     # Locate the plugin(s).
     pluginFiles = {}
     pluginFiles = {}
     pluginDependencies = {}
     pluginDependencies = {}
     dependentFiles = {}
     dependentFiles = {}
 
 
-    # These are the three primary files that make up the
+    # These are the four primary files that make up the
     # plugin/runtime.
     # plugin/runtime.
     ocx = 'p3dactivex.ocx'
     ocx = 'p3dactivex.ocx'
     npapi = 'nppanda3d.dll'
     npapi = 'nppanda3d.dll'
     panda3d = 'panda3d.exe'
     panda3d = 'panda3d.exe'
+    panda3dw = 'panda3dw.exe'
 
 
     path = DSearchPath()
     path = DSearchPath()
     path.appendPath(os.environ['PATH'])
     path.appendPath(os.environ['PATH'])
-    for file in [ocx, npapi, panda3d]:
+    for file in [ocx, npapi, panda3d, panda3dw]:
         pathname = path.findFile(file)
         pathname = path.findFile(file)
         if not pathname:
         if not pathname:
             sys.exit("Couldn't find %s." % (file))
             sys.exit("Couldn't find %s." % (file))
@@ -148,32 +193,7 @@ def makeInstaller():
         pluginDependencies[file] = []
         pluginDependencies[file] = []
 
 
         # Also look for the dll's that these plugins reference.
         # 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
     welcomeBitmap = None
     if options.welcome_image:
     if options.welcome_image:
@@ -216,6 +236,8 @@ def makeInstaller():
     CMD += '/DNPAPI_PATH="' + pluginFiles[npapi] + '" '
     CMD += '/DNPAPI_PATH="' + pluginFiles[npapi] + '" '
     CMD += '/DPANDA3D="' + panda3d + '" '
     CMD += '/DPANDA3D="' + panda3d + '" '
     CMD += '/DPANDA3D_PATH="' + pluginFiles[panda3d] + '" '
     CMD += '/DPANDA3D_PATH="' + pluginFiles[panda3d] + '" '
+    CMD += '/DPANDA3DW="' + panda3dw + '" '
+    CMD += '/DPANDA3DW_PATH="' + pluginFiles[panda3dw] + '" '
 
 
     dependencies = dependentFiles.items()
     dependencies = dependentFiles.items()
     for i in range(len(dependencies)):
     for i in range(len(dependencies)):

+ 24 - 1
direct/src/plugin_installer/p3d_installer.nsi

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

+ 26 - 0
direct/src/plugin_standalone/Sources.pp

@@ -26,3 +26,29 @@
   #endif
   #endif
 
 
 #end bin_target
 #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

+ 75 - 0
direct/src/plugin_standalone/panda3d.cxx

@@ -52,6 +52,12 @@ Panda3D() {
   _root_dir = find_root_dir();
   _root_dir = find_root_dir();
   _reporting_download = false;
   _reporting_download = false;
   _enable_security = 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
 int
 main(int argc, char *argv[]) {
 main(int argc, char *argv[]) {
   Panda3D program;
   Panda3D program;
   return program.run(argc, argv);
   return program.run(argc, argv);
 }
 }
+#endif  // NON_CONSOLE