Implemented a typelib loader cache.

diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c
index e981136..cb30cae 100644
--- a/dlls/oleaut32/typelib.c
+++ b/dlls/oleaut32/typelib.c
@@ -287,6 +287,8 @@
     INT index = 1;
 
     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
+    
+    *pptLib = NULL;
     if(!SearchPathW(NULL,szFile,NULL,sizeof(szPath)/sizeof(WCHAR),szPath,
 		    NULL)) {
 
@@ -653,6 +655,10 @@
     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
 				   libary. Only used while read MSFT
 				   typelibs */
+
+    /* typelibs are cached, keyed by path, so store the linked list info within them */
+    struct tagITypeLibImpl *next, *prev;
+    WCHAR *path;
 } ITypeLibImpl;
 
 static struct ICOM_VTABLE(ITypeLib2) tlbvt;
@@ -1708,6 +1714,7 @@
         recoffset += reclength;
     }
 }
+
 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
 		       int cVars, int offset, TLBVarDesc ** pptvd)
 {
@@ -1965,6 +1972,22 @@
     return ptiRet;
 }
 
+/* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
+ * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
+ * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
+ * tradeoff here.
+ */
+static ITypeLibImpl *tlb_cache_first;
+static CRITICAL_SECTION cache_section;
+static CRITICAL_SECTION_DEBUG cache_section_debug =
+{
+    0, 0, &cache_section,
+    { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
+      0, 0, { 0, (DWORD)(__FILE__ ": typelib loader cache") }
+};
+static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
+
+
 /****************************************************************************
  *	TLB_ReadTypeLib
  *
@@ -1975,6 +1998,7 @@
 #define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */
 int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib)
 {
+    ITypeLibImpl *entry;
     int ret = TYPE_E_CANTLOADLIBRARY;
     DWORD dwSignature = 0;
     HANDLE hFile;
@@ -1983,6 +2007,21 @@
 
     *ppTypeLib = NULL;
 
+    /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
+    EnterCriticalSection(&cache_section);
+    for (entry = tlb_cache_first; entry != NULL; entry = entry->next)
+    {
+        if (!strcmpiW(entry->path, pszFileName))
+        {
+            TRACE("cache hit\n");
+            *ppTypeLib = (ITypeLib2*)entry;
+            ITypeLib_AddRef(*ppTypeLib);
+            LeaveCriticalSection(&cache_section);
+            return S_OK;
+        }
+    }
+    LeaveCriticalSection(&cache_section);
+
     /* check the signature of the file */
     hFile = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
     if (INVALID_HANDLE_VALUE != hFile)
@@ -2054,11 +2093,23 @@
       }
     }
 
-    if(*ppTypeLib)
-      ret = S_OK;
-    else
-      ERR("Loading of typelib %s failed with error %ld\n",
-	  debugstr_w(pszFileName), GetLastError());
+    if(*ppTypeLib) {
+	ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
+	
+	TRACE("adding to cache\n");
+	impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszFileName)+1) * sizeof(WCHAR));
+	lstrcpyW(impl->path, pszFileName);
+	/* We should really canonicalise the path here. */
+
+        /* FIXME: check if it has added already in the meantime */
+        EnterCriticalSection(&cache_section);
+        if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl;
+        impl->prev = NULL;
+        tlb_cache_first = impl;
+        LeaveCriticalSection(&cache_section);
+        ret = S_OK;
+    } else
+	ERR("Loading of typelib %s failed with error %ld\n", debugstr_w(pszFileName), GetLastError());
 
     return ret;
 }
@@ -3197,7 +3248,7 @@
 {
     ICOM_THIS( ITypeLibImpl, iface);
 
-    TRACE("(%p)->ref is %u\n",This, This->ref);
+    TRACE("(%p)->ref was %u\n",This, This->ref);
 
     return ++(This->ref);
 }
@@ -3214,8 +3265,15 @@
 
     if (!This->ref)
     {
-      /* FIXME destroy child objects */
+      /* remove cache entry */
+      TRACE("removing from cache list\n");
+      EnterCriticalSection(&cache_section);
+      if (This->next) This->next->prev = This->prev;
+      if (This->prev) This->prev->next = This->next;
+      else tlb_cache_first = This->next;
+      LeaveCriticalSection(&cache_section);
 
+      /* FIXME destroy child objects */
       TRACE(" destroying ITypeLib(%p)\n",This);
 
       if (This->Name)
@@ -4448,6 +4506,7 @@
 	    if (pFDesc->funcdesc.invkind & dwFlags)
 		break;
 	}
+    
     if (pFDesc) {
 	if (TRACE_ON(typelib)) dump_TLBFuncDescOne(pFDesc);
 	/* dump_FUNCDESC(&pFDesc->funcdesc);*/
@@ -4869,13 +4928,13 @@
     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
     if (pIndex) {
       *pIndex=This->index;
-      TRACE("returning pIndex=%d", *pIndex);
+      TRACE("returning pIndex=%d\n", *pIndex);
     }
     
     if (ppTLib) {
       *ppTLib=(LPTYPELIB )(This->pTypeLib);
       ITypeLib2_AddRef(*ppTLib);
-      TRACE("returning ppTLib=%p", *ppTLib);
+      TRACE("returning ppTLib=%p\n", *ppTLib);
     }
     
     return S_OK;