fix script node advise/unadvise
diff --git a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireInstaller/Release/IECrossfireInstaller.msi b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireInstaller/Release/IECrossfireInstaller.msi
index 66f1a7d..57c85c5 100644
--- a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireInstaller/Release/IECrossfireInstaller.msi
+++ b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireInstaller/Release/IECrossfireInstaller.msi
Binary files differ
diff --git a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.cpp b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.cpp
index 0ce5aee..1b10614 100644
--- a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.cpp
+++ b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.cpp
@@ -1368,29 +1368,6 @@
         return false;
 	}
 
-	CComPtr<IDebugApplicationNode> rootNode = NULL;
-	hr = debugApplication->GetRootNode(&rootNode);
-	if (FAILED(hr)) {
-		Logger::error("CrossfireContext.getDebugApplicationThread(): GetRootNode() failed", hr);
-	} else {
-		CComPtr<IConnectionPointContainer> connectionPointContainer = NULL;
-		hr = rootNode->QueryInterface(IID_IConnectionPointContainer, (void**)&connectionPointContainer);
-		if (FAILED(hr)) {
-			Logger::error("CrossfireContext.getDebugApplicationThread(): QI(IConnectionPointContainer) failed", hr);
-		} else {
-			CComPtr<IConnectionPoint> connectionPoint = NULL;
-			hr = connectionPointContainer->FindConnectionPoint(IID_IDebugApplicationNodeEvents, &connectionPoint);
-			if (FAILED(hr)) {
-				Logger::error("CrossfireContext.getDebugApplicationThread(): FindConnectionPoint() failed", hr);
-			} else {
-				hr = connectionPoint->Advise(m_debugger, &m_cpcApplicationNodeEvents);
-				if (FAILED(hr)) {
-					Logger::error("CrossfireContext.getDebugApplicationThread(): Advise() failed", hr);
-				}
-			}
-		}
-	}
-
 	CComPtr<IEnumRemoteDebugApplicationThreads> debugApplicationThreads;
 	hr = debugApplication->EnumThreads(&debugApplicationThreads);
 	if (FAILED(hr)) {
@@ -1583,11 +1560,12 @@
 			Logger::error("CrossfireContext.registerScript(): GetName() failed", hr);
 			return false;
 		}
-		int length = wcslen(SCHEME_JSCRIPT) + wcslen(value.m_str) + 1;
+		int length = wcslen(SCHEME_JSCRIPT) + wcslen(value.m_str) + 2;
 		wchar_t* string = new wchar_t[length];
 		ZeroMemory(string, length * sizeof(wchar_t));
 		wcscat_s(string, length, SCHEME_JSCRIPT);
 		wcscat_s(string, length, value.m_str);
+		wcscat_s(string, length, L"/");
 		url.setString(string);
 		delete[] string;
 	}
@@ -1609,7 +1587,6 @@
 			break;
 		}
 		key.assign(url.getString());
-		key += wchar_t('/');
 		wchar_t qualifierString[4];
 		_ltow_s(qualifierIndex++, qualifierString, 4, 10); /* trailing linebreak */
 		key += qualifierString;
diff --git a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.h b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.h
index 989ff75..2dda24d 100644
--- a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.h
+++ b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/CrossfireContext.h
@@ -38,6 +38,7 @@
 	CrossfireContext(DWORD processId, wchar_t* url, CrossfireServer* server);
 	~CrossfireContext();
 	virtual void breakpointHit(IRemoteDebugApplicationThread *pDebugAppThread, BREAKREASON br, IActiveScriptErrorDebug *pScriptErrorDebug);
+	virtual bool getDebugApplication(IRemoteDebugApplication** _value);
 	virtual IDebugApplicationNode* getLastInitializedScriptNode();
 	virtual wchar_t* getName();
 	virtual DWORD getProcessId();
