[commit] r1696 - in trunk: GME/Core GME/Interfaces GME/Mga GME/MgaUtil Tests/GPyUnit

GMESRC Repository Notifications gme-commit at list.isis.vanderbilt.edu
Mon Nov 21 17:38:34 CST 2011


Author: ksmyth
Date: Mon Nov 21 17:38:34 2011
New Revision: 1696

Log:
Store regnodes in a hashmap. Uses an order of magnitude less memory

Added:
   trunk/GME/Core/CoreDictionaryAttributeValue.cpp
   trunk/GME/Core/CoreDictionaryAttributeValue.h
   trunk/Tests/GPyUnit/test_registry.py
Modified:
   trunk/GME/Core/Core.vcxproj
   trunk/GME/Core/Core.vcxproj.filters
   trunk/GME/Core/CoreAttribute.cpp
   trunk/GME/Core/CoreAttribute.h
   trunk/GME/Core/CoreBinFile.cpp
   trunk/GME/Core/CoreBinFile.h
   trunk/GME/Interfaces/Core.idl
   trunk/GME/Mga/Mga.vcxproj
   trunk/GME/Mga/MgaAttribute.cpp
   trunk/GME/Mga/MgaAttribute.h
   trunk/GME/Mga/MgaComplexOps.cpp
   trunk/GME/Mga/MgaCoreObj.cpp
   trunk/GME/Mga/MgaCoreObj.h
   trunk/GME/Mga/MgaDeriveOps.cpp
   trunk/GME/Mga/MgaFCO.cpp
   trunk/GME/Mga/MgaFCO.h
   trunk/GME/Mga/MgaFolder.cpp
   trunk/GME/Mga/MgaGeneric.cpp
   trunk/GME/Mga/MgaGeneric.h
   trunk/GME/Mga/MgaLibOps.cpp
   trunk/GME/Mga/MgaLibRefr.cpp
   trunk/GME/Mga/MgaProject.h
   trunk/GME/Mga/MgaTrukk.h
   trunk/GME/MgaUtil/RegBrwNode.h
   trunk/GME/MgaUtil/RegistryBrowserDlg.cpp
   trunk/Tests/GPyUnit/__init__.py

Modified: trunk/GME/Core/Core.vcxproj
==============================================================================
--- trunk/GME/Core/Core.vcxproj	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Core/Core.vcxproj	Mon Nov 21 17:38:34 2011	(r1696)
@@ -440,6 +440,7 @@
     <ClCompile Include="Core.cpp" />
     <ClCompile Include="CoreAttribute.cpp" />
     <ClCompile Include="CoreBinFile.cpp" />
+    <ClCompile Include="CoreDictionaryAttributeValue.cpp" />
     <ClCompile Include="CoreMetaAttribute.cpp" />
     <ClCompile Include="CoreMetaObject.cpp" />
     <ClCompile Include="CoreMetaProject.cpp" />
@@ -497,6 +498,7 @@
   <ItemGroup>
     <ClInclude Include="CoreAttribute.h" />
     <ClInclude Include="CoreBinFile.h" />
+    <ClInclude Include="CoreDictionaryAttributeValue.h" />
     <ClInclude Include="CoreMetaAttribute.h" />
     <ClInclude Include="CoreMetaObject.h" />
     <ClInclude Include="CoreMetaProject.h" />

Modified: trunk/GME/Core/Core.vcxproj.filters
==============================================================================
--- trunk/GME/Core/Core.vcxproj.filters	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Core/Core.vcxproj.filters	Mon Nov 21 17:38:34 2011	(r1696)
@@ -58,6 +58,9 @@
     <ClCompile Include="StdAfx.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="CoreDictionaryAttributeValue.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="CoreBinFile.rgs">
@@ -136,5 +139,8 @@
     <ClInclude Include="targetver.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="CoreDictionaryAttributeValue.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file

Modified: trunk/GME/Core/CoreAttribute.cpp
==============================================================================
--- trunk/GME/Core/CoreAttribute.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Core/CoreAttribute.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -45,6 +45,7 @@
 typedef CCoreDataAttribute<CCoreDataAttrBase<CComBstrObj>, VALTYPE_STRING> CCoreStringAttribute;
 typedef CCoreDataAttribute<CCoreDataAttrBase<bindata>, VALTYPE_BINARY> CCoreBinaryAttribute;
 typedef CCoreDataAttribute<CCoreDataAttrBase<double>, VALTYPE_REAL> CCoreRealAttribute;
+typedef CCoreDataAttribute<CCoreDataAttrBase<CComPtr<CCoreDictionaryAttributeValue>>, VALTYPE_DICT> CCoreDictAttribute;
 
 void CCoreAttribute::Create(CCoreObject *object, CCoreMetaAttribute *metaattribute)
 {
@@ -88,6 +89,17 @@
 			break;
 		}
 
+		case VALTYPE_DICT:
+		{
+			typedef CComPartObject< CCoreDictAttribute > COMTYPE;
+
+			COMTYPE *p = NULL;
+			COMTHROW( COMTYPE::CreateInstance(CastToUnknown(object), &p) );
+			attribute = p;
+
+			break;
+		}
+
 	case VALTYPE_STRING:
 		{
 			typedef CComPartObject< CCoreStringAttribute > COMTYPE;
@@ -819,13 +831,36 @@
 	CopyTo(v, values.front());
 }
 
