//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//
// TypeTesterDlg.cpp : plik implementacji
//

#include "stdafx.h"
#include "TypeTester.h"
#include "TypeTesterDlg.h"
#include "CorError.h"
#include "Cderr.h"
#include <string>
#include <sstream>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// Okno dialogowe używane przez CAboutDlg App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dane okna dialogowego
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // Obsługa DDX/DDV

// Implementacja
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


_ATL_FUNC_INFO CComTypeEvents::OnColorChangedInfo    = {CC_STDCALL, VT_EMPTY, 1, { VT_UI4 }};
_ATL_FUNC_INFO CComTypeEvents::OnDateChangedInfo     = {CC_STDCALL, VT_EMPTY, 1, { VT_DATE }};
_ATL_FUNC_INFO CComTypeEvents::OnNameChangedInfo     = {CC_STDCALL, VT_EMPTY, 1, { VT_BSTR }};
_ATL_FUNC_INFO CComTypeEvents::OnDecimalChangedInfo  = {CC_STDCALL, VT_EMPTY, 1, { VT_DECIMAL }};
_ATL_FUNC_INFO CComTypeEvents::OnVariantChangedInfo  = {CC_STDCALL, VT_EMPTY, 1, { VT_VARIANT }};
_ATL_FUNC_INFO CComTypeEvents::OnArrayChangedInfo    = {CC_STDCALL, VT_EMPTY, 1, { VT_ARRAY | VT_VARIANT }};
_ATL_FUNC_INFO CComTypeEvents::OnCounterInfo         = {CC_STDCALL, VT_EMPTY, 1, { VT_I4 }};

void __stdcall CComTypeEvents::OnColorChanged(OLE_COLOR varColor)
{
	pNotifyWindow->PostMessage(WM_COMINTEROP_COLORCHANGED, 0, 0);
}
void __stdcall CComTypeEvents::OnDateChanged(DATE date)
{
	pNotifyWindow->PostMessage(WM_COMINTEROP_DATECHANGED, 0, 0);
}
void __stdcall CComTypeEvents::OnNameChanged(BSTR bstrName)
{
	pNotifyWindow->PostMessage(WM_COMINTEROP_NAMECHANGED, 0, 0);
}
void __stdcall CComTypeEvents::OnDecimalChanged(DECIMAL currency)
{
	pNotifyWindow->PostMessage(WM_COMINTEROP_DECIMALCHANGED, 0, 0);
}
void __stdcall CComTypeEvents::OnVariantChanged(VARIANT varVariant)
{
	pNotifyWindow->PostMessage(WM_COMINTEROP_VARIANTCHANGED, 0, 0);
}
void __stdcall CComTypeEvents::OnArrayChanged(SAFEARRAY* sa)
{
	pNotifyWindow->PostMessage(WM_COMINTEROP_ARRAYCHANGED, 0, 0);
}
void __stdcall CComTypeEvents::OnCounter(long c)
{
	pNotifyWindow->PostMessage(WM_COMINTEROP_COUNTER, (WPARAM)c, 0);
}
// Okno dialogowe CTypeTesterDlg

CTypeTesterDlg::CTypeTesterDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTypeTesterDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	pNotify = NULL;
	pSafeArray = NULL;
}

void CTypeTesterDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_INPUTCOLOR, inputColorControl);
	DDX_Control(pDX, IDC_INPUTDATE, inputDateControl);
	DDX_Control(pDX, IDC_INPUTDECIMAL, inputDecimalControl);
	DDX_Control(pDX, IDC_INPUTSTRING, inputStringControl);
	DDX_Control(pDX, IDC_INPUTVARIANT, inputVariantControl);
	DDX_Control(pDX, IDC_OUTPUTCOLOR, outputColorControl);
	DDX_Control(pDX, IDC_OUTPUTDATE, outputDateControl);
	DDX_Control(pDX, IDC_OUTPUTDECIMAL, outputDecimalControl);
	DDX_Control(pDX, IDC_OUTPUTSTRING, outputStringControl);
	DDX_Control(pDX, IDC_OUTPUTVARIANT, outputVariantControl);
	DDX_Control(pDX, IDC_COUNTER, counterControl);
	DDX_Control(pDX, IDC_ERRORTEXT, errorTextControl);
	DDX_Control(pDX, IDC_ERRORLIST, errorListControl);
	DDX_Control(pDX, IDC_INPUTARRAY, inputArrayControl);
	DDX_Control(pDX, IDC_OUTPUTARRAY, outputArrayControl);
}