@@ -71,7 +72,6 @@
 	virtual bool createValueForScript(IDebugApplicationNode* node, bool includeSource, bool failIfEmpty, Value** _value);
 	virtual bool evaluate(IDebugStackFrame* stackFrame, wchar_t* expression, int flags, IDebugProperty** _result);
 	virtual bool evaluateAsync(IDebugStackFrame* stackFrame, wchar_t* expression, int flags, IJSEvalHandler* handler, void* data);
-	virtual bool getDebugApplication(IRemoteDebugApplication** _value);
 	virtual bool getDebugApplicationThread(IRemoteDebugApplicationThread** _value);
 	virtual bool getScriptUrl(IDebugApplicationNode* node, URL** _value);
 	virtual IDebugApplicationNode* getScriptNode(URL* url);
diff --git a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.cpp b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.cpp
index d112517..dfe3901 100644
--- a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.cpp
+++ b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.cpp
@@ -13,9 +13,13 @@
 #include "stdafx.h"
 #include "IEDebugger.h"
 
+/* initialize constants */
+const wchar_t* IEDebugger::ABOUT_BLANK = L"about:blank";
+
 IEDebugger::IEDebugger() {
+	m_adviseCookies = new std::map<IDebugApplicationNode*, DWORD>;
 	m_context = NULL;
-	m_adviseCookies = new std::multimap<std::wstring, DWORD>;
+	m_rootNode = NULL;
 }
 
 IEDebugger::~IEDebugger() {
@@ -77,69 +81,23 @@
 		return S_OK;
 	}
 
-	m_context->scriptInitialized(prddpChild);
-
-	CComPtr <IConnectionPointContainer> connectionPointContainer = NULL;
-	HRESULT hr = prddpChild->QueryInterface(IID_IConnectionPointContainer, (void**)&connectionPointContainer);
-	if (FAILED(hr)) {
-		Logger::error("IEDebugger.onAddChild(): QI(IID_IConnectionPointContainer) failed", hr);
-		return S_FALSE;
-	}
-	CComPtr <IConnectionPoint> nodeConnectionPoint = NULL;
-	hr = connectionPointContainer->FindConnectionPoint(IID_IDebugApplicationNodeEvents, &nodeConnectionPoint);
-	if (FAILED(hr)) {
-		Logger::error("IEDebugger.onAddChild(): FindConnectionPoint() failed", hr);
-		return S_FALSE;
-	}
-
-	DWORD connectionPointCookie = 0;
-	hr = nodeConnectionPoint->Advise(static_cast<IIEDebugger*>(this), &connectionPointCookie);
-	if (FAILED(hr)) {
-		Logger::error("IEDebugger.onAddChild(): Advise() failed", hr);
-		return S_FALSE;
-	}
-
+	/* don't register about:blank as a script */
 	CComBSTR bstrUrl = NULL;
-	hr = prddpChild->GetName(DOCUMENTNAMETYPE_TITLE, &bstrUrl);
+	HRESULT hr = prddpChild->GetName(DOCUMENTNAMETYPE_TITLE, &bstrUrl);
 	if (FAILED(hr)) {
 		Logger::error("IEDebugger.onAddChild(): GetName() failed", hr);
-		return S_FALSE;
+	} else {
+		if (wcscmp(bstrUrl, ABOUT_BLANK) != 0) {
+			m_context->scriptInitialized(prddpChild);
+		}
 	}
