Bug 751541 - Fix for VS11 C++/CX link issues: delay load vccorlib and the winrt standard libraries, and provide a dummy vccorlib on non-win8 platforms so xul lib can load. r=ehsan+khuey, sr=bsmedberg
authorJim Mathies <jmathies@mozilla.com>
Tue, 22 May 2012 16:00:48 -0500
changeset 96077 40ba9d985ba3e7c4363beeac200820823531824d
parent 96076 8344de0f1079e669d55037cf84b0bdb549812a54
child 96078 023f75b6a2ecc02f8a08f48ef9afbfc1bcd72427
push idunknown
push userunknown
push dateunknown
reviewersehsan, bsmedberg
bugs751541
milestone15.0a1
Bug 751541 - Fix for VS11 C++/CX link issues: delay load vccorlib and the winrt standard libraries, and provide a dummy vccorlib on non-win8 platforms so xul lib can load. r=ehsan+khuey, sr=bsmedberg
config/autoconf.mk.in
configure.in
toolkit/library/Makefile.in
toolkit/library/nsDllMain.cpp
toolkit/library/winvccorlib/Makefile.in
toolkit/library/winvccorlib/dummyvccorlib.cpp
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -519,16 +519,18 @@ MOZ_ENABLE_CAIRO_FT	= @MOZ_ENABLE_CAIRO_
 MOZ_ENABLE_GTK2		= @MOZ_ENABLE_GTK2@
 MOZ_ENABLE_QT		= @MOZ_ENABLE_QT@
 MOZ_ENABLE_XREMOTE	= @MOZ_ENABLE_XREMOTE@
 MOZ_ENABLE_DWRITE_FONT	= @MOZ_ENABLE_DWRITE_FONT@
 MOZ_ENABLE_D2D_SURFACE	= @MOZ_ENABLE_D2D_SURFACE@
 MOZ_ENABLE_D3D9_LAYER	= @MOZ_ENABLE_D3D9_LAYER@
 MOZ_ENABLE_D3D10_LAYER  = @MOZ_ENABLE_D3D10_LAYER@
 MOZ_METRO	= @MOZ_METRO@
+CRTDLLVERSION	= @CRTDLLVERSION@
+CRTEXPDLLVERSION	= @CRTEXPDLLVERSION@
 
 MOZ_GTK2_CFLAGS		= @MOZ_GTK2_CFLAGS@
 MOZ_GTK2_LIBS		= @MOZ_GTK2_LIBS@
 
 MOZ_QT_CFLAGS		= @MOZ_QT_CFLAGS@
 MOZ_QT_LIBS		= @MOZ_QT_LIBS@
 MOZ_ENABLE_QTNETWORK    = @MOZ_ENABLE_QTNETWORK@
 MOZ_ENABLE_QMSYSTEM2    = @MOZ_ENABLE_QMSYSTEM2@
--- a/configure.in
+++ b/configure.in
@@ -613,22 +613,28 @@ MOZ_ARG_ENABLE_BOOL(metro,
     MOZ_METRO=1,
     MOZ_METRO=)
 if test -n "$MOZ_METRO"; then
     AC_DEFINE(MOZ_METRO)
     # Target the Windows 8 Kit
     WINSDK_TARGETVER=602
     # Allow a higher api set
     WINVER=602
+    # toolkit/library/makefile.in needs these, see nsDllMain.
+    CRTDLLVERSION=110
+    CRTEXPDLLVERSION=1-1-0
 else
     # Target the Windows 7 SDK by default
     WINSDK_TARGETVER=601
     WINVER=502
 fi
 
+AC_SUBST(CRTDLLVERSION)
+AC_SUBST(CRTEXPDLLVERSION)
+
 if test -n "$MOZ_METRO"; then
   case "$target" in
   *-mingw*)
     ;;
   *)
     AC_MSG_ERROR([Metro builds only valid on the windows platform.]);
     ;;
   esac
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -12,16 +12,20 @@ include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/rdf/util/src/objs.mk
 include $(topsrcdir)/intl/unicharutil/util/objs.mk
 
 MODULE = libxul
 LIBRARY_NAME = xul
 FORCE_SHARED_LIB = 1
 MOZILLA_INTERNAL_API = 1
 
+ifdef MOZ_METRO
+DIRS += winvccorlib
+endif
+
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 # This is going to be a framework named "XUL", not an ordinary library named
 # "libxul.dylib"
 LIBRARY_NAME=XUL
 # Setting MAKE_FRAMEWORK makes DLL_PREFIX and DLL_SUFFIX be ignored when
 # setting SHARED_LIBRARY; we need to leave DLL_PREFIX and DLL_SUFFIX
 # as-is so that dependencies of the form -ltracemalloc still work.
 MAKE_FRAMEWORK=1
@@ -539,16 +543,28 @@ EXTRA_DSO_LDOPTS += \
   -DELAYLOAD:psapi.dll \
   -DELAYLOAD:dbghelp.dll \
   -DELAYLOAD:rasapi32.dll \
   -DELAYLOAD:rasdlg.dll \
   -DELAYLOAD:comdlg32.dll \
   -DELAYLOAD:winspool.drv \
   -DELAYLOAD:secur32.dll \
   $(NULL)