BEGIN_MESSAGE_MAP(CTypeTesterDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_COLORBUTTON, OnColorClicked)
	ON_BN_CLICKED(IDC_DATEBUTTON, OnDateClicked)
	ON_BN_CLICKED(IDC_DECIMALBUTTON, OnDecimalClicked)
	ON_BN_CLICKED(IDC_STRINGBUTTON, OnStringClicked)
	ON_BN_CLICKED(IDC_VARIANTBUTTON, OnVariantClicked)
	ON_BN_CLICKED(IDC_ERRORBUTTON, OnErrorClicked)
	ON_CBN_SELCHANGE(IDC_ERRORLIST, OnErrorSelectChanged)
	ON_MESSAGE(WM_COMINTEROP_COUNTER, OnCounter)
	ON_MESSAGE(WM_COMINTEROP_COLORCHANGED, OnColorChanged)
	ON_MESSAGE(WM_COMINTEROP_DATECHANGED, OnDateChanged)
	ON_MESSAGE(WM_COMINTEROP_NAMECHANGED, OnNameChanged)
	ON_MESSAGE(WM_COMINTEROP_DECIMALCHANGED, OnDecimalChanged)
	ON_MESSAGE(WM_COMINTEROP_VARIANTCHANGED, OnVariantChanged)
	ON_MESSAGE(WM_COMINTEROP_ARRAYCHANGED, OnArrayChanged)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_ARRAYBUTTON, OnArrayClicked)
	ON_BN_CLICKED(IDC_ENUMBUTTON, OnEnumClicked)
END_MESSAGE_MAP()


// Procedury obsługi wiadomości CTypeTesterDlg