+template<>
+inline void CCoreDataAttrBase<CComPtr<CCoreDictionaryAttributeValue>>::ChangeFrontValue(VARIANT &v)
+{
+	ASSERT( values.size() >= 2 );
+}
+
+
+template<class DATA>
+DATA CCoreDataAttrBase<DATA>::CreateValue()
+{
+	return value_type();
+}
+
+template<>
+CComPtr<CCoreDictionaryAttributeValue> CCoreDataAttrBase<CComPtr<CCoreDictionaryAttributeValue>>::CreateValue()
+{
+	CCoreDictionaryAttributeValue *val = NULL;
+	typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE;
+	// FIXME: is this necessary?
+	COMTHROW( COMTYPE::CreateInstance((COMTYPE **)&val) );
+	return CComPtr<CCoreDictionaryAttributeValue>(val);
+}
+
 template<class DATA>
 void CCoreDataAttrBase<DATA>::InsertFrontValue(VARIANT &v)
 {
 	if( limited_size(values, 2) == 1 )
 	{
 		LockSelfTry();
-		values.push_front(value_type());
+		values.push_front(CreateValue());
 		try
 		{
 			CopyTo(v, values.front());
@@ -840,7 +875,7 @@
 	}
 	else
 	{
-		values.push_front(value_type());
+		values.push_front(CreateValue());
 		try
 		{
 			CopyTo(v, values.front());

Modified: trunk/GME/Core/CoreAttribute.h
==============================================================================
--- trunk/GME/Core/CoreAttribute.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Core/CoreAttribute.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -7,6 +7,7 @@
 #include "CoreTransactionItem.h"
 #include "CoreMetaAttribute.h"
 #include "CoreObject.h"
+#include "CoreDictionaryAttributeValue.h"
 
 #include <list>
 #include <set>
@@ -252,6 +253,7 @@
 
 public:
 	void ChangeFrontValue(VARIANT &v);
+	DATA CreateValue();
 	void InsertFrontValue(VARIANT &v);
 
 	void SpliceValue(values_iterator before, values_iterator pos) NOTHROW;

Modified: trunk/GME/Core/CoreBinFile.cpp
==============================================================================
--- trunk/GME/Core/CoreBinFile.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Core/CoreBinFile.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -44,6 +44,9 @@
 		binattr = new ((void*)(&attr)) BinAttr<VALTYPE_COLLECTION>;
 		break;
 
+	case VALTYPE_DICT:
+		binattr = new ((void*)(&attr)) BinAttr<VALTYPE_DICT>;
+		break;
 	case VALTYPE_REAL:
 		binattr = new ((void*)(&attr)) BinAttr<VALTYPE_REAL>;
 		break;
@@ -79,7 +82,70 @@
 	*p_l4 = (((((t_guid.Data4[4] << 8) + t_guid.Data4[5]) << 8) + t_guid.Data4[6]) << 8) + t_guid.Data4[7];
 }
 
-bool BinObject::HasGuidAndStatAttributes( bool* p_guidFound, bool* p_statusFound)
+void WalkRegistry(CCoreDictionaryAttributeValue::map_type& map, CComBSTR& path, CCoreBinFile* p_bf, BinObject& node)
+{
+	binattrs_iterator i = node.binattrs.begin();
+	binattrs_iterator e = node.binattrs.end();
+	while( i != e)
+	{
+		if( i->attrid == ATTRID_REGNOWNER + ATTRID_COLLECTION) {
+			// Copy, since we're going to remove from it
+			std::vector<objects_iterator> a = ((BinAttr<VALTYPE_COLLECTION>*)(void*)&(*i))->a;
+			for (auto it = a.begin(); it != a.end(); it++)
+			{
+				objects_type::iterator regnode = p_bf->objects.find((*it)->first);
+				if (regnode == p_bf->objects.end())
+					throw E_BINFILE;
+
+				CComVariant name;
+				regnode->second.Find(ATTRID_NAME)->Get(p_bf, &name);
+#define RFLAG_HASVALUE 1
+#define RFLAG_OPAQUE 2
+				CComVariant flag;
+				regnode->second.Find(ATTRID_REGFLAGS)->Get(p_bf, &flag);
+
+				CComBSTR newPath(path);
+				if (path != L"")
+					newPath += L"/";
+				newPath += name.bstrVal;
+				if (flag.intVal & RFLAG_HASVALUE) {
+					CComVariant value;
+					regnode->second.Find(ATTRID_REGNODEVALUE)->Get(p_bf, &value);
+					map[newPath] = CComBSTR(value.bstrVal);
+				}
+				WalkRegistry(map, newPath, p_bf, regnode->second);
+				p_bf->opened_object = regnode;
+				regnode->second.Find(ATTRID_REGNOWNER)->Set(p_bf, CComVariant());
+			}
+			return;
+		}
+		++i;
+	}
+}
+
+void BinObject::UpgradeRegistryIfNecessary(CCoreBinFile* p_bf)
+{
+	binattrs_iterator i = binattrs.begin();
+	binattrs_iterator e = binattrs.end();
+	while( i != e)
+	{
+		if( i->attrid == ATTRID_REGNOWNER + ATTRID_COLLECTION) {
+			CCoreDictionaryAttributeValue::map_type map;
+			
+			WalkRegistry(map, CComBSTR(), p_bf, *this);
+
+			BinAttrBase::Create(*i, VALTYPE_DICT);
+			i->attrid = ATTRID_REGNODE;
+			CComVariant dict;
+			i->Get(p_bf, &dict);
+			((CCoreDictionaryAttributeValue*)dict.pdispVal)->m_dict = map;
+			return;
+		}
+		++i;
+	}
+}
+
+bool BinObject::HasGuidAndStatAttributes( bool* p_guidFound, bool* p_statusFound, bool* p_oldRegFound)
 {
 	int a1( 0), a2( 0), a3( 0), a4( 0);
 
@@ -94,6 +160,8 @@
 			case ATTRID_GUID3: ++a3;break;
 			case ATTRID_GUID4: ++a4;break;
 			case ATTRID_FILESTATUS: *p_statusFound = true; break;
+			case ATTRID_REGNOWNER + ATTRID_COLLECTION:
+				*p_oldRegFound = true; break;
 		};
 
 		++i;
@@ -232,6 +300,7 @@
 			{ int len; binfile->read(len); binfile->cifs += len; } // FIXME maybe cifs > cifs_eof
 			break;
 
+		case VALTYPE_DICT:
 		case VALTYPE_BINARY:
 			{ int len; binfile->read(len); binfile->cifs += len; } // FIXME maybe cifs > cifs_eof
 			break;
@@ -965,6 +1034,7 @@
 		HR_THROW(E_PROJECT_MISMATCH);
 
 	ASSERT( resolvelist.empty() );
+	bool oldReg_found = false;
 
 	for(;;)
 	{
@@ -1001,7 +1071,7 @@
 		{
 			bool stat_found( false), guid_found( false);
 
-			opened_object->second.HasGuidAndStatAttributes( &guid_found, &stat_found);
+			opened_object->second.HasGuidAndStatAttributes( &guid_found, &stat_found, &oldReg_found);
 
 			if( !guid_found) // we will create guid attributes for it
 				opened_object->second.CreateGuidAttributes( this);
@@ -1037,6 +1107,23 @@
 	isEmpty = true;
 	resolvelist.clear();
 
+	if (oldReg_found) {
+		for (auto it = objects.begin(); it != objects.end(); it++)
+		{
+			if (it->first.metaid >= DTID_MODEL && it->first.metaid <= DTID_FOLDER)	// 101 .. 106
+			{
+				it->second.UpgradeRegistryIfNecessary(this);
+			}
+		}
+		for (auto it = objects.begin(); it != objects.end(); )
+		{
+			if (it->first.metaid == DTID_REGNODE)
+				objects.erase(it++);
+			else
+				it++;
+		}
+	}
+
 	ofs.clear();
 	  // FIXME: set read_only correctly
 	read_only = false;

Modified: trunk/GME/Core/CoreBinFile.h
==============================================================================
--- trunk/GME/Core/CoreBinFile.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Core/CoreBinFile.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -2,6 +2,8 @@
 #ifndef MGA_COREBINFILE_H
 #define MGA_COREBINFILE_H
 
+#include "CoreDictionaryAttributeValue.h"
+
 #include <fstream>//fstream.h
 #include <list>//slist
 #include <map>
@@ -143,9 +145,10 @@
 	binattrs_type binattrs;
 	bool deleted;
 
-	bool HasGuidAndStatAttributes( bool* p_guidFound, bool* p_statusFound);
+	bool HasGuidAndStatAttributes( bool* p_guidFound, bool* p_statusFound, bool* p_oldRegFound);
 	void CreateGuidAttributes( CCoreBinFile* p_bf);
 	void CreateStatusAttribute( CCoreBinFile* p_bf);
+	void UpgradeRegistryIfNecessary(CCoreBinFile* binFile);
 
 	BinAttrBase *Find(attrid_type attrid)
 	{
@@ -266,6 +269,9 @@
 	void write(const CComBstrObj &a);
 	void write(const bindata &a);
 	void write(const unsigned char* a, int len);
+	void write(const wchar_t* a, int len) {
+		write((const unsigned char*)a, len * sizeof(wchar_t));
+	}
 	void writestring(const char* pos);
 // ------- Attribute
 
@@ -522,6 +528,107 @@
 	}
 };
 
+// --------------------------- BinAttr<VALTYPE_DICT>
+
+template<>
+class BinAttr<VALTYPE_DICT> : public BinAttrBase
+{
+public:
+	BinAttr() : data(0) {
+		CCoreDictionaryAttributeValue *val = NULL;
+		typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE;
+		HRESULT hr = COMTYPE::CreateInstance((COMTYPE **)&val);
+		COMTHROW(hr);
+		dict = val;
+	}
+	virtual ~BinAttr() { }
+
+	char* data;
+	// memcpy: if lazy read, data is not guaranteed to be properly aligned for int*
+	int read_len(char*& offset) const { int ret; memcpy(&ret, offset, sizeof(int)); offset += sizeof(int); return ret; }
+
+	CComPtr<ICoreDictionaryAttributeValue> dict;
+
+	virtual valtype_type GetValType() const NOTHROW { return VALTYPE_DICT; }
+	virtual void Set(CCoreBinFile *binfile, VARIANT v)
+	{
+		ASSERT( binfile != NULL );
+		ASSERT(v.vt = VT_DISPATCH);
+		binfile->modified = true;
+		dict = 0;
+		v.pdispVal->QueryInterface(&dict);
+	}
+
+	virtual void Get(CCoreBinFile *binfile, VARIANT *p) const {
+		if (dict == 0) {
+			// lazy read
+			CCoreDictionaryAttributeValue* val = NULL;
+			typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE;
+			HRESULT hr = COMTYPE::CreateInstance((COMTYPE **)&val);
+			COMTHROW(hr);
+
+			char* data = this->data;
+			int size = read_len(data);
+			while (data < this->data + size)
+			{
+				int keysize = read_len(data);
+				CComBSTR key(keysize / sizeof(wchar_t));
+				memcpy(key.m_str, data, keysize);
+				data += keysize;
+				int valuesize = read_len(data);
+				CComBSTR value(valuesize / sizeof(wchar_t));
+				memcpy(value.m_str, data, valuesize);
+				data += valuesize;
+				val->m_dict.emplace(
+					std::unordered_map<CComBSTR, CComBSTR, CComBSTR_Length>::value_type(std::move(key), std::move(value)));
+			}
+
+			BinAttr<VALTYPE_DICT>* _this = const_cast<BinAttr<VALTYPE_DICT>*>(this);
+			_this->dict = val;
+			_this->data = 0;
+		}
+		CComVariant ret = dict;
+		COMTHROW(ret.Detach(p));
+	}
+	virtual void Write(CCoreBinFile *binfile) const {
+		int size = 0;
+
+		if (dict == NULL)
+		{
+			// need to read before write
+			// TODO: could just blit it
+			CComVariant p;
+			Get(binfile, &p);
+		}
+
+		const CCoreDictionaryAttributeValue* cdict = (const CCoreDictionaryAttributeValue*)(const ICoreDictionaryAttributeValue*)dict;
+		for (auto it = cdict->m_dict.begin(); it != cdict->m_dict.end(); it++) {
+			size += sizeof(int);
+			size += it->first.Length() * sizeof(wchar_t);
+			size += sizeof(int);
+			size += it->second.Length() * sizeof(wchar_t);
+		}
+		binfile->write(size);
+
+		for (auto it = cdict->m_dict.begin(); it != cdict->m_dict.end(); it++) {
+			// binfile->write((int)it->first.Length());
+			binfile->write(it->first, it->first.Length());
+			// binfile->write((int)it->second.Length());
+			binfile->write(it->second, it->second.Length());
+		}
+	}
+	virtual void Read(CCoreBinFile *binfile) { 
+		dict = 0;
+		data = (char*)binfile->cifs;
+		int len = read_len(binfile->cifs);
+		binfile->cifs += len;
+	}
+	BinAttr(BinAttr<VALTYPE_DICT>&& that) : BinAttrBase(that.attrid), data(that.data), dict(std::move(that.dict)) { }
+	virtual void move(BinAttrUnion&& dest) {
+		new (&dest) BinAttr<VALTYPE_DICT>(std::move(*this));
+	}
+};
+
 // --------------------------- BinAttr<VALTYPE_LOCK>
 
 template<>

Added: trunk/GME/Core/CoreDictionaryAttributeValue.cpp
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/GME/Core/CoreDictionaryAttributeValue.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -0,0 +1,29 @@
+#include "StdAfx.h"
+
+#include "CoreDictionaryAttributeValue.h"
+
+STDMETHODIMP CCoreDictionaryAttributeValue::put_Value(BSTR Key, BSTR Value)
+{
+COMTRY {
+	m_dict[CComBSTR(Key)] = CComBSTR(Value);
+} COMCATCH(;)
+}
+STDMETHODIMP CCoreDictionaryAttributeValue::get_Value(BSTR Key, BSTR* Value)
+{
+COMTRY {
+	CComBSTR _key;
+	_key.Attach(Key);
+	auto ent = m_dict.find(_key);
+	_key.Detach();
+	if (ent == m_dict.end())
+		return E_NOTFOUND;
+	*Value = CComBSTR(ent->second).Detach();
+} COMCATCH(;)
+}
+
+STDMETHODIMP CCoreDictionaryAttributeValue::get_Keys(VARIANT* Keys)
+{
+COMTRY {
+	return E_NOTIMPL;
+} COMCATCH(;)
+}

Added: trunk/GME/Core/CoreDictionaryAttributeValue.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/GME/Core/CoreDictionaryAttributeValue.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -0,0 +1,71 @@
+#pragma once
+
+#include "StdAfx.h"
+
+#include <unordered_map>
+
+struct CComBSTR_Length {
+	::std::size_t operator ()(const CComBSTR& bstr) const {
+		return bstr.Length();
+	}
+};
+
+class ATL_NO_VTABLE CCoreDictionaryAttributeValue :
+	public CComObjectRootEx<CComSingleThreadModel>,
+	public IDispatchImpl<ICoreDictionaryAttributeValue, &IID_ICoreDictionaryAttributeValue, &LIBID_MGACoreLib>
+{
+public:
+	CCoreDictionaryAttributeValue() {}
+	~CCoreDictionaryAttributeValue() {}
+
+//DECLARE_REGISTRY_RESOURCEID(IDR_)
+//DECLARE_PROTECT_FINAL_CONSTRUCT()
+//	DECLARE_INTERFACE
+
+BEGIN_COM_MAP(CCoreDictionaryAttributeValue)
+	COM_INTERFACE_ENTRY(ICoreDictionaryAttributeValue)
+	COM_INTERFACE_ENTRY(IDispatch)
+END_COM_MAP()
+
+public:
+	STDMETHOD(put_Value)(BSTR Key, BSTR Value);
+	STDMETHOD(get_Value)(BSTR Key, BSTR* Value);
+	STDMETHOD(get_Keys)(VARIANT* Keys);
+	STDMETHOD(get_Map)(VARIANT* Map) {
+		Map->vt = VT_I8;
+		Map->llVal = (size_t)(void*)&m_dict;
+		return S_OK;
+	}
+
+	STDMETHOD(put_Map)(VARIANT Map) {
+		m_dict = std::move(*(map_type*)(void*)(size_t)Map.llVal);
+		return S_OK;
+	}
+
+	STDMETHOD(Clone)(ICoreDictionaryAttributeValue** Clone)
+	{
+		CCoreDictionaryAttributeValue* out;
+		typedef CComObject< CCoreDictionaryAttributeValue > COMTYPE;
+		HRESULT hr = COMTYPE::CreateInstance((COMTYPE **)&out);
+		if (SUCCEEDED(hr))
+		{
+			out->AddRef();
+			out->m_dict = this->m_dict;
+			*Clone = out;
+		}
+		return hr;
+	}
+
+	typedef std::unordered_map<CComBSTR, CComBSTR, CComBSTR_Length> map_type;
+	map_type m_dict;
+};
+
+static void CopyTo(const VARIANT& from, CComPtr<CCoreDictionaryAttributeValue>& to)
+{
+	if (from.vt == VT_DISPATCH) {
+		to = 0;
+		CComPtr<ICoreDictionaryAttributeValue> fro;
+		COMTHROW(from.pdispVal->QueryInterface(&fro));
+		COMTHROW(fro->Clone((ICoreDictionaryAttributeValue**)&to));
+	}
+}

Modified: trunk/GME/Interfaces/Core.idl
==============================================================================
--- trunk/GME/Interfaces/Core.idl	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Interfaces/Core.idl	Mon Nov 21 17:38:34 2011	(r1696)
@@ -85,8 +85,9 @@
 	[helpstring("Real (double precision)")] 
 	VALTYPE_REAL = 7,
 
+	VALTYPE_DICT = 8,
 	[helpstring("Last value type")] 
-	VALTYPE_MAX = 7
+	VALTYPE_MAX = 8,
 } valtype_enum;
 
 typedef enum transtype_enum
@@ -597,4 +598,30 @@
 	HRESULT version([out, retval] GMEInterfaceVersion_enum *pVal);
 };
 
+[
+	object,
+	uuid(FAB8C11E-747A-45A5-BF05-1A8FB353B03B),
+	dual,
+	pointer_default(unique)
+]
+interface ICoreDictionaryAttributeValue : IDispatch
+{
+	[propget, id(DISPID_VALUE)]
+	HRESULT Value([in] BSTR Key, [out, retval] BSTR *Value);
+
+	[propput, id(DISPID_VALUE)]
+	HRESULT Value([in] BSTR Key, [in] BSTR Value);
+
+	[propget]
+	HRESULT Keys([out, retval] VARIANT *Keys);
+
+	[propget]
+	HRESULT Map([out, retval] VARIANT* Map);
+
+	[propput]
+	HRESULT Map([in] VARIANT Map);
+
+	HRESULT Clone([out] ICoreDictionaryAttributeValue** Clone);
+};
+
 //-------------------------------------------------------------------------------
\ No newline at end of file

Modified: trunk/GME/Mga/Mga.vcxproj
==============================================================================
--- trunk/GME/Mga/Mga.vcxproj	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/Mga.vcxproj	Mon Nov 21 17:38:34 2011	(r1696)
@@ -176,7 +176,7 @@
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
       <PrecompiledHeader>Use</PrecompiledHeader>
-      <WarningLevel>Level4</WarningLevel>
+      <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
     </ClCompile>
     <ResourceCompile>

Modified: trunk/GME/Mga/MgaAttribute.cpp
==============================================================================
--- trunk/GME/Mga/MgaAttribute.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaAttribute.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -3,6 +3,12 @@
 #include "MgaAttribute.h"
 #include "MgaFCO.h"
 
+#include "atlsafe.h"
+
+#include <unordered_map>
+
+#include "Core.h"
+
 /////////////////////////////////////////////////////////////////////////////
 // CMgaAttribute
 
@@ -456,20 +462,6 @@
 /////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
-#define RFLAG_HASVALUE 1
-#define RFLAG_OPAQUE 2
-
-
-// THROWS!!!
-// RECURSIVE!!!
-void RegistryChildrenRemove(CoreObj &t) {
-		CoreObjs children = CoreObj(t)[ATTRID_REGNOWNER + ATTRID_COLLECTION];
-		ITERATE_THROUGH(children) {
-			RegistryChildrenRemove(ITER);
-			COMTHROW(ITER->Delete());
-		}
-}
-
 
 // THROWS!!!
 // RECURSIVE!!!
@@ -479,77 +471,40 @@
 // If dst node is opaque, src is not copied and recursion also stops.
 
 void MergeRegs(const CoreObj &src, CoreObj &dst) {
-	CoreObjs dstcoll = dst[ATTRID_REGNOWNER+ATTRID_COLLECTION];
-	ITERATE_THROUGH(src[ATTRID_REGNOWNER+ATTRID_COLLECTION]) {
-		CoreObj &srcn = ITER;
-		CoreObj dstn;
-		CComBSTR srcname = srcn[ATTRID_NAME];
-		long dstflags, srcflags = ITER[ATTRID_REGFLAGS];
-		ITERATE_THROUGH(dstcoll) {
-			if(srcname == CComBSTR(ITER[ATTRID_NAME])) {
-				dstn = ITER;
-				break;
-			}
-		}
-		if(!dstn) {
-			CComPtr<ICoreProject> p;
-			COMTHROW(dst->get_Project(&p));
-			COMTHROW(p->CreateObject(DTID_REGNODE, &dstn.ComPtr()));
-			dstn[ATTRID_NAME] = srcn[ATTRID_NAME];
-			dstn[ATTRID_REGNOWNER] = dst;
-			dstflags = 0;
-		}
-		else dstflags = ITER[ATTRID_REGFLAGS];
-		if(!(dstflags & RFLAG_OPAQUE)) {
-			if(!(dstflags & RFLAG_HASVALUE) && (srcflags & RFLAG_HASVALUE)) {
-				dstn[ATTRID_REGNODEVALUE] = srcn[ATTRID_REGNODEVALUE];
-				dstn[ATTRID_XREF] = srcn[ATTRID_XREF];
-			}
-			dstn[ATTRID_REGFLAGS] = dstflags | srcflags;
-			MergeRegs(srcn, dstn);
-		}
+	{
+		// KMS: need to set ATTRID_REGNODE for write ops
+		CComVariant attr = dst[ATTRID_REGNODE];
+		dst[ATTRID_REGNODE] = attr;
 	}
-}
 
+	CComVariant attr = dst[ATTRID_REGNODE];
+	CComPtr<ICoreDictionaryAttributeValue> dictval;
+	COMTHROW(attr.pdispVal->QueryInterface(&dictval));
+	VARIANT vmap;
+	COMTHROW(dictval->get_Map(&vmap));
+	CMgaRegNode::map_type* map = (CMgaRegNode::map_type*)(void*)vmap.llVal;
+
+	CoreObj s = src;
+	do {
+		CComVariant sattr = s[ATTRID_REGNODE];
+		CComPtr<ICoreDictionaryAttributeValue> sdictval;
+		COMTHROW(sattr.pdispVal->QueryInterface(&sdictval));
+		VARIANT svmap;
+		COMTHROW(sdictval->get_Map(&svmap));
+		CMgaRegNode::map_type* smap = (CMgaRegNode::map_type*)(void*)svmap.llVal;
 
-// throws
-CoreObj findregvalueobj(CoreObj &cur, LPOLESTR bstrObname, long &opacity, bool create) {  //returns NULL if not found
-	wchar_t* obname = bstrObname;
-	if (obname == NULL) obname = L"";
-	ASSERT(*obname != '/');
-	LPOLESTR endstr = wcschr(obname,'/');
-	size_t len = endstr ? endstr - obname : wcslen(obname);
-	CoreObjs snodes = cur[ATTRID_REGNOWNER+ATTRID_COLLECTION];
-	ITERATE_THROUGH(snodes) {
-		CComBSTR nm = ITER[ATTRID_NAME];
-		if(nm.Length()==len && wcsncmp(nm,obname, len) == 0) {
-			opacity |= (long)ITER[ATTRID_REGFLAGS];
-			if(!endstr) {
-				return ITER;
-			}
-			return findregvalueobj(ITER, endstr +1, opacity, create);
-		}
-	}
-	if(create) {
-		CComPtr<ICoreProject> p;
-		COMTHROW(cur->get_Project(&p));
-		CoreObj nob;
-		COMTHROW(p->CreateObject(DTID_REGNODE, &nob.ComPtr()));
+		for (auto it = smap->begin(); it != smap->end(); it++)
 		{
-			LPOLESTR z = new OLECHAR[len+1];
-			wcsncpy(z, obname, len);
-			z[len] = '\0';
-			nob[ATTRID_NAME] = z;
-			delete[] z;
+			if (map->find(it->first) == map->end())
+			{
+				map->insert(CMgaRegNode::map_type::value_type(it->first, it->second));
+			}
 		}
-		nob[ATTRID_REGFLAGS] = 0; 
-		nob[ATTRID_REGNOWNER] =  cur;
-		if(!endstr) return nob;
-		return findregvalueobj(nob, endstr +1, opacity, create);
-	}
-	return NULLCOREOBJ;
-}
 
+		if (!s.IsFCO())
+			break;
+	} while (s = s[ATTRID_DERIVED]);
+}
 
 class regnotifytask : public DeriveTreeTask {
 	bool Do(CoreObj self, std::vector<CoreObj> *peers = NULL) {
@@ -559,6 +514,66 @@
 };
 
 
+template<class F>
+void CMgaRegNode::WalkKeyValues(CoreObj& obj, F& f, long status, bool& continue_)
+{
+	CComVariant attr = obj[ATTRID_REGNODE];
+	CComPtr<ICoreDictionaryAttributeValue> oldval;
+	COMTHROW(attr.pdispVal->QueryInterface(&oldval));
+	VARIANT vmap;
+	COMTHROW(oldval->get_Map(&vmap));
+	map_type* map = (map_type*)(void*)vmap.llVal;
+
+	for (auto it = map->begin(); it != map->end(); it++)
+	{
+		f(*map, it, status, continue_);
+	}
+}
+
+template<class F>
+void CMgaRegNode::WalkKeyValuesInher(F& f)
+{
+	bool continue_ = true;
+	CoreObj s = fco->self;
+	long status = ATTSTATUS_HERE;
+	do {
+		WalkKeyValues(s, f, status, continue_);
+		status = min(ATTSTATUS_IN_ARCHETYPE4, status + 1);
+		if (!continue_)
+			break;
+		if (!s.IsFCO())
+			break;
+	} while (s = s[ATTRID_DERIVED]);
+}
+
+void CMgaRegNode::SetValue(const wchar_t* path, const wchar_t* value)
+{
+	{
+		// KMS: need to set ATTRID_REGNODE for write ops
+		CComVariant attr = fco->self[ATTRID_REGNODE];
+		fco->self[ATTRID_REGNODE] = attr;
+	}
+
+	CComVariant attr = fco->self[ATTRID_REGNODE];
+	CComPtr<ICoreDictionaryAttributeValue> oldval;
+	COMTHROW(attr.pdispVal->QueryInterface(&oldval));
+
+	CComPtr<ICoreDictionaryAttributeValue> newval = oldval;
+	//COMTHROW(oldval->Clone(&newval));
+	VARIANT vmap;
+	COMTHROW(newval->get_Map(&vmap));
+	map_type* map = (map_type*)(void*)vmap.llVal;
+
+	if (value == NULL_SENTINEL) {
+		auto ent = map->find(CComBSTR(path));
+		if (ent != map->end())
+			map->erase(ent);
+	} else
+		(*map)[CComBSTR(path)] = CComBSTR(value);
+}
+
+const wchar_t* CMgaRegNode::NULL_SENTINEL = (const wchar_t*) "\0xFF\0xFE\0";
+
 
 void CMgaRegNode::markchg() {
 	regnotifytask().DoWithDeriveds(fco->self);
@@ -569,7 +584,7 @@
 
 
 STDMETHODIMP CMgaRegNode::get_Object( IMgaObject **pVal) {  
-	COMTRY { 
+	COMTRY {
 		CHECK_OUTPTRPAR(pVal);
 		IMgaFCO *p;
 		fco->getinterface(&p); 
@@ -582,11 +597,45 @@
 			fco->CheckRead();
 			CHECK_OUTPAR(status);
 
-			if(load_status == ATTSTATUS_INVALID) {
-				CComBSTR v;
-				COMTHROW(get_Value(&v));
+			*status = ATTSTATUS_UNDEFINED;
+			CoreObj s = fco->self;
+			long _status = ATTSTATUS_HERE;
+			do {
+				CComVariant attr = s[ATTRID_REGNODE];
+				CComPtr<ICoreDictionaryAttributeValue> oldval;
+				COMTHROW(attr.pdispVal->QueryInterface(&oldval));
+
+				CComPtr<ICoreDictionaryAttributeValue> newval = oldval;
+				VARIANT vmap;
+				COMTHROW(newval->get_Map(&vmap));
+				map_type* map = (map_type*)(void*)vmap.llVal;
+				if (map->find(mypath) != map->end())
+				{
+					*status = _status;
+					return S_OK;
+				}
+
+				_status = min(ATTSTATUS_IN_ARCHETYPE4, _status + 1);
+				if (!s.IsFCO())
+					break;
+			} while (s = s[ATTRID_DERIVED]);
+
+			metaref_type mref = fco->self[ATTRID_META];
+			if(mref) {
+				CComQIPtr<IMgaMetaBase> m(mgaproject->FindMetaRef(mref));
+				CComPtr<IMgaMetaRegNode> rn;
+				HRESULT hr = m->get_RegistryNode(mypath, &rn);
+				if (hr == E_NOTFOUND) {
+					*status = ATTSTATUS_UNDEFINED;
+				}
+				else if (SUCCEEDED(hr)) {
+					*status = ATTSTATUS_METADEFAULT;
+				}
+				else if(hr != E_NOTFOUND)
+					COMTHROW(hr);
 			}
-			*status = load_status;
+
+			return S_OK;
 		} COMCATCH(;)
 }
 
@@ -594,55 +643,38 @@
 STDMETHODIMP CMgaRegNode::get_Value(BSTR *pVal) {
 		COMTRY {
 			CHECK_OUTVARIANTPAR(pVal);
-			fco->CheckRead();
-			CComVariant var;
-			long opacity = 0;
-			if(load_status == ATTSTATUS_INVALID) {
-				long ls = ATTSTATUS_HERE;
-				CoreObj cur = fco->self;
-				valueobj = NULL;
-				while(cur) {
-					valueobj <<= findregvalueobj(cur, mypath, opacity, false);
-					if(valueobj != NULL) {
-					   long flags = valueobj[ATTRID_REGFLAGS];
-					   if(flags & RFLAG_HASVALUE) {
-  							load_status = ls;
-							break;				// breaks here with >= HERE 
-					   }
-					}
-					if((opacity & RFLAG_OPAQUE) != 0) {  // opaque node hit.
-						load_status = ATTSTATUS_UNDEFINED;
-						break;
-					}
-					CComPtr<ICoreMetaObject> mo;
-					if(GetMetaID(cur) == DTID_FOLDER) break;  // folders do not inherit
-					cur = cur[ATTRID_DERIVED];
-					ls++;
-				}
-			}
 
-			if(load_status >= ATTSTATUS_HERE) {
-				*pVal = CComBSTR(valueobj[ATTRID_REGNODEVALUE]).Detach();
-			}
-			else if(load_status != ATTSTATUS_UNDEFINED) {    // INVALID || INMETA
-				load_status = ATTSTATUS_UNDEFINED;
-				metaref_type mref = fco->self[ATTRID_META];
-				if(mref) {
-					CComQIPtr<IMgaMetaBase> m(mgaproject->FindMetaRef(mref));
-					CComPtr<IMgaMetaRegNode> rn;
-					HRESULT hr = m->get_RegistryNode(mypath, &rn);
-					if(hr == S_OK) {
-						load_status = ATTSTATUS_METADEFAULT;
-						COMTHROW(rn->get_Value( pVal));
-					}
-					else if(hr != E_NOTFOUND) COMTHROW(hr);
+			CoreObj s = fco->self;
+			do {
+				CComVariant attr = s[ATTRID_REGNODE];
+				CComPtr<ICoreDictionaryAttributeValue> dict;
+				COMTHROW(attr.pdispVal->QueryInterface(&dict));
+				VARIANT vmap;
+				COMTHROW(dict->get_Map(&vmap));
+				map_type* map = (map_type*)(void*)vmap.llVal;
+
+				map_type::iterator it = map->find(mypath);
+				if (it != map->end()) {
+					*pVal = CComBSTR(it->second).Detach();
+					return S_OK;
+				}
+				if (!s.IsFCO())
+					break;
+			} while (s = s[ATTRID_DERIVED]);
+
+			metaref_type mref = fco->self[ATTRID_META];
+			if(mref) {
+				CComQIPtr<IMgaMetaBase> m(mgaproject->FindMetaRef(mref));
+				CComPtr<IMgaMetaRegNode> rn;
+				HRESULT hr = m->get_RegistryNode(mypath, &rn);
+				if(hr == S_OK) {
+					COMTHROW(rn->get_Value(pVal));
+					return S_OK;
 				}
+				else if(hr != E_NOTFOUND)
+					COMTHROW(hr);
 			}
-			if(load_status == ATTSTATUS_UNDEFINED) {
-				// n.b. this is a fancy way of saying *pVal = NULL;
-				// FIXME: *pVal is NULL here and we return S_OK
-				CComBSTR x;   *pVal = x.Detach();
-			}
+			*pVal = NULL;
 
 		} COMCATCH(;)
 }
@@ -652,16 +684,7 @@
 			fco->CheckRead();
 			CHECK_OUTPTRPAR(pVal);
 
-			if(load_status == ATTSTATUS_INVALID) {
-				CComBSTR v;
-				COMTHROW(get_Value(&v));
-			}
-			if(load_status >= ATTSTATUS_HERE) {
-				CoreObj v = valueobj[ATTRID_XREF];
-				if(v) {
-					ObjForCore(v)->getinterface(pVal);
-				}
-			}
+			fco->getinterface(pVal);
 		} COMCATCH(;)
 }
 
@@ -670,61 +693,33 @@
 			fco->CheckRead();
 			CHECK_OUTPAR(pVal)
 			*pVal = VARIANT_FALSE;
-			long opa;
-			CoreObj vobj;
-			vobj <<= findregvalueobj(fco->self, mypath, opa, false);
-			if(vobj) {
-				long flags = vobj[ATTRID_REGFLAGS];
-				if(flags & ~RFLAG_OPAQUE) 
-					*pVal = VARIANT_TRUE;
-			}
 		} COMCATCH(;);
 }
 
 STDMETHODIMP CMgaRegNode::put_Opacity( VARIANT_BOOL newVal) {
+	return S_OK;
+	return E_NOTIMPL;
 		COMTRY_IN_TRANSACTION {
 			fco->CheckWrite();
 			CHECK_INPAR(newVal);
-			long opa;
-			CoreObj vobj;
-			vobj <<= findregvalueobj(fco->self, mypath, opa, true);
-			long newmask = newVal ? RFLAG_OPAQUE : 0;
-			long flags = vobj[ATTRID_REGFLAGS];
-			if((flags & RFLAG_OPAQUE) != newmask) {
-				vobj[ATTRID_REGFLAGS] = (flags & ~RFLAG_OPAQUE) | newmask;
-				if(load_status != ATTSTATUS_HERE) load_status = ATTSTATUS_INVALID;
-				markchg();
-			}
 		} COMCATCH_IN_TRANSACTION(;);
 }
 
 
 STDMETHODIMP CMgaRegNode::put_Value(BSTR newVal) {
-		COMTRY_IN_TRANSACTION_MAYBE {
+		COMTRY {
 			CHECK_INSTRPAR(newVal);
 			fco->CheckWrite();
-			long dummy;
-			valueobj <<= findregvalueobj(fco->self, mypath, dummy, true);
-			load_status = ATTSTATUS_HERE;
-			valueobj[ATTRID_REGNODEVALUE] = newVal;
-			valueobj[ATTRID_XREF] = NULLCOREOBJ;
-			long flags = valueobj[ATTRID_REGFLAGS];
-			if(!(flags & RFLAG_HASVALUE)) valueobj[ATTRID_REGFLAGS] = flags | RFLAG_HASVALUE;
+			SetValue(mypath, newVal);
 			markchg();
-		} COMCATCH_IN_TRANSACTION_MAYBE(;)
+		} COMCATCH(;)
 }
 
 STDMETHODIMP CMgaRegNode::put_FCOValue(IMgaFCO *newVal) {
+	return E_NOTIMPL;
 		COMTRY_IN_TRANSACTION {
 			CHECK_MYINPTRPAR(newVal);
 			fco->CheckWrite();
-			long dummy;
-			valueobj <<= findregvalueobj(fco->self, mypath, dummy, true);
-			load_status = ATTSTATUS_HERE;
-			valueobj[ATTRID_REGNODEVALUE] = CComBSTR();
-			valueobj[ATTRID_XREF] = CoreObj(newVal);
-			long flags = valueobj[ATTRID_REGFLAGS];
-			if(!(flags & RFLAG_HASVALUE)) valueobj[ATTRID_REGFLAGS] = flags | RFLAG_HASVALUE;
 			markchg();
 		} COMCATCH_IN_TRANSACTION(;)
 }
@@ -733,50 +728,65 @@
 		COMTRY {
 			fco->CheckRead();
 			CHECK_OUTPTRPAR(pVal);
-			long dummy;
-			stdext::hash_set<CComBSTRNoAt, CComBSTR_hashfunc> match;
+
 			CoreObj s = fco->self;
-			if(!s.IsFCO()) virtuals = VARIANT_FALSE;
+			if(!s.IsFCO())
+				virtuals = VARIANT_FALSE;
 			CREATEEXCOLLECTION_FOR(MgaRegNode,q);
-			do {
-				CoreObj vobj;
-				vobj <<= findregvalueobj(s, mypath, dummy, false);
-				if(!vobj)  continue;
-				CoreObjs children = vobj[ATTRID_REGNOWNER+ATTRID_COLLECTION];
-
-				ITERATE_THROUGH(children) {
-					CComBSTR subpath(mypath);
-					COMTHROW(subpath.Append(L"/"));
-					CComBSTR path = ITER[ATTRID_NAME];
-					COMTHROW(subpath.Append(path));
-					if(virtuals) {
-						if(match.find(path) != match.end()) continue;
-						match.insert(path);
+			std::set<std::wstring> paths;
+			WalkKeyValuesInher([&](map_type& map, map_type::iterator& it, int inher, bool& continue_) {
+				if (virtuals == VARIANT_FALSE && inher != ATTSTATUS_HERE)
+				{
+					continue_ = false;
+					return;
+				}
+				if (wcsncmp(it->first, mypath, mypath.Length()) == 0)
+				{
+					std::wstring path = it->first;
+					if (path.length() > mypath.Length())
+					{
+						size_t end = path.find(L'/', mypath.Length() + 1);
+						if (end != std::wstring::npos)
+							path = path.substr(0, end);
+						paths.insert(std::move(path));
 					}
-					q->Add(fco->rpool.getpoolobj(subpath, fco, mgaproject));
 				}
-			} while(virtuals && (s = s[ATTRID_DERIVED]));
+			});
 			if(virtuals) {
 				metaref_type mref = fco->self[ATTRID_META];
 				if(mref) {
 					CComQIPtr<IMgaMetaBase> m(mgaproject->FindMetaRef(mref));
 					CComPtr<IMgaMetaRegNode> rn;
-					HRESULT hr = m->get_RegistryNode(mypath, &rn);
+					HRESULT hr;
+					if (mypath == L"")
+						hr = S_OK;
+					else
+						hr = m->get_RegistryNode(mypath, &rn);
 					CComPtr<IMgaMetaRegNodes> rns;
 					if(hr == S_OK) {
-						COMTHROW(hr = rn->get_RegistryNodes(&rns));
+						if (mypath == L"")
+							COMTHROW(m->get_RegistryNodes(&rns));
+						else
+							COMTHROW(rn->get_RegistryNodes(&rns));
 						MGACOLL_ITERATE(IMgaMetaRegNode, rns) {
 							CComBSTR path;
 							COMTHROW(MGACOLL_ITER->get_Name(&path));
-							if(match.find(path) != match.end()) continue;
 							CComBSTR subpath(mypath);
-							COMTHROW(subpath.Append("/"));
+							if (mypath != L"")
+								COMTHROW(subpath.Append("/"));
 							COMTHROW(subpath.Append(path));
-							q->Add(fco->rpool.getpoolobj(subpath, fco, mgaproject));
+							paths.insert(subpath);
 						} MGACOLL_ITERATE_END;
 					}
 				}
 			}
+			for (std::set<std::wstring>::iterator pathsIt = paths.begin(); pathsIt != paths.end(); pathsIt++)
+			{
+				CComPtr<CMgaRegNode> regnode;
+				CreateComObject(regnode);
+				regnode->Initialize(CComBSTR(pathsIt->c_str()), fco, mgaproject);
+				q->Append(regnode.Detach());
+			}
 			*pVal = q.Detach();
 		} COMCATCH(;)
 }
@@ -812,58 +822,45 @@
 STDMETHODIMP CMgaRegNode::Clear() {
 		COMTRY_IN_TRANSACTION {
 			fco->CheckWrite();
-/*  // old implementation: did not create object if it was not already there
-			long l;
-			COMTHROW(get_Status(&l));
-			if(l == ATTSTATUS_HERE) {
-				long flags = valueobj[ATTRID_REGFLAGS];
-				valueobj[ATTRID_REGFLAGS] = flags & ~RFLAG_HASVALUE;
-				load_status = ATTSTATUS_INVALID;
-				markchg();
-			}
-*/
-			long dummy;
-			valueobj <<= findregvalueobj(fco->self, mypath, dummy, true);
-			valueobj[ATTRID_REGNODEVALUE] = CComBSTR();
-			long flags = valueobj[ATTRID_REGFLAGS];
-			valueobj[ATTRID_REGFLAGS] = flags & ~RFLAG_HASVALUE;
-			load_status = ATTSTATUS_INVALID;
+			SetValue(mypath, NULL_SENTINEL);
+
 			markchg();
 		} COMCATCH_IN_TRANSACTION(;);
 }
 
 STDMETHODIMP CMgaRegNode::RemoveTree() {
-	COMTRY_IN_TRANSACTION {
-			fco->CheckWrite();
-			long dummy;
-			valueobj <<= findregvalueobj(fco->self, mypath, dummy, false);
-			if(valueobj) {
-				// lph: Pre-Notification PRE_STATUS (the registry node is being destroyed)
-				CComBSTR desc = L"REGISTRY,";
-				COMTHROW(desc.Append(mypath));
-				COMTHROW(desc.Append(L",Removed"));
-				fco->PreNotify(OBJEVENT_PRE_STATUS, CComVariant(desc));
-				//--------------------------------------------------------------------------
-				RegistryChildrenRemove(valueobj);
-				COMTHROW(valueobj->Delete());			
-				load_status = ATTSTATUS_INVALID;
-				markchg();
-			}
-	} COMCATCH_IN_TRANSACTION(;);
-}
-
-
-
-
-
-
-
-
-
-
+	COMTRY {
+		fco->CheckWrite();
+		// lph: Pre-Notification PRE_STATUS (the registry node is being destroyed)
+		CComBSTR desc = L"REGISTRY,";
+		COMTHROW(desc.Append(mypath));
+		COMTHROW(desc.Append(L",Removed"));
+		fco->PreNotify(OBJEVENT_PRE_STATUS, CComVariant(desc));
 
+		{
+		// KMS: need to set ATTRID_REGNODE for write ops
+		CComVariant attr = fco->self[ATTRID_REGNODE];
+		fco->self[ATTRID_REGNODE] = attr;
+		}
 
+		CComVariant attr = fco->self[ATTRID_REGNODE];
+		CComPtr<ICoreDictionaryAttributeValue> oldval;
+		COMTHROW(attr.pdispVal->QueryInterface(&oldval));
+		VARIANT vmap;
+		COMTHROW(oldval->get_Map(&vmap));
+		map_type* map = (map_type*)(void*)vmap.llVal;
 
+		for (auto it = map->begin(); it != map->end(); it++)
+		{
+			if (wcsncmp(it->first, mypath, mypath.Length()) == 0)
+			{
+				map->erase(it);
+			}
+		}
+		// TODO
+		markchg();
+	} COMCATCH(;);
+}
 
 
 

Modified: trunk/GME/Mga/MgaAttribute.h
==============================================================================
--- trunk/GME/Mga/MgaAttribute.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaAttribute.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -5,7 +5,15 @@
 
 #include "resource.h"       // main symbols
 
+#include "MgaProject.h"
 
+#include <unordered_map>
+
+struct CComBSTR_Length {
+	::std::size_t operator ()(const CComBSTR& bstr) const {
+		return bstr.Length();
+	}
+};
 
 /////////////////////////////////////////////////////////////////////////////
 // CMgaAttribute
@@ -146,11 +154,11 @@
 // IMgaRegNode
 	void markchg();
 public:
-	STDMETHOD(get_Name)( BSTR *pVal) { 
+	STDMETHOD(get_Name)(BSTR *pVal) { 
 		COMTRY {
 			CHECK_OUTPAR(pVal);
 			LPCOLESTR p = (mypath == NULL ? NULL : wcsrchr(mypath, '/'));
-			if(p) p += 1; // skip '/'
+			if (p) p += 1; // skip '/'
 			else p = mypath;
 			CComBSTR rval(p);
 			*pVal = rval.Detach();
@@ -179,72 +187,32 @@
 	STDMETHOD(Clear)();
 	STDMETHOD(RemoveTree)();
 
-	typedef CMgaRegNode *hashobp;
-	hashobp *prevptr, next;
-	CMgaRegNode()	: prevptr(NULL), next(NULL), load_status(ATTSTATUS_INVALID) {	}
-	~CMgaRegNode() {						// remove object from hash
-		if(next) next->prevptr = prevptr;
-		*prevptr = next;
-	}
-	void Initialize(BSTR path, FCO *o, CMgaProject *p) {   // Throws!!!
-		mypath = path;		
+	CMgaRegNode() { }
+	~CMgaRegNode() { }
+
+	void Initialize(BSTR path, FCO *o, CMgaProject* mgaproject) {
+		mypath = path;
 		fco = o;
-		mgaproject = p;
+		this->mgaproject = mgaproject;
 	}
 
-	long load_status;
-	CoreObj valueobj;
-	FCOPtr fco;
-	CComBSTR mypath;
-	CMgaProject *mgaproject;
-};
-
+	template<class F>
+	void WalkKeyValues(CoreObj& obj, F& f, long status, bool& continue_);
 
-#define RPOOL_HASHSIZE 8
+	template<class F>
+	void WalkKeyValuesInher(F& f);
 
+	void SetValue(const wchar_t* path, const wchar_t* value);
+	const static wchar_t* NULL_SENTINEL;
 
-class regnpool {
-	CMgaRegNode::hashobp pool[RPOOL_HASHSIZE];
-public:
-	regnpool() { 
-		int i; 
-		for(i = 0; i < RPOOL_HASHSIZE;i++) pool[i] = NULL;
-	}
-
-	~regnpool() {
-		int i; 
-		for(i = 0; i < RPOOL_HASHSIZE;i++) ASSERT(pool[i] == NULL);
-	}
-
-	int rpool_hash(BSTR nam) {
-		int i = SysStringLen(nam);
-		int hash = i;
-		while(i) hash ^= nam[--i];
-		return hash % RPOOL_HASHSIZE;
-	}
-
-	// Throws (allocates)!!!!
-	CComPtr<IMgaRegNode>  getpoolobj(BSTR nam, FCO *o, CMgaProject *pr) {
-		CMgaRegNode::hashobp &k = pool[rpool_hash(nam)], *kk;
-		for(kk = &k; *kk != NULL; kk = &((*kk)->next)) {
-			if((*kk)->mypath == nam) {
-				return (*kk);
-			}
-		}
-		CComPtr<CMgaRegNode > s;
-		CreateComObject(s);
-		s->prevptr = &k;				// Insert to the front
-		s->next = k;
-		if(k) k->prevptr = &(s->next);
-		k = s;
+	FCOPtr fco;
+	CComBSTR mypath;
+	CMgaProject* mgaproject;
 
-		s->Initialize(nam, o, pr);  
-		CComPtr<IMgaRegNode> retval = s;
-		return retval;
-	}
+	typedef std::unordered_map<CComBSTR, CComBSTR, CComBSTR_Length> map_type;
 };
 
-void RegistryChildrenRemove(CoreObj &t);
+
 void MergeRegs(const CoreObj &src, CoreObj &dst);
 
 

Modified: trunk/GME/Mga/MgaComplexOps.cpp
==============================================================================
--- trunk/GME/Mga/MgaComplexOps.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaComplexOps.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -122,11 +122,6 @@
 						ITER[ATTRID_XREF] = nil;
 						CoreObjMark(ITER[ATTRID_ATTRPARENT], OBJEVENT_ATTR);
 						break;
-					case DTID_REGNODE:
-// registry REF attribute:  set it to NIL
-						ITER[ATTRID_XREF] = nil;
-						CoreObjMark(ITER[ATTRID_REGNOWNER], OBJEVENT_REGISTRY);
-						break;
 					default:	
 										COMTHROW(E_MGA_META_INCOMPATIBILITY);
 					}
@@ -473,7 +468,7 @@
 			}
 			else {
 				ai -= ATTRID_COLLECTION;
-				if(LINKREF_ATTR(ai) && ai != ATTRID_ATTRPARENT && ai != ATTRID_REGNOWNER) {
+				if(LINKREF_ATTR(ai) && ai != ATTRID_ATTRPARENT) {
 					CoreObjs collmembers = origobj[ai + ATTRID_COLLECTION];
 					ITERATE_THROUGH(collmembers) {
 						CoreObj nchild;
@@ -1643,12 +1638,13 @@
 					case ATTRID_MASTEROBJ:
 					{
 						CoreObj nmas = nobj[ai];
-						if( nobj.IsFCO() && nmas.IsFCO()) // save its master's guid into registry
+						if( nobj.IsFCO() && nmas && nmas.IsFCO()) // save its master's guid into registry
 						{
 							CComBSTR bstr;
 							ObjForCore( nmas)->GetGuidDisp( &bstr);
 							if( bstr) ObjForCore( nobj)->put_RegistryValue( CComBSTR( DETACHED_FROM), bstr);
 						}
+						MergeRegs(orig, nobj);
 						nobj[ai] = CComVariant( (IDispatch*) 0);//an empty value;
 						break;
 					}
@@ -1711,16 +1707,6 @@
 				ai -= ATTRID_COLLECTION;
 
 				switch( ai) {
-					case ATTRID_REGNOWNER: // merge registry
-					{ 
-						CoreObjs collmembers = orig[ai + ATTRID_COLLECTION]; // copy the base's entries
-						ITERATE_THROUGH(collmembers) {
-							CoreObj nchild;
-							ObjTreeCopy(mgaproject, ITER, nchild, crealist);
-							nchild[ai] = nobj;
-						}
-						break;
-					}
 					case ATTRID_ATTRPARENT: // copy the unfilled attributes
 					{
 						unsigned int owned_attrs(0), inherited_attrs(0), l3(0);
@@ -1871,7 +1857,6 @@
 				ai -= ATTRID_COLLECTION;
 				if(LINKREF_ATTR(ai))  {
 					if( ai == ATTRID_ATTRPARENT) { } // no need to copy attr values since the newobj already had its own
-					else if( ai == ATTRID_REGNOWNER) { } // automatic
 					else if( ai == ATTRID_CONSTROWNER) { }
 					else if( ai == ATTRID_CONNROLE) { }
 					else if( ai == ATTRID_SETMEMBER) { }

Modified: trunk/GME/Mga/MgaCoreObj.cpp
==============================================================================
--- trunk/GME/Mga/MgaCoreObj.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaCoreObj.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -130,7 +130,6 @@
 		case DTID_CONNROLESEG:  ai = ATTRID_CONNSEG; break;
 		case DTID_SETNODE:		ai = ATTRID_SETMEMBER; break;
 		case DTID_CONSTRAINT:   ai = ATTRID_CONSTROWNER; break;
-		case DTID_REGNODE:      ai = ATTRID_REGNOWNER; break;
 		default:				ai = ATTRID_ATTRPARENT;
 		}
 		r = r[ai];

Modified: trunk/GME/Mga/MgaCoreObj.h
==============================================================================
--- trunk/GME/Mga/MgaCoreObj.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaCoreObj.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -2,6 +2,10 @@
 ////////////////////////////// COREOBJ COREOBJS & COREATTRIBUTE //////////////////
 ///////////////////////////////////////////////////////////////////////////////////
 
+#pragma once
+
+#include "MgaGeneric.h"
+
 class CoreAttr;  // defined  below
 class CoreObjs;
 

Modified: trunk/GME/Mga/MgaDeriveOps.cpp
==============================================================================
--- trunk/GME/Mga/MgaDeriveOps.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaDeriveOps.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -176,7 +176,6 @@
 	case DTID_CONNROLE:	 a = ATTRID_XREF; break;	
 	case DTID_SETNODE:	 a = ATTRID_XREF; break;	
 	case DTID_REFATTR:	 a = ATTRID_XREF; break;	
-	case DTID_REGNODE:	 a = ATTRID_XREF; break;	
 	case DTID_CONNROLESEG:   a = ATTRID_SEGREF;	break;
 	default: COMTHROW(E_MGA_DATA_INCONSISTENCY);
 	}

Modified: trunk/GME/Mga/MgaFCO.cpp
==============================================================================
--- trunk/GME/Mga/MgaFCO.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaFCO.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -780,7 +780,15 @@
 			CheckRead();
 			CHECK_INSTRPAR(path);
 			CHECK_OUTPTRPAR(pVal);
-			*pVal = rpool.getpoolobj(path, this, mgaproject).Detach();
+
+		CComPtr<CMgaRegNode> s;
+		CreateComObject(s);
+
+		s->Initialize(path, this, mgaproject);
+
+		CComPtr<IMgaRegNode> retval = s;
+
+		*pVal = s.Detach();
 	} COMCATCH(;)
 }
 
@@ -792,36 +800,16 @@
 	COMTRY {  
 		CheckRead();
 		CHECK_OUTPTRPAR(pVal);
-		CREATEEXCOLLECTION_FOR(MgaRegNode,q);
-		CoreObj s = self;
-		if(!s.IsFCO()) virtuals = VARIANT_FALSE;
-		stdext::hash_set<CComBSTRNoAt, CComBSTR_hashfunc> match;
-		do {
-			CoreObjs children = s[ATTRID_REGNOWNER+ATTRID_COLLECTION];
-			ITERATE_THROUGH(children) {
-				CComBSTR path;
-				path	= ITER[ATTRID_NAME];
-				if(virtuals) {
-					if(match.find(path) != match.end()) continue;
-					match.insert(path);
-				}
-				q->Add(rpool.getpoolobj(path, this, mgaproject));
-			}
-		} while(virtuals && (s = s[ATTRID_DERIVED]));
-		if(virtuals) {
-			CComQIPtr<IMgaMetaBase> m;
-			COMTHROW(get_MetaBase(&m));
-			CComPtr<IMgaMetaRegNodes> rns;
-			COMTHROW(m->get_RegistryNodes(&rns));
-			MGACOLL_ITERATE(IMgaMetaRegNode, rns) {
-				CComBSTR path;
-				COMTHROW(MGACOLL_ITER->get_Name(&path));
-				if(match.find(path) != match.end()) continue;
-				q->Add(rpool.getpoolobj(path, this, mgaproject));
-			} MGACOLL_ITERATE_END;
-		}
 
-		*pVal = q.Detach();
+		if(!self.IsFCO())
+			virtuals = VARIANT_FALSE;
+
+		CComPtr<CMgaRegNode> regnode;
+		CreateComObject(regnode);
+
+		regnode->Initialize(CComBSTR(L""), this, mgaproject);
+
+		COMTHROW(regnode->get_SubNodes(virtuals, pVal));
 	} COMCATCH(;);
 }
 HRESULT FCO::get_RegistryValue( BSTR path,  BSTR *pVal) {  
@@ -847,33 +835,14 @@
 typedef std::vector<CComVariant> ModificationsVector;
 
 void getRegistryModifications(CoreObj &cobj, CComBSTR &path, ModificationsVector &mv) {
-	CComVariant current  = cobj[ATTRID_REGNODEVALUE];
-	CComVariant previous;
-	COMTHROW(cobj->get_PreviousAttrValue(ATTRID_REGNODEVALUE, &previous));
-	if (previous != current) {
-		CComBSTR label = "REGISTRY:";
-		COMTHROW(label.Append(path));
-		CComVariant ident = label;
-		mv.push_back(ident);
-		mv.push_back(previous);
-	}
-	ITERATE_THROUGH(cobj[ATTRID_REGNOWNER+ATTRID_COLLECTION]) {
-		CComBSTR cname = ITER[ATTRID_NAME];
-		CComBSTR cpath = path;
-		COMTHROW(cpath.Append("/"));
-		COMTHROW(cpath.Append(cname));
-		getRegistryModifications(ITER, cpath, mv);
-	}
+	// TODO
 }
 
 HRESULT get_Modifications(FCO *fco, unsigned long changemask, CComVariant *mods) {
 	COMTRY {
 	ModificationsVector modifications;
 	if (changemask & OBJEVENT_REGISTRY) {
-		ITERATE_THROUGH(fco->self[ATTRID_REGNOWNER+ATTRID_COLLECTION]) {
-			CComBSTR path = ITER[ATTRID_NAME];
-			getRegistryModifications(ITER, path, modifications);
-		}
+		// TODO
 	}
 	if (changemask & OBJEVENT_ATTR) {
 		CComPtr<IMgaMetaFCO> mfco;

Modified: trunk/GME/Mga/MgaFCO.h
==============================================================================
--- trunk/GME/Mga/MgaFCO.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaFCO.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -355,7 +355,6 @@
 	bool simpleconn();
 	partpool ppool;
 	attrpool apool;
-	regnpool rpool;
 	typedef stdext::hash_map<objid_type, CMgaConnPoint *, cp_hashfunc> cphash;
 	cphash connpointhash;
 	typedef stdext::hash_map<objid_type, CMgaConstraint *, cp_hashfunc> cshash;

Modified: trunk/GME/Mga/MgaFolder.cpp
==============================================================================
--- trunk/GME/Mga/MgaFolder.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaFolder.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -945,8 +945,7 @@
 				nnode[ATTRID_DERIVED] = NULL;
 				nnode[ATTRID_PERMISSIONS] = 0;
 				{ ITERATE_THROUGH(self[ATTRID_CONSTROWNER+ATTRID_COLLECTION]) ITER[ATTRID_CONSTROWNER] = nnode; }
-				{ ITERATE_THROUGH(self[ATTRID_REGNOWNER+ATTRID_COLLECTION]) ITER[ATTRID_REGNOWNER] = nnode; }
-				{ ITERATE_THROUGH(self[ATTRID_ATTRPARENT+ATTRID_COLLECTION]) ITER[ATTRID_ATTRPARENT] = nnode; }
+				// FIXME: should copy registry
 				{ ITERATE_THROUGH(self[ATTRID_XREF+ATTRID_COLLECTION]) ITER[ATTRID_XREF] = nnode; }
 				{ ITERATE_THROUGH(self[ATTRID_XREF+ATTRID_REFERENCE]) ITER[ATTRID_REFERENCE] = nnode; }
 				COMTHROW(self->Delete());

Modified: trunk/GME/Mga/MgaGeneric.cpp
==============================================================================
--- trunk/GME/Mga/MgaGeneric.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaGeneric.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -73,16 +73,17 @@
 		CREATE_ATTRIBUTE(ATTRID_CONSTRPRIORITY, "ConstrPriority", "Constraint Priority",VALTYPE_STRING);
 		CREATE_POINTER(ATTRID_CONSTROWNER, "ConstraintOf", "Owner Kind");
 
+// Old REGNODE format. Upgraded to new format in CoreBinFile
 //REGNODE
-		CREATE_OBJECT(DTID_REGNODE, "RegNode", "Template For Registry Node");
-		COMMON_DEF
-
-		CREATE_ATTRIBUTE(ATTRID_NAME, "Name", "RegNode Name",		VALTYPE_STRING);
-		CREATE_ATTRIBUTE(ATTRID_REGFLAGS, "RegistryFlags", "Registry Flags", VALTYPE_LONG);
-		CREATE_POINTER(ATTRID_REGNOWNER, "RegNodeOf", "Parent Object/Regnode");
-		CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes");
-		CREATE_ATTRIBUTE(ATTRID_REGNODEVALUE, "RegNodeValue", "RegNode Value",VALTYPE_STRING);
-		CREATE_POINTER(ATTRID_XREF,	"FCOref", "Referenced FCO");
+//		CREATE_OBJECT(DTID_REGNODE, "RegNode", "Template For Registry Node");
+//		COMMON_DEF
+//
+//		CREATE_ATTRIBUTE(ATTRID_NAME, "Name", "RegNode Name",		VALTYPE_STRING);
+//		CREATE_ATTRIBUTE(ATTRID_REGFLAGS, "RegistryFlags", "Registry Flags", VALTYPE_LONG);
+//		CREATE_POINTER(ATTRID_REGNOWNER, "RegNodeOf", "Parent Object/Regnode");
+//		CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes");
+//		CREATE_ATTRIBUTE(ATTRID_REGNODEVALUE, "RegNodeValue", "RegNode Value",VALTYPE_STRING);
+//		CREATE_POINTER(ATTRID_XREF,	"FCOref", "Referenced FCO");
 
 //////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////// DATA ///////////////////////////////////////////////////
@@ -109,7 +110,8 @@
 		CREATE_POINTER(ATTRID_PARENT, "Parent", "Parent Object");
 		CREATE_COLLECTION(ATTRID_PARENT, "Children", "Child Objects");
 		CREATE_COLLECTION(ATTRID_CONSTROWNER, "Constraints", "Constraints");
-		CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes");
+		//CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes");
+		CREATE_ATTRIBUTE(ATTRID_REGNODE, "RegNodes", "Registry Nodes", VALTYPE_DICT);
 		CREATE_ATTRIBUTE(ATTRID_PERMISSIONS, "Permissions", "Permissions", VALTYPE_LONG);
 
 		if( v2) GUID_ATTRS_DEFS;
@@ -125,13 +127,12 @@
 		CREATE_ATTRIBUTE(ATTRID_ROLEMETA, "RoleMeta", "Role Meta Identifier",VALTYPE_METAREF);\
 		CREATE_POINTER(ATTRID_FCOPARENT, "Parent", "Parent Object");\
 		CREATE_COLLECTION(ATTRID_CONSTROWNER, "Constraints", "Constraints");\
-		CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes");\
+		CREATE_ATTRIBUTE(ATTRID_REGNODE, "RegNodes", "Registry Nodes", VALTYPE_DICT); \
 		CREATE_COLLECTION(ATTRID_REFERENCE, "References", "Referenced by");\
 		CREATE_COLLECTION(ATTRID_XREF,		"XReferences", "Cross refs");\
 		CREATE_COLLECTION(ATTRID_ATTRPARENT,"Attributes", "Attributes");\
 		CREATE_POINTER(ATTRID_DERIVED, "BaseType", "BaseType");\
 		CREATE_COLLECTION(ATTRID_DERIVED, "SubTypes", "SubTypes/Instances"); \
-/*		CREATE_COLLECTION(ATTRID_REALOBJECT, "Aliases", "Aliases"); */ \
 		CREATE_ATTRIBUTE(ATTRID_PERMISSIONS, "Permissions", "Permissions", VALTYPE_LONG);
 
 //MODEL
@@ -178,19 +179,6 @@
 		if( v2) GUID_ATTRS_DEFS;
 		CLSID_PUSH(  CLSID_MgaO );  
 
-/*
-//ALIAS		
-		CREATE_OBJECT(DTID_ALIASNODE, "AliasNode", "Template For Aliases");
-		COMMON_DEF
-
-		CREATE_ATTRIBUTE(ATTRID_ROLEMETA, "RoleMeta", "Role Meta Identifier",VALTYPE_METAREF);\
-		CREATE_POINTER(ATTRID_FCOPARENT, "Parent", "Parent of FCO");\
-		CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes");\
-		CREATE_POINTER(ATTRID_REALOBJECT, "RealObject", "Real Object");\
-		CREATE_POINTER(ATTRID_DERIVED, "BaseType", "BaseType");\
-		CREATE_COLLECTION(ATTRID_DERIVED, "SubTypes", "SubTypes/Instances"); \
-		CREATE_ATTRIBUTE(ATTRID_PERMISSIONS, "IsInstance", "Is instance?", VALTYPE_LONG);
-*/
 
 //SETNODE		
 		CREATE_OBJECT(DTID_SETNODE, "SetNode", "Template For Set Member");
@@ -235,9 +223,7 @@
 #define ATTR_DEF \
 		COMMON_DEF\
 		CREATE_ATTRIBUTE(ATTRID_META, "Meta", "Meta Identifier",VALTYPE_METAREF);\
-		CREATE_POINTER(ATTRID_ATTRPARENT,"Owner", "Owner FCO");\
-//		CREATE_COLLECTION(ATTRID_CONSTROWNER, "Constraints", "Constraints");\
-//		CREATE_COLLECTION(ATTRID_REGNOWNER, "RegNodes", "Registry Nodes");\
+		CREATE_POINTER(ATTRID_ATTRPARENT,"Owner", "Owner FCO");
 
 //STRATTR
 		CREATE_OBJECT(DTID_STRATTR, "StrAttr", "String Attribute");

Modified: trunk/GME/Mga/MgaGeneric.h
==============================================================================
--- trunk/GME/Mga/MgaGeneric.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaGeneric.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -1,3 +1,4 @@
+#pragma once
 
 void CreateCoreMetaProject(CComPtr<ICoreMetaProject> &project, bool v2 = false);
 
@@ -71,10 +72,10 @@
 #define	ATTRID_CONSTRPRIORITY			451
 #define	ATTRID_CONSTROWNER				652
 
-#define	ATTRID_REGNOWNER				655
-#define	ATTRID_REGNODENAME				456
-#define	ATTRID_REGNODEVALUE				457
-#define	ATTRID_REGFLAGS					458
+#define	ATTRID_REGNOWNER				655 // <! deprecated
+#define	ATTRID_REGNODEVALUE				457 // <! deprecated
+#define	ATTRID_REGFLAGS					458 // <! deprecated
+#define	ATTRID_REGNODE				457
 
 
 // OBJECT ID'S
@@ -105,7 +106,7 @@
 // contigious block ends
 	
 #define DTID_CONSTRAINT			120	
-#define DTID_REGNODE			121	
+#define DTID_REGNODE			121	 // <! deprecated
 #define DTID_SETNODE			122	
 
 

Modified: trunk/GME/Mga/MgaLibOps.cpp
==============================================================================
--- trunk/GME/Mga/MgaLibOps.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaLibOps.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -280,9 +280,6 @@
 	metaid_type s;
 	COMTHROW( m_mgaproject->dataproject->CreateObject(s = orig.GetMetaID(), &nobj.ComPtr()));
 
-	if( s != DTID_REGNODE )		// speedup, no references to regnodes
-		m_fixup.identify(orig, nobj);
-
 	bool skip_this = false;
 	if(s >= DTID_MODEL && s <= DTID_FOLDER) {
 		setcheck( m_mgaproject, nobj, CHK_NEW);
@@ -701,7 +698,6 @@
 	if(oldnode.IsContainer()) {
 		newnode[ATTRID_LASTRELID] = oldnode[ATTRID_LASTRELID];
 	}
-	steal(oldnode, newnode, ATTRID_REGNOWNER);
 	steal(oldnode, newnode, ATTRID_CONSTROWNER);
 
 	if(oldnode.IsFCO()) {

Modified: trunk/GME/Mga/MgaLibRefr.cpp
==============================================================================
--- trunk/GME/Mga/MgaLibRefr.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaLibRefr.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -205,7 +205,6 @@
 	COMTHROW(m_mgaproject->dataproject->CreateObject( GetMetaID(owner), &p_one_conn.saver.ComPtr()));
 
 	steal( owner, p_one_conn.saver, ATTRID_ATTRPARENT);
-	steal( owner, p_one_conn.saver, ATTRID_REGNOWNER);
 	steal( owner, p_one_conn.saver, ATTRID_CONSTROWNER);
 }
 
@@ -213,7 +212,6 @@
 {
 	CoreObj inheritor( p_nConn);
 	steal( p_one_conn.saver, inheritor, ATTRID_ATTRPARENT);
-	steal( p_one_conn.saver, inheritor, ATTRID_REGNOWNER);
 	steal( p_one_conn.saver, inheritor, ATTRID_CONSTROWNER);
 
 	SingleObjTreeDelete( p_one_conn.saver, true);
@@ -2164,7 +2162,6 @@
 				ai -= ATTRID_COLLECTION;
 				if(LINKREF_ATTR(ai))  {
 					if( ai == ATTRID_ATTRPARENT)       { } // don't care
-					else if( ai == ATTRID_REGNOWNER)   { } // don't care
 					else if( ai == ATTRID_CONSTROWNER) { } // don't care
 					else if( ai == ATTRID_CONNROLE)    { } // manually propagated, see collectFreshConnection below
 					else if( ai == ATTRID_SETMEMBER)   { } // manually set, see SyncDerSets below
@@ -2481,7 +2478,6 @@
 
 				switch( ai) {
 					case ATTRID_CONSTROWNER:        // the subobjects which are owned by p_derdObj
-					case ATTRID_REGNOWNER:          // will be preserved automatically
 					case ATTRID_ATTRPARENT:         // p_baseObj's subobjects will be forgotten
                             break;                  // and when the new version is reattached
                                                     // then those will be propagated down to p_derdObj
@@ -2665,7 +2661,6 @@
 				ai -= ATTRID_COLLECTION;
 				if(LINKREF_ATTR(ai))  {
 					//if( ai == ATTRID_ATTRPARENT)       { } // no need to copy these since the
-					//else if( ai == ATTRID_REGNOWNER)   { } // attachment provides the propagation
 					//else if( ai == ATTRID_CONSTROWNER) { } // automatically
 					if(ai == ATTRID_CONNROLE) {
 						// ConnRoles also depend on their base with ATTRID_MASTEROBJ

Modified: trunk/GME/Mga/MgaProject.h
==============================================================================
--- trunk/GME/Mga/MgaProject.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaProject.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -4,7 +4,7 @@
 #define __MGAPROJECT_H_
 
 #include "resource.h"       // main symbols
-
+#include "MgaTrukk.h"
 class CMgaTerritory;
 class CMgaAddOn;
 class CMgaClient;

Modified: trunk/GME/Mga/MgaTrukk.h
==============================================================================
--- trunk/GME/Mga/MgaTrukk.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/Mga/MgaTrukk.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -2,6 +2,9 @@
 // Tricks, macros, definitions used throughout the Mga library
 //
 
+#pragma once
+
+#include "MgaCoreObj.h"
 #include "CommonMgaTrukk.h"
 
 #define DIM(x) (sizeof(x)/ sizeof((x)[0]))

Modified: trunk/GME/MgaUtil/RegBrwNode.h
==============================================================================
--- trunk/GME/MgaUtil/RegBrwNode.h	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/MgaUtil/RegBrwNode.h	Mon Nov 21 17:38:34 2011	(r1696)
@@ -13,7 +13,6 @@
 class CRegBrwNode  
 {
 public:
-	bool opacity;
 	long status;
 	void* handle;
 	CRegBrwNode* parent;

Modified: trunk/GME/MgaUtil/RegistryBrowserDlg.cpp
==============================================================================
--- trunk/GME/MgaUtil/RegistryBrowserDlg.cpp	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/GME/MgaUtil/RegistryBrowserDlg.cpp	Mon Nov 21 17:38:34 2011	(r1696)
@@ -250,10 +250,6 @@
 
 		COMTHROW(regNode->get_Status(&(brNode->status)));
 
-		VARIANT_BOOL op;
-		COMTHROW(regNode->get_Opacity(&op));
-		brNode->opacity = (op == VARIANT_TRUE);
-
 		HTREEITEM hnd;
 		if (parent) {
 			hnd = m_wndRegistryTree.InsertItem(brNode->name, (HTREEITEM)(parent->handle));

Modified: trunk/Tests/GPyUnit/__init__.py
==============================================================================
--- trunk/Tests/GPyUnit/__init__.py	Mon Nov 21 17:37:54 2011	(r1695)
+++ trunk/Tests/GPyUnit/__init__.py	Mon Nov 21 17:38:34 2011	(r1696)
@@ -10,6 +10,7 @@
  'test_registrar',
  'test_gmeoleapp',
  'test_parser',
+ 'test_registry',
  'GME_297.suite',
  'GME_310.suite',
  'GME_371',

Added: trunk/Tests/GPyUnit/test_registry.py
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/Tests/GPyUnit/test_registry.py	Mon Nov 21 17:38:34 2011	(r1696)
@@ -0,0 +1,159 @@
+
+import sys
+import os.path
+import unittest
+import win32com.client
+
+class TestRegistry(unittest.TestCase):
+    def __init__(self, name, **kwds):
+        super(TestRegistry, self).__init__(name, **kwds)
+        self.output_file = "TestRegistry-output.mga"
+
+    def test(self):
+        def _adjacent_file(file):
+            import os.path
+            return os.path.join(os.path.dirname(__file__), file)
+        from GPyUnit import util
+        util.register_xmp('MetaGME')
+        with util.disable_early_binding():
+            self.project = win32com.client.DispatchEx("Mga.MgaProject")
+            self.project.Create("MGA=" + _adjacent_file(self.output_file), "MetaGME")
+            self.project.BeginTransactionInNewTerr()
+            
+            rootregs = self.project.RootFolder.GetRegistryDisp(True)
+            self.assertEqual(rootregs.Count, 0)
+            self.project.RootFolder.GetRegistryNodeDisp('test123').Value = 'xxx'
+            self.project.RootFolder.GetRegistryNodeDisp('test345').Value = 'yyy'
+            
+            for i in range(1, self.project.RootMeta.RootFolder.DefinedFCOs.Count+1):
+                if self.project.RootMeta.RootFolder.DefinedFCOs.Item(i).Name == 'ParadigmSheet':
+                    sheet_meta = self.project.RootMeta.RootFolder.DefinedFCOs.Item(i)
+            sheet = self.project.RootFolder.CreateRootObject(sheet_meta)
+            sheetregs = sheet.GetRegistryDisp(True)
+            self.assertEqual(sheetregs.Item(1).Name, 'namePosition')
+            
+            namePosition = sheet.GetRegistryNodeDisp('namePosition')
+            self.assertEqual(namePosition.Name, 'namePosition')
+            self.assertEqual(namePosition.Value, '0')
+            self.assertEqual(namePosition.GetSubNodesDisp(True).Count, 0)
+            self.assertEqual(namePosition.GetSubNodesDisp(False).Count, 0)
+            
+            def keytest():
+                newkey = sheet.GetRegistryNodeDisp('newkey')
+                newkey.Value = 'newvalue'
+                self.assertEqual(newkey.Value, 'newvalue')
+            keytest()
+            newkey = sheet.GetRegistryNodeDisp('newkey')
+            self.assertEqual(newkey.GetSubNodesDisp(True).Count, 0)
+            
+            def subkeytest():
+                newsubkey = sheet.GetRegistryNodeDisp('newkey/subkey')
+                newsubkey.Value = 'subvalue'
+                self.assertEqual(newsubkey.Value, 'subvalue')
+                self.assertEqual(newsubkey.GetSubNodesDisp(True).Count, 0)
+                newkey = sheet.GetRegistryNodeDisp('newkey')
+                self.assertEqual(newkey.GetSubNodesDisp(False).Count, 1)
+            subkeytest()
+            
+
+            #self.project.Save("MGA=" + _adjacent_file(self.output_file))
+            self.project.CommitTransaction()
+            terr = self.project.BeginTransactionInNewTerr()
+            sheet = terr.OpenObj(sheet)
+            keytest()
+            subkeytest()
+            self.project.CommitTransaction()
+            
+            self.project.Undo()
+            self.project.Undo()
+            terr = self.project.BeginTransactionInNewTerr()
+            self.assertEqual(self.project.RootFolder.GetRegistryDisp(False).Count, 0)
+            self.project.CommitTransaction()
+            
+            terr = self.project.BeginTransactionInNewTerr()
+            self.project.RootFolder.GetRegistryNodeDisp('xtest123').Value = 'xxx'
+            self.project.RootFolder.GetRegistryNodeDisp('ytest123').Value = 'yyy'
+            self.project.RootFolder.GetRegistryNodeDisp('xtest123/ztest').Value = 'zzz'
+            self.project.RootFolder.GetRegistryNodeDisp('xtest123/ztest/blank').Value = ''
+            self.project.CommitTransaction()
+            
+            self.project.Save()
+            self.project.Close(True)
+            
+            self.project.Open("MGA=" + _adjacent_file(self.output_file))
+            terr = self.project.BeginTransactionInNewTerr()
+            self.assertEqual(self.project.RootFolder.GetRegistryNodeDisp('xtest123').Value, 'xxx')
+            self.assertEqual(self.project.RootFolder.GetRegistryNodeDisp('ytest123').Value, 'yyy')
+            self.assertEqual(self.project.RootFolder.GetRegistryNodeDisp('xtest123/ztest').Value, 'zzz')
+            self.assertEqual(self.project.RootFolder.GetRegistryNodeDisp('xtest123/ztest/blank').Value, '')
+            ATTSTATUS_HERE = 0
+            self.assertEqual(self.project.RootFolder.GetRegistryNodeDisp('xtest123/ztest/blank').Status(), ATTSTATUS_HERE)
+            self.project.CommitTransaction()
+            self.project.Close(True)
+
+    def test_derived(self):
+        def _adjacent_file(file):
+            import os.path
+            return os.path.join(os.path.dirname(__file__), file)
+        from GPyUnit import util
+        util.register_xmp('MetaGME')
+        with util.disable_early_binding():
+            self.project = win32com.client.DispatchEx("Mga.MgaProject")
+            self.project.Create("MGA=" + _adjacent_file(self.output_file), "MetaGME")
+            self.project.BeginTransactionInNewTerr()
+            
+            for i in range(1, self.project.RootMeta.RootFolder.DefinedFCOs.Count+1):
+                if self.project.RootMeta.RootFolder.DefinedFCOs.Item(i).Name == 'ParadigmSheet':
+                    sheet_meta = self.project.RootMeta.RootFolder.DefinedFCOs.Item(i)
+            sheet = self.project.RootFolder.CreateRootObject(sheet_meta)
+            sheet2 = self.project.RootFolder.DeriveRootObject(sheet, False)
+            sheet3 = self.project.RootFolder.DeriveRootObject(sheet2, False)
+            sheet4 = self.project.RootFolder.DeriveRootObject(sheet3, False)
+            
+            sheet.SetRegistryValueDisp('test123', 'test')
+            self.assertEqual(sheet4.GetRegistryValueDisp('test123'), 'test')
+            sheet3.DetachFromArcheType()
+            self.assertEqual(sheet4.GetRegistryValueDisp('test123'), 'test')
+            self.assertEqual(sheet2.GetRegistryDisp(False).Count, 0)
+            self.assertEqual(sheet4.GetRegistryDisp(False).Count, 0)
+            self.project.CommitTransaction()
+            self.project.Save()
+            self.project.Close()
+
+
+    def test_copy(self):
+        def _adjacent_file(file):
+            import os.path
+            return os.path.join(os.path.dirname(__file__), file)
+        from GPyUnit import util
+        util.register_xmp('MetaGME')
+        with util.disable_early_binding():
+            self.project = win32com.client.DispatchEx("Mga.MgaProject")
+            self.project.Create("MGA=" + _adjacent_file(self.output_file), "MetaGME")
+            self.project.BeginTransactionInNewTerr()
+            
+            for i in range(1, self.project.RootMeta.RootFolder.DefinedFCOs.Count+1):
+                if self.project.RootMeta.RootFolder.DefinedFCOs.Item(i).Name == 'ParadigmSheet':
+                    sheet_meta = self.project.RootMeta.RootFolder.DefinedFCOs.Item(i)
+            sheet = self.project.RootFolder.CreateRootObject(sheet_meta)
+            sheet.SetRegistryValueDisp('test123', 'test')
+            sheet2 = self.project.RootFolder.CopyFCOs(self.project.RootFolder.ChildFCOs).Item(1)
+            self.assertEqual(sheet2.GetRegistryValueDisp('test123'), 'test')
+            self.project.CommitTransaction()
+            self.project.Save()
+            self.project.Close()
+
+    def xxxtestupgrade(self):
+        def _adjacent_file(file):
+            import os.path
+            return os.path.join(os.path.dirname(__file__), file)
+        from GPyUnit import util
+        util.register_xmp('MetaGME')
+        with util.disable_early_binding():
+            self.project = win32com.client.DispatchEx("Mga.MgaProject")
+            self.project.Open("MGA=" + r"C:\Users\ksmyth\Documents\META\meta\CyPhyML\CyPhyML.mga")
+            self.project.BeginTransactionInNewTerr()
+            self.project.RootFolder.ChildFolders
+
+if __name__ == "__main__":
+    unittest.main()


More information about the gme-commit mailing list