locked
Handling HSTRING with a vector wrapper

    Question

  • Hello,

    I have made a wrapper for handling collections for WinRT components. Exemple, a component "Root" contains some methods that return vectors of elements (HSTRING, a custom type MyData, int). Here is the IDL.

    	interface IRoot : IInspectable
    	{
    		HRESULT GetVector([out][retval] Windows.Foundation.Collections.IVector<HSTRING>** value);
    		HRESULT GetVectorData([out][retval] Windows.Foundation.Collections.IVector<IMyData *>** value);
    		HRESULT GetVectorInt([out][retval] Windows.Foundation.Collections.IVector<int>** value);
    	}

    In my C++ code, here is how the methods are implemented:

    		STDMETHODIMP Root::GetVector(IVector<HSTRING>** value)
    		{
    			ComPtr<Vector<HSTRING>> v = Make<Vector<HSTRING>>();
    			HString str1;
    			str1.Set(L"String1");
    			v->Append(str1.Detach());
    			HString str2;
    			str2.Set(L"String2");
    			v->Append(str2.Detach());
    			HString str3;
    			str3.Set(L"String3");
    			v->Append(str3.Detach());
    			HString str4;
    			str4.Set(L"String4");
    			v->Append(str4.Detach());
    			*value = v.Detach();
    			return S_OK;
    		}
    
    		STDMETHODIMP Root::GetVectorData(IVector<IMyData *>** value)
    		{
    			ComPtr<Vector<IMyData *>> v = Make<Vector<IMyData *>>();
    
    			HString str1;
    			str1.Set(L"String1");
    			ComPtr<MyData> data1 = Make<MyData>();
    			data1->SetName(str1.Detach());
    			v->Append(data1.Detach());
    
    			HString str2;
    			str2.Set(L"String2");
    			ComPtr<MyData> data2 = Make<MyData>();
    			data2->SetName(str2.Detach());
    			v->Append(data2.Detach());
    
    			*value = v.Detach();
    			return S_OK;
    		}
    
    		STDMETHODIMP Root::GetVectorInt(IVector<int>** value)
    		{
    			ComPtr<Vector<int>> v = Make<Vector<int>>();
    			v->Append(10);
    			v->Append(20);
    			v->Append(30);
    			v->Append(40);
    			*value = v.Detach();
    			return S_OK;
    		}

    All these 3 methods use the same template class named Vector<T> and it looks like that:

    		template <class T>
    		class Iterator : public RuntimeClass<IIterator<T>>
    		{
    			InspectableClass(L"Library1.Iterator", BaseTrust)
    
    		private:
    			typedef typename std::shared_ptr<std::vector<T>> V;
    			typedef typename std::vector<T>::iterator IT;
    
    		public:
    			Iterator() {}
    
    			HRESULT Init(const V & item)
    			{
    				_v = item;
    				_it = _v->begin();
    				if (_it != _v->end())
    				{
    					_element = *_it;
    					_bElement = TRUE;
    				}
    				else
    					_bElement = FALSE;
    				return S_OK;
    			}
    
    		public:
    			virtual HRESULT STDMETHODCALLTYPE get_Current(T *current)
    			{
    				if (_it != _v->end())
    				{
    					_bElement = TRUE;
    					_element = *_it;
    					*current = _element;
    				}
    				else
    				{
    					_bElement = FALSE;
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE get_HasCurrent(boolean *hasCurrent)
    			{
    				if (_bElement)
    					*hasCurrent = TRUE;
    				else
    					*hasCurrent = FALSE;
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE MoveNext(boolean *hasCurrent)
    			{
    				if (_it != _v->end())
    				{
    					++_it;
    					if (_it == _v->end())
    						*hasCurrent = FALSE;
    					else
    						*hasCurrent = TRUE;
    				}
    				else
    				{
    					*hasCurrent = FALSE;
    				}
    				return S_OK;
    			}
    
    		private:
    			V _v;
    			IT _it;
    			T _element;
    			boolean _bElement = FALSE;
    		};
    
    		template <typename T>
    		class Vector : public RuntimeClass<IVector<T>, IIterable<T>>
    		{
    			InspectableClass(L"Library1.Vector", BaseTrust)
    
    		public:
    			Vector() 
    			{
    				std::shared_ptr<std::vector<T>> ptr(new std::vector<T>());
    				_v = ptr;
    			}
    
    		public:
    
    			// read methods
    			virtual HRESULT STDMETHODCALLTYPE GetAt(unsigned index, T *item)
    			{
    				*item = (*_v)[index];
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE get_Size(unsigned *size)
    			{
    				*size = _v->size();
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE GetView(IVectorView<T> **view)
    			{
    				return E_NOTIMPL;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE IndexOf(T value, unsigned *index, boolean *found)
    			{
    				unsigned foundedIndex = 0;
    				bool founded = false;
    				for (std::vector<T>::const_iterator it = _v->cbegin() ; it != _v->end() ; ++it)
    				{
    					const T & v = *it;
    					if (v == value)
    					{
    						founded = true;
    						break;
    					}
    					foundedIndex++;
    				}
    				if (founded == true)
    				{
    					*found = TRUE;
    					*index = foundedIndex;
    				}
    				else
    				{
    					*found = FALSE;
    				}
    				return S_OK;
    			}
    
    			// write methods
    			virtual HRESULT STDMETHODCALLTYPE SetAt(unsigned index, T item)
    			{
    				if (index < _v->size())
    				{
    					(*_v)[index] = item;
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE InsertAt(unsigned index, T item)
    			{
    				//_v->emplace(_v->begin() + index, item);
    				_v->insert(_v->begin() + index, item);
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE RemoveAt(unsigned index)
    			{
    				if (index < _v->size())
    				{
    					_v->erase(_v->begin() + index);
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE Append(T item)
    			{
    				//_v->emplace_back(item);
    				_v->push_back(item);
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE RemoveAtEnd()
    			{
    				if (!_v->empty())
    				{
    					_v->pop_back();
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE Clear()
    			{
    				_v->clear();
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE First(IIterator<T> **first)
    			{
    				ComPtr<Iterator<T>> p = Make<Iterator<T>>();
    				p->Init(_v);
    				*first = p.Detach();
    				return S_OK;
    			}
    
    		private:
    			std::shared_ptr<std::vector<T>> _v;
    		};

    The client app (C# XAML) is calling the component via 3 distinct buttons :

            private void Button_Click_VectorInt(object sender, RoutedEventArgs e)
            {
                try
                {
                    // C# XAML APP using Root::GetVectorInt()
                    Root root = new Root();
                    IList<int> list1 = root.GetVectorInt();
                    foreach (int i in list1)
                    {
                        LogInfo("int: " + i.ToString());
                    }
                    list1[0] = 11;
                    list1[1] = 22;
                    list1.Add(1001);
                    list1.Insert(0, 1);
                    foreach (int i in list1)
                    {
                        LogInfo("int: " + i.ToString());
                    }
                }
                catch (Exception ex)
                {
                    LogInfo("Exception! " + ex.Message + " " + ex.StackTrace);
                }
            }
    
            private void Button_Click_VectorMyData(object sender, RoutedEventArgs e)
            {
                Root root = new Root();
                LogInfo("root.GetVectorData()...");
                IList<IMyData> list1 = root.GetVectorData();
                LogInfo("foreach...");
                foreach (IMyData data in list1)
                {
                    string name = data.GetName();
                    LogInfo("MyData name: " + name);
                }
                LogInfo("foreach...");
                foreach (IMyData data in list1)
                {
                    string name = data.GetName();
                    LogInfo("MyData name: " + name);
                }
            }
    
            private void Button_Click_VectorString(object sender, RoutedEventArgs e)
            {
                try
                {
                    Root root = new Root();
                    LogInfo("root.GetVector()...");
                    IList<string> list1 = root.GetVector();
    
                    LogInfo("foreach...");
                    foreach (string s in list1)
                    {
                        LogInfo("string: " + s.ToString());
                    }
                    // This second iteration fails! -> Exception! Exception of type 'System.OutOfMemoryException' was thrown.
                    LogInfo("foreach...");
                    foreach (string s2 in list1)
                    {
                        LogInfo("string: " + s2.ToString());
                    }
                    return;
    
                    // This call will produce -> 'list1[0]' threw an exception of type 'System.AccessViolationException'
                    list1[0] = "string 0 added";
                    list1[1] = "string 1 added";
                    list1.Add("a new string");
                    list1.Insert(0, "another new string");
    
                    LogInfo("foreach...");
                    foreach (string s2 in list1)
                    {
                        LogInfo("string: " + s2.ToString());
                    }
                }
                catch (Exception ex)
                {
                    LogInfo("Exception! " + ex.Message + " " + ex.StackTrace);
                }
            }

    It works perfectly well for the collection that return int or MyData custom type. I can enumerate elements, add, append, it works !

    But the problem is when I handle the vector of strings (HSTRING). The method seems to return the collection, the debugger tells there is a valid Count of elements but when I try to enumerate the collection one time it is OK but if I enumerate a second time , it fails ! Also, if I try to append or insert data, it fails ! When it's about Vector<int>, it works, when it's about Vector<HSTRING>, It fails !

    All the code for the WRL C++ component and the C# client app is available as a sample in the Windows Dev Center: http://code.msdn.microsoft.com/windowsapps/Windows-Runtime-Component-4dc6fa20



    Christophe Pichaud





    Saturday, April 12, 2014 9:05 AM

Answers

  • I'm not exactly familiar with WinRT and its HSTRING but shouldn't you use a vector<HString> instead of vector<HSTRING>? HSTRING is reference counted, presumably something needs to deal with increasing the reference count of the string when it is handed out to the outside world.


    Thursday, April 17, 2014 6:07 AM
  • Hello,

    You are partially right. HSTRING is ref counted. So I can't store it directly... I need to increment its ref counter and use a wrapper for my vector handler. This is also true for handling interface pointers for custom types, I can't store them directly, I need to use a ComPtr. So here is the magical wrap stuff:

    		template <typename T>
    		struct Wrap
    		{
    			typename typedef T type;
    			static const T& MakeWrap(const T& t)
    			{
    				return t;
    			}
    			static const T& Unwrap(const T& t)
    			{
    				return t;
    			}
    		};
    
    		template <>
    		struct Wrap<HSTRING>
    		{
    			typedef HStringHelper type;
    			static HStringHelper MakeWrap(const HSTRING& t)
    			{
    				HStringHelper str;
    				str.Set(t);
    				return str;
    			}
    			static HSTRING Unwrap(const HStringHelper& t)
    			{
    				HSTRING str;
    				HRESULT hr = t.CopyTo(&str);
    				// Error check
    				return str;
    			}
    		};
    
    		template <typename T>
    		struct Wrap<T*>
    		{
    			typename typedef ComPtr<T> type;
    			static ComPtr<T> MakeWrap(T* t)
    			{
    				ComPtr<T> ptr;
    				ptr.Attach(t);
    				return ptr;
    			}
    			static T* Unwrap(ComPtr<T> t)
    			{
    				ComPtr<T> ptr(t);
    				return t.Detach();
    			}
    		};
    

    And my vector template class is now made with this:

    		template <class T>
    		class Iterator : public RuntimeClass<IIterator<T>>
    		{
    			InspectableClass(L"Library1.Iterator", BaseTrust)
    
    		private:
    			typedef typename std::vector<typename Wrap<T>::type> WrappedVector;
    			typedef typename std::shared_ptr<WrappedVector> V;
    			typedef typename WrappedVector::iterator IT;
    
    		public:
    			Iterator() {} 
    
    			void LogVectorContent()
    			{
    				for (IT it = _v->begin(); it != _v->end(); it++)
    				{
    					T element = Wrap<T>::Unwrap(*it);
    					void * ptr = (void *)element;
    					wchar_t sz[255];
    					swprintf(sz, 255, L"adress T =0x%08x\n", (int)ptr);
    					_LogInfo(sz);
    				}
    			}
    
    			HRESULT Init(const V& vec)
    			{
    				try {
    					_LogInfo(L"Iterator::Init()...");
    
    				_v = vec;
    				
    				LogVectorContent();
    
    				_it = _v->begin();
    				if (_it != _v->end())
    				{
    					_element = Wrap<T>::Unwrap(*_it);
    					_bElement = TRUE;
    				}
    				else
    					_bElement = FALSE;
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::Init()...");
    			}
    
    		public:
    			virtual HRESULT STDMETHODCALLTYPE get_Current(T *current)
    			{
    				try {
    					_LogInfo(L"Iterator::get_Current()...");
    				if (_it != _v->end())
    				{
    					_bElement = TRUE;
    					_element = Wrap<T>::Unwrap(*_it);
    					*current = _element;
    				}
    				else
    				{
    					_bElement = FALSE;
    				}
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::get_Current()...");
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE get_HasCurrent(boolean *hasCurrent)
    			{
    				try {
    					_LogInfo(L"Iterator::get_HasCurrent()...");
    				if (_bElement)
    					*hasCurrent = TRUE;
    				else
    					*hasCurrent = FALSE;
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::get_HasCurrent()...");
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE MoveNext(boolean *hasCurrent)
    			{
    				try {
    					_LogInfo(L"Iterator::MoveNext()...");
    				if (_it != _v->end())
    				{
    					++_it;
    					if (_it == _v->end())
    					{
    						*hasCurrent = FALSE;
    						_bElement = FALSE;
    					}
    					else
    					{
    						*hasCurrent = TRUE;
    						_bElement = TRUE;
    					}
    				}
    				else
    				{
    					*hasCurrent = FALSE;
    					_bElement = FALSE;
    				}
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::MoveNext()...");
    			}
    
    		private:
    			V _v;
    			IT _it;
    			T _element;
    			boolean _bElement = FALSE;
    		};
    
    		template <typename T>
    		class Vector : public RuntimeClass<IVector<T>, 
    			IIterable<T >>
    		{
    			InspectableClass(L"Library1.Vector", BaseTrust)
    
    		private:
    			typedef typename std::vector<typename Wrap<T>::type> WrappedVector;
    			typedef typename WrappedVector::const_iterator CIT;
    
    		public:
    			Vector() 
    			{
    				_LogInfo(L"Vector::Vector()...");
    				_v = std::make_shared<WrappedVector>();
    			}
    
    		public:
    			// read methods
    			virtual HRESULT STDMETHODCALLTYPE GetAt(unsigned index, T *item)
    			{
    				_LogInfo(L"Vector::GetAt()...");
    				*item = Wrap<T>::Unwrap((*_v)[index]);
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE get_Size(unsigned *size)
    			{
    				_LogInfo(L"Vector::get_Size()...");
    				*size = _v->size();
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE GetView(IVectorView<T> **view)
    			{
    				_LogInfo(L"Vector::GetView()...");
    				return E_NOTIMPL;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE IndexOf(T value, unsigned *index, boolean *found)
    			{
    				_LogInfo(L"Vector::IndexOf()...");
    				unsigned foundedIndex = 0;
    				bool founded = false;
    				for (CIT it = _v->cbegin() ; it != _v->end() ; ++it)
    				{
    					const T & v = Wrap<T>::Unwrap(*it);
    					if (v == value)
    					{
    						founded = true;
    						break;
    					}
    					foundedIndex++;
    				}
    				if (founded == true)
    				{
    					*found = TRUE;
    					*index = foundedIndex;
    				}
    				else
    				{
    					*found = FALSE;
    				}
    				return S_OK;
    			}
    
    			// write methods
    			virtual HRESULT STDMETHODCALLTYPE SetAt(unsigned index, T item)
    			{
    				_LogInfo(L"Vector::SetAt()...");
    				if (index < _v->size())
    				{
    					(*_v)[index] = Wrap<T>::MakeWrap(item);
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE InsertAt(unsigned index, T item)
    			{
    				_LogInfo(L"Vector::InsertAt()...");
    				_v->insert(_v->begin() + index, Wrap<T>::MakeWrap(item));
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE RemoveAt(unsigned index)
    			{
    				_LogInfo(L"Vector::RemoveAt()...");
    				if (index < _v->size())
    				{
    					_v->erase(_v->begin() + index);
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE Append(T item)
    			{
    				_LogInfo(L"Vector::Append()...");
    				_v->push_back(Wrap<T>::MakeWrap(item));
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE RemoveAtEnd()
    			{
    				_LogInfo(L"Vector::RemoveAtEnd()...");
    				if (!_v->empty())
    				{
    					_v->pop_back();
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE Clear()
    			{
    				_LogInfo(L"Vector::Clear()...");
    				_v->clear();
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE First(IIterator<T> **first)
    			{
    				_LogInfo(L"Vector::First()...");
    				ComPtr<Iterator<T>> p = Make<Iterator<T>>();
    				p->Init(_v);
    				*first = p.Detach();
    				return S_OK;
    			}
    
    		private:
    			std::shared_ptr<WrappedVector> _v;
    		};
    

    Elements are wrapped and unwrapped.

    Christophe Pichaud

    Wednesday, April 23, 2014 12:55 AM

All replies

  • More details! When I try to access a data using that code, sometimes, it fails... sometimes, it works...

    I just call the method that return the vector, call count, and get item at position 0.

            private void Button_Click_VectorString(object sender, RoutedEventArgs e)
            {
                try
                {
                    Root root = new Root();
                    LogInfo("root.GetVector()...");
                    IList<string> list1 = root.GetVector();
                    int count = list1.Count;
                    LogInfo("list Count=" + count.ToString());
                    LogInfo("list1[0]=" + list1[0]);
                    LogInfo("list1[0]=" + list1[0]);
                    LogInfo("list1[0]=" + list1[0]);
                }
                catch (Exception ex)
                {
                    LogInfo("Exception! " + ex.Message + " " + ex.StackTrace);
                }
            }

    Here is the result from the LogInfo() method:

    root.GetVector()...
    list Count=4
    list1[0]=String1
    list1[0]=String1
    list1[0]=String1
    root.GetVector()...
    list Count=4
    list1[0]=String1
    Exception! Arithmetic operation resulted in an overflow.    at System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.HStringToString(IntPtr hstring)
       at System.StubHelpers.HStringMarshaler.ConvertToManaged(IntPtr hstring)
       at System.Runtime.InteropServices.WindowsRuntime.IVector`1.GetAt(UInt32 index)
       at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.GetAt[T](IVector`1 _this, UInt32 index)
       at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.Indexer_Get[T](Int32 index)
       at StoreAppForLibrary1.MainPage.Button_Click_VectorString(Object sender, RoutedEventArgs e)
    root.GetVector()...
    list Count=4
    list1[0]=String1
    list1[0]=String1
    Exception! Exception of type 'System.OutOfMemoryException' was thrown.    at System.String.CtorCharPtrStartLength(Char* ptr, Int32 startIndex, Int32 length)
       at System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.HStringToString(IntPtr hstring)
       at System.StubHelpers.HStringMarshaler.ConvertToManaged(IntPtr hstring)
       at System.Runtime.InteropServices.WindowsRuntime.IVector`1.GetAt(UInt32 index)
       at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.GetAt[T](IVector`1 _this, UInt32 index)
       at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.Indexer_Get[T](Int32 index)
       at StoreAppForLibrary1.MainPage.Button_Click_VectorString(Object sender, RoutedEventArgs e)
    root.GetVector()...
    list Count=4
    list1[0]=String1
    list1[0]=String1
    list1[0]=String1
    root.GetVector()...
    list Count=4
    list1[0]=String1
    list1[0]=String1
    list1[0]=String1
    root.GetVector()...
    list Count=4
    list1[0]=String1
    list1[0]=String1
    list1[0]=String1
    root.GetVector()...
    list Count=4
    list1[0]=String1
    list1[0]=String1
    list1[0]=String1
    root.GetVector()...
    list Count=4
    list1[0]=String1
    list1[0]=String1
    list1[0]=String1


    Christophe Pichaud


    Sunday, April 13, 2014 9:06 AM
  • The point is only about the vector of HSTRING because with the same vector, provided by my Vector<T> template, using integers, there are no problem. This code that enumerates the data, insert and modify works great:

            private void Button_Click_VectorInt(object sender, RoutedEventArgs e)
            {
                try
                {
                    // C# XAML APP using Root::GetVectorInt()
                    Root root = new Root();
                    IList<int> list1 = root.GetVectorInt();
                    LogInfo("list Count=" + list1.Count.ToString());
                    foreach (int i in list1)
                    {
                        LogInfo("int: " + i.ToString());
                    }
                    list1[0] = 11;
                    list1[1] = 22;
                    list1.Add(1001);
                    list1.Insert(0, 1);
                    LogInfo("list Count=" + list1.Count.ToString());
                    foreach (int i in list1)
                    {
                        LogInfo("int: " + i.ToString());
                    }
                }
                catch (Exception ex)
                {
                    LogInfo("Exception! " + ex.Message + " " + ex.StackTrace);
                }
            }
    


    Christophe Pichaud

    Sunday, April 13, 2014 9:18 AM
  • Hello,

    I have previously asked a question in the Windows Store Apps forum with C++ but I have 0 responses.

    Here is my thread: Handling HSTRING with a vector wrapper Question

    I have a Vector<T> that basically wraps the std::vector for using it with Windows Runtime Collections. When I deal with integer or custom data types, there are no problem, I can iterate, retrieve, add, update elements... But when I use HSTRING, I have encountered some problems.

    The data are retrieved the first time, then it fails !



    Christophe Pichaud

    Wednesday, April 16, 2014 1:03 PM
  • I'm not exactly familiar with WinRT and its HSTRING but shouldn't you use a vector<HString> instead of vector<HSTRING>? HSTRING is reference counted, presumably something needs to deal with increasing the reference count of the string when it is handed out to the outside world.


    Thursday, April 17, 2014 6:07 AM
  • Hi,

    Thanks for posting here. But this issue is more related with WinRT, windows store apps forum is more proper for this issue. VC++ forum aims to discuss and ask questions about the Visual C++ IDE, libraries, samples, tools, setup, and windows programming using MFC and ATL. Hope you can understand.

    May


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, April 17, 2014 8:59 AM
  • Hello,

    You are partially right. HSTRING is ref counted. So I can't store it directly... I need to increment its ref counter and use a wrapper for my vector handler. This is also true for handling interface pointers for custom types, I can't store them directly, I need to use a ComPtr. So here is the magical wrap stuff:

    		template <typename T>
    		struct Wrap
    		{
    			typename typedef T type;
    			static const T& MakeWrap(const T& t)
    			{
    				return t;
    			}
    			static const T& Unwrap(const T& t)
    			{
    				return t;
    			}
    		};
    
    		template <>
    		struct Wrap<HSTRING>
    		{
    			typedef HStringHelper type;
    			static HStringHelper MakeWrap(const HSTRING& t)
    			{
    				HStringHelper str;
    				str.Set(t);
    				return str;
    			}
    			static HSTRING Unwrap(const HStringHelper& t)
    			{
    				HSTRING str;
    				HRESULT hr = t.CopyTo(&str);
    				// Error check
    				return str;
    			}
    		};
    
    		template <typename T>
    		struct Wrap<T*>
    		{
    			typename typedef ComPtr<T> type;
    			static ComPtr<T> MakeWrap(T* t)
    			{
    				ComPtr<T> ptr;
    				ptr.Attach(t);
    				return ptr;
    			}
    			static T* Unwrap(ComPtr<T> t)
    			{
    				ComPtr<T> ptr(t);
    				return t.Detach();
    			}
    		};
    

    And my vector template class is now made with this:

    		template <class T>
    		class Iterator : public RuntimeClass<IIterator<T>>
    		{
    			InspectableClass(L"Library1.Iterator", BaseTrust)
    
    		private:
    			typedef typename std::vector<typename Wrap<T>::type> WrappedVector;
    			typedef typename std::shared_ptr<WrappedVector> V;
    			typedef typename WrappedVector::iterator IT;
    
    		public:
    			Iterator() {} 
    
    			void LogVectorContent()
    			{
    				for (IT it = _v->begin(); it != _v->end(); it++)
    				{
    					T element = Wrap<T>::Unwrap(*it);
    					void * ptr = (void *)element;
    					wchar_t sz[255];
    					swprintf(sz, 255, L"adress T =0x%08x\n", (int)ptr);
    					_LogInfo(sz);
    				}
    			}
    
    			HRESULT Init(const V& vec)
    			{
    				try {
    					_LogInfo(L"Iterator::Init()...");
    
    				_v = vec;
    				
    				LogVectorContent();
    
    				_it = _v->begin();
    				if (_it != _v->end())
    				{
    					_element = Wrap<T>::Unwrap(*_it);
    					_bElement = TRUE;
    				}
    				else
    					_bElement = FALSE;
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::Init()...");
    			}
    
    		public:
    			virtual HRESULT STDMETHODCALLTYPE get_Current(T *current)
    			{
    				try {
    					_LogInfo(L"Iterator::get_Current()...");
    				if (_it != _v->end())
    				{
    					_bElement = TRUE;
    					_element = Wrap<T>::Unwrap(*_it);
    					*current = _element;
    				}
    				else
    				{
    					_bElement = FALSE;
    				}
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::get_Current()...");
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE get_HasCurrent(boolean *hasCurrent)
    			{
    				try {
    					_LogInfo(L"Iterator::get_HasCurrent()...");
    				if (_bElement)
    					*hasCurrent = TRUE;
    				else
    					*hasCurrent = FALSE;
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::get_HasCurrent()...");
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE MoveNext(boolean *hasCurrent)
    			{
    				try {
    					_LogInfo(L"Iterator::MoveNext()...");
    				if (_it != _v->end())
    				{
    					++_it;
    					if (_it == _v->end())
    					{
    						*hasCurrent = FALSE;
    						_bElement = FALSE;
    					}
    					else
    					{
    						*hasCurrent = TRUE;
    						_bElement = TRUE;
    					}
    				}
    				else
    				{
    					*hasCurrent = FALSE;
    					_bElement = FALSE;
    				}
    				return S_OK;
    				_EXCEPTION_HANDLER(L"Iterator::MoveNext()...");
    			}
    
    		private:
    			V _v;
    			IT _it;
    			T _element;
    			boolean _bElement = FALSE;
    		};
    
    		template <typename T>
    		class Vector : public RuntimeClass<IVector<T>, 
    			IIterable<T >>
    		{
    			InspectableClass(L"Library1.Vector", BaseTrust)
    
    		private:
    			typedef typename std::vector<typename Wrap<T>::type> WrappedVector;
    			typedef typename WrappedVector::const_iterator CIT;
    
    		public:
    			Vector() 
    			{
    				_LogInfo(L"Vector::Vector()...");
    				_v = std::make_shared<WrappedVector>();
    			}
    
    		public:
    			// read methods
    			virtual HRESULT STDMETHODCALLTYPE GetAt(unsigned index, T *item)
    			{
    				_LogInfo(L"Vector::GetAt()...");
    				*item = Wrap<T>::Unwrap((*_v)[index]);
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE get_Size(unsigned *size)
    			{
    				_LogInfo(L"Vector::get_Size()...");
    				*size = _v->size();
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE GetView(IVectorView<T> **view)
    			{
    				_LogInfo(L"Vector::GetView()...");
    				return E_NOTIMPL;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE IndexOf(T value, unsigned *index, boolean *found)
    			{
    				_LogInfo(L"Vector::IndexOf()...");
    				unsigned foundedIndex = 0;
    				bool founded = false;
    				for (CIT it = _v->cbegin() ; it != _v->end() ; ++it)
    				{
    					const T & v = Wrap<T>::Unwrap(*it);
    					if (v == value)
    					{
    						founded = true;
    						break;
    					}
    					foundedIndex++;
    				}
    				if (founded == true)
    				{
    					*found = TRUE;
    					*index = foundedIndex;
    				}
    				else
    				{
    					*found = FALSE;
    				}
    				return S_OK;
    			}
    
    			// write methods
    			virtual HRESULT STDMETHODCALLTYPE SetAt(unsigned index, T item)
    			{
    				_LogInfo(L"Vector::SetAt()...");
    				if (index < _v->size())
    				{
    					(*_v)[index] = Wrap<T>::MakeWrap(item);
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE InsertAt(unsigned index, T item)
    			{
    				_LogInfo(L"Vector::InsertAt()...");
    				_v->insert(_v->begin() + index, Wrap<T>::MakeWrap(item));
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE RemoveAt(unsigned index)
    			{
    				_LogInfo(L"Vector::RemoveAt()...");
    				if (index < _v->size())
    				{
    					_v->erase(_v->begin() + index);
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE Append(T item)
    			{
    				_LogInfo(L"Vector::Append()...");
    				_v->push_back(Wrap<T>::MakeWrap(item));
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE RemoveAtEnd()
    			{
    				_LogInfo(L"Vector::RemoveAtEnd()...");
    				if (!_v->empty())
    				{
    					_v->pop_back();
    				}
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE Clear()
    			{
    				_LogInfo(L"Vector::Clear()...");
    				_v->clear();
    				return S_OK;
    			}
    
    			virtual HRESULT STDMETHODCALLTYPE First(IIterator<T> **first)
    			{
    				_LogInfo(L"Vector::First()...");
    				ComPtr<Iterator<T>> p = Make<Iterator<T>>();
    				p->Init(_v);
    				*first = p.Detach();
    				return S_OK;
    			}
    
    		private:
    			std::shared_ptr<WrappedVector> _v;
    		};
    

    Elements are wrapped and unwrapped.

    Christophe Pichaud

    Wednesday, April 23, 2014 12:55 AM