BOOL CTypeTesterDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Dodanie elementu menu "O programie..." do menu systemowego.

	CButton *pb = (CButton*)GetDlgItem(IDC_ENUMBUTTON);
	pb->EnableWindow(FALSE);

	// IDM_ABOUTBOX musi znajdować się w zasięgu poleceń systemowych.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Ustawienie ikonki dla tego okna dialogowego. Struktura wykonuje to automatycznie,
	//  jeśli główne okno aplikacji nie jest oknem dialogowym.
	SetIcon(m_hIcon, TRUE);			// Ustawienie dużej ikonki
	SetIcon(m_hIcon, FALSE);		// Ustawienie małej ikonki

	HRESULT hr = comTypes.CoCreateInstance(__uuidof(dotNETCOMTypes::CComTypes));
	if(FAILED(hr))
		return FALSE;

	hr = CComObject<CComTypeEvents>::CreateInstance(&pNotify);
	if(SUCCEEDED(hr) &&
	   pNotify != NULL)
	{
		pNotify->AddRef();
		hr = pNotify->DispEventAdvise(comTypes,
		                              &dotNETCOMTypes::DIID__IComTypesEvents);
		if(FAILED(hr))
		{
			CString msg;
			msg.Format(_T("Działanie DispEventAdvise nie powiodło się - 0x%0X!"), hr);
			ATLTRACE(msg);
			pNotify->Release();
			pNotify = NULL;
			comTypes = NULL;
			return FALSE;
		}
		pNotify->SetNotifyWindow(this);
	}
	int index;

	index = errorListControl.AddString(L"COR_E_APPLICATION");
	errorListControl.SetItemData(index, COR_E_APPLICATION);

	index = errorListControl.AddString(L"COR_E_ARGUMENT");
	errorListControl.SetItemData(index, COR_E_ARGUMENT);

	index = errorListControl.AddString(L"E_INVALIDARG");
	errorListControl.SetItemData(index, E_INVALIDARG);

	index = errorListControl.AddString(L"COR_E_ARGUMENTOUTOFRANGE");
	errorListControl.SetItemData(index, COR_E_ARGUMENTOUTOFRANGE);

	index = errorListControl.AddString(L"COR_E_ARITHMETIC");
	errorListControl.SetItemData(index, COR_E_ARITHMETIC);

	index = errorListControl.AddString(L"ERROR_ARITHMETIC_OVERFLOW");
	errorListControl.SetItemData(index, COR_E_ARITHMETIC);

	index = errorListControl.AddString(L"COR_E_ARRAYTYPEMISMATCH");
	errorListControl.SetItemData(index, COR_E_ARRAYTYPEMISMATCH);

	index = errorListControl.AddString(L"COR_E_BADIMAGEFORMAT");
	errorListControl.SetItemData(index, COR_E_BADIMAGEFORMAT);

	index = errorListControl.AddString(L"ERROR_BAD_FORMAT");
	errorListControl.SetItemData(index, HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));

	index = errorListControl.AddString(L"COR_E_CONTEXTMARSHAL");
	errorListControl.SetItemData(index, COR_E_CONTEXTMARSHAL);

	index = errorListControl.AddString(L"NTE_FAIL");
	errorListControl.SetItemData(index, NTE_FAIL);

	index = errorListControl.AddString(L"COR_E_DIRECTORYNOTFOUND");
	errorListControl.SetItemData(index, COR_E_DIRECTORYNOTFOUND);

	index = errorListControl.AddString(L"ERROR_PATH_NOT_FOUND");
	errorListControl.SetItemData(index, HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND));

	index = errorListControl.AddString(L"COR_E_DIVIDEBYZERO");
	errorListControl.SetItemData(index, COR_E_DIVIDEBYZERO);

	index = errorListControl.AddString(L"COR_E_DUPLICATEWAITOBJECT");
	errorListControl.SetItemData(index, COR_E_DUPLICATEWAITOBJECT);

	index = errorListControl.AddString(L"COR_E_ENDOFSTREAM");
	errorListControl.SetItemData(index, COR_E_ENDOFSTREAM);

	index = errorListControl.AddString(L"COR_E_TYPELOAD");
	errorListControl.SetItemData(index, COR_E_TYPELOAD);

	index = errorListControl.AddString(L"COR_E_EXCEPTION");
	errorListControl.SetItemData(index, COR_E_EXCEPTION);

	index = errorListControl.AddString(L"COR_E_EXECUTIONENGINE");
	errorListControl.SetItemData(index, COR_E_EXECUTIONENGINE);

	index = errorListControl.AddString(L"COR_E_FIELDACCESS");
	errorListControl.SetItemData(index, COR_E_FIELDACCESS);

	index = errorListControl.AddString(L"COR_E_FILENOTFOUND");
	errorListControl.SetItemData(index, COR_E_FILENOTFOUND);

	index = errorListControl.AddString(L"ERROR_FILE_NOT_FOUND");
	errorListControl.SetItemData(index, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));

	index = errorListControl.AddString(L"COR_E_FORMAT");
	errorListControl.SetItemData(index, COR_E_FORMAT);

	index = errorListControl.AddString(L"COR_E_INDEXOUTOFRANGE");
	errorListControl.SetItemData(index, COR_E_INDEXOUTOFRANGE);

	index = errorListControl.AddString(L"COR_E_INVALIDCAST");
	errorListControl.SetItemData(index, COR_E_INVALIDCAST);

	index = errorListControl.AddString(L"E_NOINTERFACE");
	errorListControl.SetItemData(index, E_NOINTERFACE);

	index = errorListControl.AddString(L"COR_E_INVALIDCOMOBJECT");
	errorListControl.SetItemData(index, COR_E_INVALIDCOMOBJECT);

	index = errorListControl.AddString(L"COR_E_INVALIDFILTERCRITERIA");
	errorListControl.SetItemData(index, COR_E_INVALIDFILTERCRITERIA);

	index = errorListControl.AddString(L"COR_E_INVALIDOLEVARIANTTYPE");
	errorListControl.SetItemData(index, COR_E_INVALIDOLEVARIANTTYPE);

	index = errorListControl.AddString(L"COR_E_INVALIDOPERATION");
	errorListControl.SetItemData(index, COR_E_INVALIDOPERATION);

	index = errorListControl.AddString(L"COR_E_IO");
	errorListControl.SetItemData(index, COR_E_IO);

	index = errorListControl.AddString(L"COR_E_MEMBERACCESS");
	errorListControl.SetItemData(index, COR_E_MEMBERACCESS);

	index = errorListControl.AddString(L"COR_E_METHODACCESS");
	errorListControl.SetItemData(index, COR_E_METHODACCESS);

	index = errorListControl.AddString(L"COR_E_MISSINGFIELD");
	errorListControl.SetItemData(index, COR_E_MISSINGFIELD);

	index = errorListControl.AddString(L"COR_E_MISSINGMANIFESTRESOURCE");
	errorListControl.SetItemData(index, COR_E_MISSINGMANIFESTRESOURCE);

	index = errorListControl.AddString(L"COR_E_MISSINGMEMBER");
	errorListControl.SetItemData(index, COR_E_MISSINGMEMBER);

	index = errorListControl.AddString(L"COR_E_MISSINGMETHOD");
	errorListControl.SetItemData(index, COR_E_MISSINGMETHOD);

	index = errorListControl.AddString(L"COR_E_MULTICASTNOTSUPPORTED");
	errorListControl.SetItemData(index, COR_E_MULTICASTNOTSUPPORTED);

	index = errorListControl.AddString(L"COR_E_NOTFINITENUMBER");
	errorListControl.SetItemData(index, COR_E_NOTFINITENUMBER);

	index = errorListControl.AddString(L"E_NOTIMPL");
	errorListControl.SetItemData(index, E_NOTIMPL);

	index = errorListControl.AddString(L"COR_E_NOTSUPPORTED");
	errorListControl.SetItemData(index, COR_E_NOTSUPPORTED);

	index = errorListControl.AddString(L"COR_E_NULLREFERENCE");
	errorListControl.SetItemData(index, COR_E_NULLREFERENCE);

	index = errorListControl.AddString(L"E_POINTER");
	errorListControl.SetItemData(index, E_POINTER);

	index = errorListControl.AddString(L"COR_E_OUTOFMEMORY");
	errorListControl.SetItemData(index, COR_E_OUTOFMEMORY);

	index = errorListControl.AddString(L"COR_E_OVERFLOW");
	errorListControl.SetItemData(index, COR_E_OVERFLOW);

	index = errorListControl.AddString(L"COR_E_PATHTOOLONG");
	errorListControl.SetItemData(index, COR_E_PATHTOOLONG);

	index = errorListControl.AddString(L"ERROR_FILENAME_EXCED_RANGE");
	errorListControl.SetItemData(index, HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE));

	index = errorListControl.AddString(L"COR_E_RANK");
	errorListControl.SetItemData(index, COR_E_RANK);

	index = errorListControl.AddString(L"COR_E_REFLECTIONTYPELOAD");
	errorListControl.SetItemData(index, COR_E_REFLECTIONTYPELOAD);

	index = errorListControl.AddString(L"COR_E_REMOTING");
	errorListControl.SetItemData(index, COR_E_REMOTING);

	index = errorListControl.AddString(L"COR_E_SAFEARRAYTYPEMISMATCH");
	errorListControl.SetItemData(index, COR_E_SAFEARRAYTYPEMISMATCH);

	index = errorListControl.AddString(L"COR_E_SECURITY");
	errorListControl.SetItemData(index, COR_E_SECURITY);

	index = errorListControl.AddString(L"COR_E_SERIALIZATION");
	errorListControl.SetItemData(index, COR_E_SERIALIZATION);

	index = errorListControl.AddString(L"COR_E_STACKOVERFLOW");
	errorListControl.SetItemData(index, COR_E_STACKOVERFLOW);

	index = errorListControl.AddString(L"ERROR_STACK_OVERFLOW");
	errorListControl.SetItemData(index, HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW));

	index = errorListControl.AddString(L"COR_E_SYNCHRONIZATIONLOCK");
	errorListControl.SetItemData(index, COR_E_SYNCHRONIZATIONLOCK);

	index = errorListControl.AddString(L"COR_E_SYSTEM");
	errorListControl.SetItemData(index, COR_E_SYSTEM);

	index = errorListControl.AddString(L"COR_E_TARGET");
	errorListControl.SetItemData(index, COR_E_TARGET);

	index = errorListControl.AddString(L"COR_E_TARGETINVOCATION");
	errorListControl.SetItemData(index, COR_E_TARGETINVOCATION);

	index = errorListControl.AddString(L"COR_E_TARGETPARAMCOUNT");
	errorListControl.SetItemData(index, COR_E_TARGETPARAMCOUNT);

	index = errorListControl.AddString(L"COR_E_THREADABORTED");
	errorListControl.SetItemData(index, COR_E_THREADABORTED);

	index = errorListControl.AddString(L"COR_E_THREADINTERRUPTED");
	errorListControl.SetItemData(index, COR_E_THREADINTERRUPTED);

	index = errorListControl.AddString(L"COR_E_THREADSTATE");
	errorListControl.SetItemData(index, COR_E_THREADSTATE);

	index = errorListControl.AddString(L"COR_E_THREADSTOP");
	errorListControl.SetItemData(index, COR_E_THREADSTOP);

	index = errorListControl.AddString(L"COR_E_TYPELOAD");
	errorListControl.SetItemData(index, COR_E_TYPELOAD);

	index = errorListControl.AddString(L"COR_E_TYPEINITIALIZATION");
	errorListControl.SetItemData(index, COR_E_TYPEINITIALIZATION);

	index = errorListControl.AddString(L"COR_E_VERIFICATION");
	errorListControl.SetItemData(index, COR_E_VERIFICATION);

	index = errorListControl.AddString(L"E_FAIL");
	errorListControl.SetItemData(index, E_FAIL);
	
	errorListControl.SetCurSel(0);

	return TRUE;  // zwrócenie TRUE, chyba że ognisko ustawiono na element sterujący
}