-	URL url(bstrUrl);
-	m_adviseCookies->insert(std::pair<std::wstring,DWORD>(std::wstring(url.getString()), connectionPointCookie));
+
+	advise(prddpChild, false, false);
 	return S_OK;
 }
 
 STDMETHODIMP IEDebugger::onRemoveChild(IDebugApplicationNode *prddpChild) {
-	CComBSTR bstrUrl = NULL;
-	if (FAILED(prddpChild->GetName(DOCUMENTNAMETYPE_TITLE, &bstrUrl))) {
-		return S_OK;
-	}
-	URL url(bstrUrl);
-
-	CComPtr <IConnectionPointContainer> connectionPointContainer = NULL;
-	HRESULT hr = prddpChild->QueryInterface(IID_IConnectionPointContainer, (void**)&connectionPointContainer);
-	if (FAILED(hr)) {
-		Logger::error("IEDebugger.onRemoveChild(): QI(IID_IConnectionPointContainer) failed", hr);
-		return S_FALSE;
-	}
-	CComPtr <IConnectionPoint> nodeConnectionPoint = NULL;
-	hr = connectionPointContainer->FindConnectionPoint(IID_IDebugApplicationNodeEvents, &nodeConnectionPoint);
-	if (FAILED(hr)) {
-		Logger::error("IEDebugger.onRemoveChild(): FindConnectionPoint() failed", hr);
-		return S_FALSE;
-	}
-
-	std::pair<std::multimap<std::wstring,DWORD>::iterator,std::multimap<std::wstring,DWORD>::iterator> range;
-	range = m_adviseCookies->equal_range(std::wstring(url.getString()));
-	std::multimap<std::wstring,DWORD>::iterator it;
-	for (it = range.first; it != range.second; ++it) {
-		if (SUCCEEDED(nodeConnectionPoint->Unadvise(it->second))) {
-			m_adviseCookies->erase(it);
-			break;
-		}
-	}
-
+	unadvise(prddpChild, false, false);
 	return S_OK;
 }
 
@@ -160,7 +118,131 @@
 
 /* IEDebugger */
 