+
+# See nsDllMain for an explanation
+ifdef MOZ_METRO
+ifdef MOZ_DEBUG
+EXTRA_DSO_LDOPTS += -DELAYLOAD:VCCORLIB$(CRTDLLVERSION)D.DLL
+else
+EXTRA_DSO_LDOPTS += -DELAYLOAD:VCCORLIB$(CRTDLLVERSION).DLL
+endif
+EXTRA_DSO_LDOPTS += -DELAYLOAD:API-MS-WIN-CORE-WINRT-L$(CRTEXPDLLVERSION).DLL
+EXTRA_DSO_LDOPTS += -DELAYLOAD:API-MS-WIN-CORE-WINRT-STRING-L$(CRTEXPDLLVERSION).DLL
+endif
+
 ifdef ACCESSIBILITY
 EXTRA_DSO_LDOPTS += -DELAYLOAD:oleacc.dll
 endif
 endif
 endif # WINNT
 
 ifdef MOZ_JPROF
 EXTRA_DSO_LDOPTS += -ljprof
--- a/toolkit/library/nsDllMain.cpp
+++ b/toolkit/library/nsDllMain.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
 #include <windows.h>
+#include <delayimp.h>
 #include "nsToolkit.h"
 
 #if defined(__GNUC__)
 // If DllMain gets name mangled, it won't be seen.
 extern "C" {
 #endif
 
 BOOL APIENTRY DllMain(  
@@ -31,11 +32,68 @@ BOOL APIENTRY DllMain(
             nsToolkit::Shutdown();
             break;
 
     }
 
     return TRUE;
 }
 
+#if defined(MOZ_METRO)
+/*
+ * DelayDllLoadHook - the crt calls here anytime a delay load dll is about to
+ * load. There are a number of events, we listen for dliNotePreLoadLibrary.
+ * 
+ * On Win8, we enable Windows Runtime Component Extension support. When enabled
+ * the compiler bakes auto-generated code into our binary, including a c init-
+ * ializer which inits the winrt library through a call into the winrt standard
+ * lib 'vccorlib'. Vccorlib in turn has system dll dependencies which are only
+ * available on Win8 (currently API-MS-WIN-CORE-WINRT and
+ * API-MS-WIN-CORE-WINRT-STRING), which prevent xul.dll from loading on os <=
+ * Win7. To get around this we generate a dummy vccore lib with the three entry
+ * points the initializer needs and load it in place of the real vccorlib. We
+ * also have to add vccorlib and the system dlls to the delay load list.
+ */
+static bool IsWin8OrHigher()
+{
+  static PRInt32 version = 0;
+
+  if (version) {
+    return (version >= 0x602);
+  }
+
+  // Match Win8 or Win8 Server or higher
+  OSVERSIONINFOEX osInfo;
+  osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+  ::GetVersionEx((OSVERSIONINFO*)&osInfo);
+  version =
+    (osInfo.dwMajorVersion & 0xff) << 8 | (osInfo.dwMinorVersion & 0xff);
+  return (version >= 0x602);
+}
+
+const char* kvccorlib = "vccorlib";
+const char* kwinrtprelim = "api-ms-win-core-winrt";
+
+static bool IsWinRTDLLPresent(PDelayLoadInfo pdli, const char* aLibToken)
+{
+  return (!IsWin8OrHigher() && pdli->szDll &&
+          !strnicmp(pdli->szDll, aLibToken, strlen(aLibToken)));
+}
+
+FARPROC WINAPI DelayDllLoadHook(unsigned dliNotify, PDelayLoadInfo pdli)
+{
+  if (dliNotify == dliNotePreLoadLibrary) {
+    if (IsWinRTDLLPresent(pdli, kvccorlib)) {
+      return (FARPROC)LoadLibraryA("dummyvccorlib.dll");
+    }
+    NS_ASSERTION(!IsWinRTDLLPresent(pdli, kwinrtprelim),
+      "Attempting to load winrt libs in non-metro environment. "
+      "(Winrt variable type placed in global scope?)");
+  }
+  return NULL;
+}
+
+ExternC PfnDliHook __pfnDliNotifyHook2 = DelayDllLoadHook;
+#endif // MOZ_METRO
+
 #if defined(__GNUC__)
 } // extern "C"
 #endif
new file mode 100644
--- /dev/null
+++ b/toolkit/library/winvccorlib/Makefile.in
@@ -0,0 +1,23 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEPTH     = ../../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+LIBRARY_NAME	= dummyvccorlib
+MODULE    = dummyvccorlib
+GRE_MODULE   = 1
+
+include $(DEPTH)/config/autoconf.mk
+
+FORCE_SHARED_LIB=1
+
+CPPSRCS	= \
+	dummyvccorlib.cpp \
+	$(NULL)
+
+include $(topsrcdir)/config/rules.mk
+
new file mode 100644
--- /dev/null
+++ b/toolkit/library/winvccorlib/dummyvccorlib.cpp
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <windows.h>
+
+// A dummy vccorlib.dll for shunting winrt initialization calls when we are not
+// using the winrt library. For a longer explanantion see nsDllMain.cpp.
+
+extern "C" {
+__declspec(dllexport) long __stdcall __InitializeWinRTRuntime(unsigned long data) { return S_OK; }
+}
+
+namespace Platform {
+namespace Details {
+__declspec(dllexport) HRESULT InitializeData(int __threading_model) { return S_OK; }
+__declspec(dllexport) void UninitializeData(int __threading_model) { }
+}
+}