void CTypeTesterDlg::OnDestroy()
{
	CDialog::OnDestroy();

	if(pSafeArray)
	{
		SafeArrayDestroy(pSafeArray);
		pSafeArray = NULL;
	}

	if(pNotify)
	{
		HRESULT hr = pNotify->DispEventUnadvise(comTypes,
		                                        &dotNETCOMTypes::DIID__IComTypesEvents);
		if(FAILED(hr))
		{
			ATLTRACE(_T("Działanie DispEventUnadvise dla CTypeTesterDlg nie powiodło się - 0x%0x\n"), hr);
		}
		pNotify->Release();
		pNotify = NULL;
	}

}

void CTypeTesterDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// Jeśli do okna dialogowego zostanie dodany przycisk minimalizacji, poniższy kod będzie niezbędny
//  do przeciągania ikonki. W przypadku aplikacji MFC korzystających z modelu dokument/widok
//  zostanie to wykonane automatycznie przez strukturę.

void CTypeTesterDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // kontekst urządzenia służący do rysowania

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Wypośrodkowanie ikonki w prostokącie klienta
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Rysowanie ikonki
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// System wywołuje tę funkcję w celu uzyskania wskaźnika, kiedy użytkownik przeciąga
//  zminimalizowane okno.
HCURSOR CTypeTesterDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}
void CTypeTesterDlg::OnColorClicked()
{
	CHOOSECOLOR cc;                 // struktura typowego okna dialogowego
	static COLORREF acrCustClr[16]; // tablica własnych kolorów 
	static DWORD rgbCurrent;        // wybór początkowego koloru

	// Initialize CHOOSECOLOR 
	ZeroMemory(&cc, sizeof(CHOOSECOLOR));
	cc.lStructSize = sizeof(CHOOSECOLOR);
	cc.hwndOwner = NULL;
	cc.lpCustColors = (LPDWORD) acrCustClr;
	cc.rgbResult = rgbCurrent;
	cc.Flags = CC_FULLOPEN | CC_RGBINIT;
	 
	if (ChooseColor(&cc)==TRUE)
	{
		rgbCurrent = cc.rgbResult;
		OLE_COLOR c = (OLE_COLOR)rgbCurrent;
		comTypes->ColorValue = c;
	}
	else
	{
		DWORD dwError = CommDlgExtendedError();
		switch(dwError)
		{
		case CDERR_DIALOGFAILURE:
			ATLTRACE("Utworzenie okna dialogowego nie było możliwe. Wywołanie funkcji okna dialogowego do funkcji DialogBox nie powiodło się. Ten błąd może wystąpić, jeśli jedno z wywołań zawiera błędny uchwyt okna.");
			break;
		case CDERR_FINDRESFAILURE:
			ATLTRACE("Funkcja okna dialogowego nie odnalazła podanego zasobu.");
			break;
		case CDERR_INITIALIZATION:
			ATLTRACE("Działanie funkcji okna dialogowego zostało przerwane w czasie inicjalizacji. Ten błąd występuje często w przypadku braku pamięci.");
			break;
		case CDERR_LOADRESFAILURE:
			ATLTRACE("Funkcja okna dialogowego nie mogła załadować podanego zasobu.");
			break;
		case CDERR_LOADSTRFAILURE:
			ATLTRACE("Funkcja okna dialogowego nie mogła załadować podanego ciągu.");
			break;
		case CDERR_LOCKRESFAILURE:
			ATLTRACE("Funkcja okna dialogowego nie mogła zablokować podanego zasobu.");
			break;
		case CDERR_MEMALLOCFAILURE:
			ATLTRACE("Funkcja okna dialogowego nie mogła alokować pamięci dla wewnętrznych struktur.");
			break;
		case CDERR_MEMLOCKFAILURE:
			ATLTRACE("Funkcja okna dialogowego nie mogła zablokować pamięci związanej z uchwytem.");
			break;
		case CDERR_NOHINSTANCE:
			ATLTRACE("Znacznik ENABLETEMPLATE został ustawiony w elemencie składowym Flags struktury inicjalizacji dla okna dialogowego, ale nie podano odpowiedniego uchwytu egzemplarza.");
			break;
		case CDERR_NOHOOK:
			ATLTRACE("Znacznik ENABLEHOOK został ustawiony w elemencie składowym Flags struktury inicjalizacji dla okna dialogowego, ale nie podano wskaźnika do odpowiedniej procedury haka.");
			break;
		case CDERR_NOTEMPLATE:
			ATLTRACE("Znacznik ENABLETEMPLATE został ustawiony w elemencie składowym Flags struktury inicjalizacji dla okna dialogowego, ale nie podano odpowiedniego szablonu.");
			break;
		case CDERR_REGISTERMSGFAIL:
			ATLTRACE("Funkcja RegisterWindowMessage zwróciła kod błędu po wywołaniu przez funkcję okna dialogowego.");
			break;
		case CDERR_STRUCTSIZE:
			ATLTRACE("Element składowy lStructSize struktury inicjalizacji okna dialogowego jest niepoprawny.");
			break;
		default:
			ATLTRACE("NIEZNANY BŁĄD KOLORU");
			break;
		}
	}
}