-void IEDebugger::setContext(CrossfireContext* value) {
-	m_context = value;
+bool IEDebugger::advise(IDebugApplicationNode* node, bool isRoot, bool recurse) {
+	CComPtr<IConnectionPointContainer> connectionPointContainer = NULL;
+	HRESULT hr = node->QueryInterface(IID_IConnectionPointContainer, (void**)&connectionPointContainer);
+	if (FAILED(hr)) {
+		Logger::error("IEDebugger.advise(): QI(IID_IConnectionPointContainer) failed", hr);
+		return false;
+	}
+	CComPtr<IConnectionPoint> nodeConnectionPoint = NULL;
+	hr = connectionPointContainer->FindConnectionPoint(IID_IDebugApplicationNodeEvents, &nodeConnectionPoint);
+	if (FAILED(hr)) {
+		Logger::error("IEDebugger.advise(): FindConnectionPoint() failed", hr);
+		return false;
+	}
+
+	DWORD connectionPointCookie = 0;
+	hr = nodeConnectionPoint->Advise(static_cast<IIEDebugger*>(this), &connectionPointCookie);
+	if (FAILED(hr)) {
+		Logger::error("IEDebugger.advise(): Advise() failed", hr);
+		return false;
+	}
+
+	if (isRoot) {
+		m_rootCookie = connectionPointCookie;
+		m_rootNode = node;
+	} else {
+		m_adviseCookies->insert(std::pair<IDebugApplicationNode*,DWORD>(node, connectionPointCookie));
+	}
+	node->AddRef();
+
+	if (recurse) {
+		CComPtr<IEnumDebugApplicationNodes> nodes = NULL;
+		hr = node->EnumChildren(&nodes);
+		if (FAILED(hr)) {
+			Logger::error("IEDebugger.advise(): EnumChildren() failed", hr);
+		} else {
+			IDebugApplicationNode* current = NULL;
+			ULONG count = 0;
+			hr = nodes->Next(1, &current, &count);
+			while (SUCCEEDED(hr) && count) {
+				advise(current, false, true);
+				current->Release();
+				hr = nodes->Next(1, &current, &count);
+			}
+		}
+	}
+	return true;
 }
 
+void IEDebugger::setContext(CrossfireContext* value) {
+	if (m_context == value) {
+		return;
+	}
+	m_context = value;
+
+	if (m_rootNode) {
+		unadvise(m_rootNode, true, true);
+	}
+
+	if (value) {
+		CComPtr<IRemoteDebugApplication> application = NULL;
+		HRESULT hr = m_context->getDebugApplication(&application);
+		if (SUCCEEDED(hr)) {
+			CComPtr<IDebugApplicationNode> rootNode = NULL;
+			hr = application->GetRootNode(&rootNode);
+			if (FAILED(hr)) {
+				Logger::error("IEDebugger.setContext(): GetRootNode() failed", hr);
+				return;
+			}
+			advise(rootNode, true, true);
+		}
+	}
+}
+
+bool IEDebugger::unadvise(IDebugApplicationNode* node, bool isRoot, bool recurse) {
+	CComPtr<IConnectionPointContainer> connectionPointContainer = NULL;
+	HRESULT hr = node->QueryInterface(IID_IConnectionPointContainer, (void**)&connectionPointContainer);
+	if (FAILED(hr)) {
+		Logger::error("IEDebugger.unadvise(): QI(IID_IConnectionPointContainer) failed", hr);
+		return false;
+	}
+	CComPtr<IConnectionPoint> nodeConnectionPoint = NULL;
+	hr = connectionPointContainer->FindConnectionPoint(IID_IDebugApplicationNodeEvents, &nodeConnectionPoint);
+	if (FAILED(hr)) {
+		Logger::error("IEDebugger.unadvise(): FindConnectionPoint() failed", hr);
+		return false;
+	}
+
+	DWORD cookie = 0;
+	if (isRoot) {
+		cookie = m_rootCookie;
+		m_rootNode->Release();
+		m_rootNode = NULL;
+	} else {
+		std::map<IDebugApplicationNode*, DWORD>::iterator iterator = m_adviseCookies->find(node);
+		if (iterator != m_adviseCookies->end()) {
+			cookie = iterator->second;
+			iterator->first->Release();
+			m_adviseCookies->erase(iterator);
+		}
+	}
+
+	if (cookie) {
+		hr = nodeConnectionPoint->Unadvise(cookie);
+		if (FAILED(hr)) {
+			Logger::error("IEDebugger.unadvise(): Unadvise() failed", hr);
+		}
+	}
+
+	if (recurse) {
+		CComPtr<IEnumDebugApplicationNodes> nodes = NULL;
+		hr = node->EnumChildren(&nodes);
+		if (FAILED(hr)) {
+			Logger::error("IEDebugger.unadvise(): EnumChildren() failed", hr);
+		} else {
+			IDebugApplicationNode* current = NULL;
+			ULONG count = 0;
+			hr = nodes->Next(1, &current, &count);
+			while (SUCCEEDED(hr) && count) {
+				unadvise(current, false, true);
+				current->Release();
+				hr = nodes->Next(1, &current, &count);
+			}
+		}
+	}
+	return true;
+}
+
+
diff --git a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.h b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.h
index 8aece0d..3985801 100644
--- a/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.h
+++ b/development/org.eclipse.wst.jsdt.debug.ie/IECrossfireServer/IEDebugger.h
@@ -93,8 +93,16 @@
 	virtual void setContext(CrossfireContext* value);
 
 private:
+	virtual bool advise(IDebugApplicationNode* node, bool isRoot, bool recurse);
+	virtual bool unadvise(IDebugApplicationNode* node, bool isRoot, bool recurse);
+
+	std::map<IDebugApplicationNode*, DWORD>* m_adviseCookies;
 	CrossfireContext* m_context;
-	std::multimap<std::wstring, DWORD>* m_adviseCookies;
+	DWORD m_rootCookie;
+	IDebugApplicationNode* m_rootNode;
+
+	/* constants */
+	static const wchar_t* ABOUT_BLANK;
 };
 
 OBJECT_ENTRY_AUTO(__uuidof(IEDebugger), IEDebugger)