void CTypeTesterDlg::OnDateClicked()
{
	TCHAR buffer[128];
	inputDateControl.GetWindowText(buffer, sizeof(buffer));
	COleDateTime dt;
	BOOL ret = dt.ParseDateTime(buffer);
	if(ret)
	{
		comTypes->Date = dt;
	}
}

void CTypeTesterDlg::OnDecimalClicked()
{
	TCHAR buffer[128];
	inputDecimalControl.GetWindowText(buffer, sizeof(buffer));
	_variant_t c = buffer;
	try
	{
		c.ChangeType(VT_DECIMAL);
		comTypes->Decimal = c.decVal;
	}
	catch(_com_error)
	{
	}
}

void CTypeTesterDlg::OnStringClicked()
{
	TCHAR buffer[128];
	inputStringControl.GetWindowText(buffer, sizeof(buffer));
	comTypes->Name = buffer;
}

void CTypeTesterDlg::OnVariantClicked()
{
	TCHAR buffer[128];
	inputVariantControl.GetWindowText(buffer, sizeof(buffer));
	_variant_t v = buffer;
	try
	{
		if(_wtoi(buffer) != 0 &&
			wcschr(buffer, L'.') == NULL)
			v.ChangeType(VT_I4);
		else if(_wtof(buffer) != 0)
			v.ChangeType(VT_R4);
	}
	catch(_com_error)
	{
	}
	comTypes->Variant = v;
}

void CTypeTesterDlg::OnArrayClicked()
{
	TCHAR buffer[128];
	int index = inputArrayControl.GetWindowText(buffer, sizeof(buffer));
	int fn = 0;
	int in = 0;
	int sn = 0;
	std::wstring str = buffer;
	std::wstring sub;
	std::wstring::size_type pos;
	std::wstring::size_type bpos = 0;
	std::wstring::size_type spos;
	int count = 1;
	while((pos = str.find(L',', bpos)) != std::wstring::npos)
	{
		sub = str.substr(bpos, pos - bpos);
		if((spos = sub.find_first_not_of(L"0123456789")) != std::wstring::npos)
		{
			if(sub[spos] == L'.')
			{
				if((spos = sub.find_first_not_of(L"0123456789", spos + 1)) == std::wstring::npos)
					fn++;
				else
					sn++;
			}
			else
				sn++;
		}
		else
			in++;
		count++;
		bpos = pos + 1;
	}
	sub = str.substr(bpos, std::string::npos);
	if((spos = sub.find_first_not_of(L"0123456789")) != std::wstring::npos)
	{
		if(sub[spos] == L'.')
		{
			if((spos = sub.find_first_not_of(L"0123456789", spos + 1)) == std::wstring::npos)
				fn++;
			else
				sn++;
		}
		else
			sn++;
	}
	else
		in++;

	if(pSafeArray)
	{
		SafeArrayDestroy(pSafeArray);
		pSafeArray = NULL;
	}
	pSafeArray = SafeArrayCreateVector(VT_VARIANT, 0, count);
	VARIANT *pva;
	SafeArrayAccessData(pSafeArray, (void **)&pva);
	_variant_t item;
	bpos = 0;
	if(sn > 0)
	{
		sn = 0;
		// Jeśli jeden z elementów jest ciągiem, to wszystkie są ciągami
		while((pos = str.find(L',', bpos)) != std::wstring::npos)
		{
			sub = str.substr(bpos, pos - bpos);
			item = sub.c_str();
			pva[sn++] = item;
			bpos = pos + 1;
		}
		sub = str.substr(bpos, std::string::npos);
		item = sub.c_str();
		pva[sn++] = item;
	}
	else if(fn > 0)
	{
		fn = 0;
		// Jeśli jeden z elementów jest liczbą zmiennoprzecinkową, to wszystkie są takimi liczbami
		while((pos = str.find(L',', bpos)) != std::wstring::npos)
		{
			sub = str.substr(bpos, pos - bpos);
			item = (float)_wtof(sub.c_str());
			pva[fn++] = item;
			bpos = pos + 1;
		}
		sub = str.substr(bpos, std::string::npos);
		item = (float)_wtof(sub.c_str());
		pva[fn++] = item;
	}
	else
	{
		in = 0;
		// Tylko jeśli wszystkie elementy są liczbami całkowitymi
		while((pos = str.find(L',', bpos)) != std::wstring::npos)
		{
			sub = str.substr(bpos, pos - bpos);
			item = _wtoi(sub.c_str());
			pva[in++] = item;
			bpos = pos + 1;
		}
		sub = str.substr(bpos, std::string::npos);
		item = _wtoi(sub.c_str());
		pva[in++] = item;
	}
	SafeArrayUnaccessData(pSafeArray);
	comTypes->Array = pSafeArray;
	CButton *pb = (CButton*)GetDlgItem(IDC_ENUMBUTTON);
	pb->EnableWindow();
}

void CTypeTesterDlg::OnEnumClicked()
{
	IEnumVARIANT *pe = comTypes->Enumerator;
	long nelem = 1;
	CComVariant v;
	ULONG n = 0;
	_bstr_t b;
	std::wstring so;
	while(pe->Next(nelem, &v, &n) == S_OK)
	{
		v.ChangeType(VT_BSTR);
		b = v;
		so += std::wstring(b) + std::wstring(L" ");
	}
	CEdit *pedit = (CEdit *)GetDlgItem(IDC_OUTPUTENUM);
	pedit->SetWindowText(so.c_str());
}

void CTypeTesterDlg::OnErrorClicked()
{
	if(errorListControl.GetCurSel() == CB_ERR)
		errorListControl.SetCurSel(0);
	TCHAR buffer[128];
	int index = errorListControl.GetCurSel();
	errorListControl.GetLBText(index, buffer);
	HRESULT hr = comTypes->raw_ErrorTest(_bstr_t(buffer));
	errorTextControl.SetSel(0, -1);

	std::wostringstream wmsg;
	if(hr == errorListControl.GetItemData(index))
		wmsg << L"ErrorTest zwrócił " << buffer << L".\r\n";
	else
		wmsg << L"ErrorTest zwrócił 0x" << std::hex << hr << L".\r\n";

	CComQIPtr<ISupportErrorInfo> isei = comTypes;
	hr = isei->InterfaceSupportsErrorInfo(__uuidof(dotNETCOMTypes::IComTypes));
	if(SUCCEEDED(hr))
	{
		CComPtr<IErrorInfo> iei;
		GetErrorInfo(0, &iei);
		CComBSTR description;
		iei->GetDescription(&description);
		wmsg << (LPCTSTR)description << L"\r\n";
		CComBSTR source;
		iei->GetSource(&source);
		wmsg << (LPCTSTR)source << L"\r\n";
	}

	errorTextControl.ReplaceSel(wmsg.str().c_str());
	errorTextControl.SetSel(-1, 0);
}

// Metody wyjścia

void CTypeTesterDlg::OnErrorSelectChanged()
{
	OnErrorClicked();
}

LONG CTypeTesterDlg::OnCounter(UINT wParam, LONG lParam)
{
	UINT msg = wParam;

	TCHAR buffer[128];
	_stprintf(buffer, L"%d", msg);
	counterControl.SetWindowText(buffer);

	return 0;
}

LONG CTypeTesterDlg::OnColorChanged(UINT wParam, LONG lParam)
{
	OLE_COLOR dwColor;
	// dwColor = comTypes->ColorValue;
	return 0;
}

LONG CTypeTesterDlg::OnDateChanged(UINT wParam, LONG lParam)
{
	COleDateTime dt(comTypes->Date);
	outputDateControl.SetWindowText(dt.Format(L"%A, %B %d, %Y"));
	return 0;
}

LONG CTypeTesterDlg::OnNameChanged(UINT wParam, LONG lParam)
{
	outputStringControl.SetWindowText(_bstr_t(comTypes->Name));
	return 0;
}

LONG CTypeTesterDlg::OnDecimalChanged(UINT wParam, LONG lParam)
{
	DECIMAL dwDec = comTypes->Decimal;
	_variant_t c = dwDec;
	c.ChangeType(VT_BSTR);
	_bstr_t b = c;
	outputDecimalControl.SetWindowText(b);
	return 0;
}

LONG CTypeTesterDlg::OnVariantChanged(UINT wParam, LONG lParam)
{
	_variant_t v = comTypes->Variant;
	v.ChangeType(VT_BSTR);
	_bstr_t b = v;
	outputVariantControl.SetWindowText(b);
	return 0;
}

LONG CTypeTesterDlg::OnArrayChanged(UINT wParam, LONG lParam)
{
	LPSAFEARRAY psa = comTypes->Array;

	if(SafeArrayGetDim(psa) != 1)
		return 1;

	long count = 0;
	SafeArrayGetLBound(psa, 1, &count);
	if(count != 0)
		return 1;

	SafeArrayGetUBound(psa, 1, &count);
	count++;

	VARIANT *pva;
	_variant_t item;
	_bstr_t sitem;
	std::wstring s;
	SafeArrayAccessData(psa, (void **)&pva);
	for(int i = 0; i < count; i++)
	{
		item = pva[i];
		item.ChangeType(VT_BSTR);
		sitem = item;
		if(i != count - 1)
			s += std::wstring((LPCTSTR)sitem) + std::wstring(L",");
		else
			s += std::wstring((LPCTSTR)sitem);
	}
	SafeArrayUnaccessData(psa);
	outputArrayControl.SetWindowText(s.c_str());
	return 0;
}

