Visual Studio 2008 에서 ActiveX 컴파일시

error PRJ0019: 도구에서 오류 코드를 반환했습니다

에러가 발생하면... VS2008 을 관리자 권한으로 실행시키면 됨 ㅠㅠ

'C++ > 설정' 카테고리의 다른 글

OCX CAB 로 만들기  (0) 2012.04.18
ActiveX 테스트 컨테이너  (0) 2012.04.18

UTF-8 -> Unicode

C++/기본 2012. 6. 13. 15:20 Posted by 퓨어레드
TCHAR unicodeBuf[1024];
char *szBuff = (char *) szResp;

MultiByteToWideChar (CP_UTF8, 0, szBuff, -1, unicodeBuf, 1024); 

'C++ > 기본' 카테고리의 다른 글

TCHAR 용 스트링 함수  (0) 2012.06.13
[warning C4996] "_CRT_SECURE_NO_DEPRECATE"로 해결  (0) 2012.05.02

IOCP 이용 Socket Programming 개념

C++/Network 2012. 6. 13. 15:20 Posted by 퓨어레드
음... iocp의 동작원리를 다시한번 상기해 보시기 바랍니다.
기본적으로 iocp는 proactor라는 패턴의 성격을 가지고 있습니다.
즉, 어떤 작업에 대한 선요청이 있어야지만 해당 작업을 한다는 것이죠...
reactor와 반대되는 넘입니다.
음... 풀어서 설명해보면...

iocp를 이용해서 네떡 프로그래밍 하실때 절차를 다시함 생각해보죠...

먼저 WSARecv()를 호출해 주죠?
이것은 nt kernel에게
"어이~ NT야... 네떡에서 데이터좀 받아야 쓰겠는데... 데이터 있으면
parameter로 넘기는 버퍼에 복사하구 알려줄래?"
라고 하는 의미이지 대부분의 경우 이 함수 호출즉시 실제 데이터가 수신되지는 않죠?

그러다가 실제로 요청한 세션에 데이터가 들어와 있거나 들어오는 데이터가 있다면...
하위 네떡 레이어의 수신버퍼로부터 유저가 제공한 버퍼로
복사가 일어나게 되고, 이사실을 app에게 알려주기 위해서
Kernel은 Completion Packet을 하나 생성하구 그 넘을 Iocp에 queueing하게 되겠죠...
이때가 되서야 우리는 GetQueuedCompletionStatus()를 통해 그 사실을 알게되어
실제 데이터를 얻게되구요...

음... 맞나요?

즉! 우리가 application에서 WSARecv()같은 함수를 통해서 명시적으로
operation을 posting해주지 않는다면 절대로 completion이 일어나지
않습니다. 즉, 님께서 만든 application에서 이전에 받은 데이터를 처리하고
다음 데이터를 받기위해 WSARecv()를 호출해 주지 않는 이상은
completion이 일어나지 않는다는 것이 되기때문에 iocp의 queue가 overflow되는
경우는 발생할 수 없겠죠.

음... 근데 여담으루 이런 경우는 있을 수 있겠네요...
recv posting을 엄청 많이... 그러니깐 completion을 받건 말건 걍 무쟈게 많이
미리 해버리는 경우...
메모리 바닥날때까지 해버린다면... 맛이 갈 수는 있겠네요... ^_^;
아마도 ERROR_INSUFFICIENT_RESOURCES 에러가 나겠죠?
더구나 recv나 send를 해서 소켓 operation이 kernel로 넘어가서 pending상태가 되면
이넘들은 kernel에서 접근하기때문에 pageable메모리에 있으면 안되거든요.
반드시 locking이 가능한 physical memory에 올라와야 하죠...
근데 이 lockable 메모리의 사이즈는 그다지 크기 않기땜에 생각보다 빨리
메모리가 바닥날 수 있겠네요...
근데 일반적인 경우에 이렇게 할 일은 별로 없겠죠? ^_^;

음... 이번에는 좀더 원론적인 부분에서 생각을 해보죠...
자 우리가 사용하는 socket 프로그램의 하위엔 TCP stack이라고 하는 넘이
있습니다. 즉, 우리 일반 application프로그래머들은 신경쓰지 않아도 되는
수많은 TCP/IP protocol의 처리들을 구현해 놓은 녀석들이죠...
sliding window protocol이란 녀석을 들어보셨으리라 생각합니다.
TCP/IP 에서 Flow control을 담당하는 녀석이죠... 즉, 위에서 언급한
iocp메커니즘 관련된 것은 제외하고라도, 이넘이 관계하는
incoming/outgoing buffer가 있습니다. 들어오고 나가는 데이터를 버퍼링 하는
것이죠... 즉, 상대측에서 아무리 데이터를 날리고 싶어도 내 컴터의 app에서
어떤 불가피한 상황에 의해 데이터 받는 즉시즉시 데이터를 빼내가지 않아서
수신버퍼에 데이터가 꽉 차있는 상태라면 상대측에선 어떤 데이터도 날릴 수 없는 것이죠...
아무리 송신측에서 Send를 해도 수신측의 버퍼에 여유가 없다면 송신측은 계속
outstanding상태에 있게 된답니다.
즉, posting된 recv가 없는 상태라면 비록 네떡 수신 버퍼는 꽉꽉차있어도
iocp로부터의 completion은 발생하지 않게 됩니다.
당연하겠죠... 요청한 작업이 없는데도 nt가 알아서 completion packet을
저절로 만드는 일은 결코 없을테니까요.

분명한 사실은 iocp라는 넘의 정체는 소켓, 혹은 네떡 프로그래밍만을 위해 존재하는 녀석은
아닙니다.
말 그대로 컴터에서 일어나는 I/O 작업의 completion을 application에서 인지할 수 있게
해주고, 또한 i/o 작업시에 일어날 수 있는 app의 performance저하를 최대한
피할 수 있도록 능동적인 thread pooling의 기능을 제공하는 하나의 커널객체 입니다.
그 이상도 이하도 아니지요...
즉, 이넘을 네떡에도 쓸 수 있고, 화일처리에도 사용할 수 있습니다.
물론 그밖의 핸들을 사용하는 i/o 작업이면 어디에도 가능한 것이죠...

 

TCHAR 용 스트링 함수

C++/기본 2012. 6. 13. 15:18 Posted by 퓨어레드
_tprintf : printf
_stprintf : sprintf
_tcslen : strlen
_tcscpy : strcpy
_tsplitpath : _splitpath

 

'C++ > 기본' 카테고리의 다른 글

UTF-8 -> Unicode  (0) 2012.06.13
[warning C4996] "_CRT_SECURE_NO_DEPRECATE"로 해결  (0) 2012.05.02

IPAddress

C#/Network 2012. 6. 13. 15:14 Posted by 퓨어레드
/************************************************************************/
/* IPAddress : 하나의 주소를 표현함
/************************************************************************/

IPAddress test1 = IPAddress.Parse("192.168.1.1");
IPAddress test2 = IPAddress.Loopback;
IPAddress test3 = IPAddress.Broadcast;
IPAddress test4 = IPAddress.Any;
IPAddress test5 = IPAddress.None;

IPHostEntry ihe = Dns.GetHostByName (Dns.GetHostName ());

IPAddress myself = ihe.AddressList[0];

if (IPAddress.IsLoopback (test2))
{
	result += String.Format ("The Loopback address is : {0}\r\n", test2.ToString ());
}
else
	result += "Error obtaining the loopback address\r\n";

result += String.Format ("The Local IP address is {0}\r\n", myself.ToString ());

if (myself == test2)
	result += "The loopback address is the same as local address.\r\n";
else
	result += "The loopback address is not the local address.\r\n";

result += String.Format ("The test address is : {0}\r\n", test1.ToString ());
result += String.Format ("Boardcast address is : {0}\r\n", test3.ToString ());
result += String.Format ("Any address is : {0}\r\n", test4.ToString ());
result += String.Format ("The NONE address is : {0}\r\n", test5.ToString ());

 

결과 ...

====================================

 

The Loopback address is : 127.0.0.1
The Local IP address is 192.168.123.176
The loopback address is not the local address.
The test address is : 192.168.1.1
Boardcast address is : 255.255.255.255
Any address is : 0.0.0.0
The NONE address is : 255.255.255.255

'C# > Network' 카테고리의 다른 글

GetHostName 및 GetHostByName  (0) 2012.06.13
C# POSTDATA 파일 업로드  (0) 2012.06.04
C# HttpWebRequest 클래스를 이용한 POST 전송하기  (0) 2012.06.04
Socket Server 연결 Sample  (0) 2012.04.18
Socket Client 연결 Sample  (0) 2012.04.18

날짜형 파싱하여 DateTime 형으로 만들기

C#/기본 2012. 6. 13. 15:13 Posted by 퓨어레드

'C# > 기본' 카테고리의 다른 글

DateTime 시간 스트링으로 변환  (0) 2012.06.27
웹브라우져 띄우기  (0) 2012.06.22
C#.NET 입출력 관련 정리  (0) 2012.05.24
const 와 readonly 의 차이  (0) 2012.05.02
C# 컬렉션 - 1  (0) 2012.05.02

How to build your own SQL Server Explorer

C#/Sample 2012. 6. 13. 15:11 Posted by 퓨어레드

출처 : http://blog.vuscode.com/malovicn/archive/2007/11/12/how-to-build-your-own-sql-server-explorer.aspx

Recently, I've started making in my free time my own little ORM tool, mainly as an fun way into exploration of the ADO .NET 2.0

Every dissent ORM tool has to be based on DB object enumeration activities and I've noticed there are not a lot straight "how to" articles on net how to do various things (at least I had a hard time finding them), so I decided to make a simple blog post describing exactly those How-To's

How to enumerate visible SQL server instances

Enumerating visible instances of MS SQL Server can be performed by executing the GetDataSource() of the SqlDataSourceEnumerator type singleton instance.

GetDataSource returns four column data table with next columns:

  1. ServerName - Name of the server.
  2. InstanceName - Name of the server instance. Blank if the server is running as the default instance.
  3. IsClustered - Indicates whether the server is part of a cluster.
  4. Version - Version of the server (8.00.x for SQL Server 2000, and 9.00.x for SQL Server 2005).

Code example:

   1: public static IList<string> GetActiveServers()
   2: {
   3:     Collection<string> result = new Collection<string>();
   4:     SqlDataSourceEnumerator instanceEnumerator = SqlDataSourceEnumerator.Instance;
   5:     DataTable instancesTable = instanceEnumerator.GetDataSources();
   6:     foreach (DataRow row in instancesTable.Rows)
   7:     {
   8:         if (!string.IsNullOrEmpty(row["InstanceName"].ToString()))
   9:             result.Add(string.Format(@"{0}{1}", row["ServerName"], row["InstanceName"]));
  10:         else
  11:             result.Add(row["ServerName"].ToString());
  12:     }
  13:     return result;
  14: }

How to enumerate databases of the given SQL server instance

Enumerating the databases of the given server can be performed by executing the GetSchema method of the SqlConnection instance with a SqlClientMetaDataCollectionNames.Databases string enumeration value passed to method.

Passing that enumeration or it's string equivalent ("Databases") is totally the same, except enumeration looks cooler :)

Code example:

   1: public static IList<string> GetDatabases(string serverName, string userId, string password,
   2:                                               bool windowsAuthentication)
   3:      {
   4:          Collection<string> result = new Collection<string>();
   5:          using (
   6:              SqlConnection connection =
   7:                  GetActiveConnection(serverName, string.Empty, userId, password, windowsAuthentication))
   8:          {
   9:              connection.Open();
  10:              DataTable dt = connection.GetSchema(SqlClientMetaDataCollectionNames.Databases);
  11:              foreach (DataRow row in dt.Rows)
  12:              {
  13:                  result.Add(string.Format("{0}", row[0]));
  14:              }
  15:          }
  16:          return result;
  17:      }

In line 6, we are using an instance of SqlConnection type created by GetActiveConnection method.

In line 10, we are calling GetSchema connection instance method which returns a data table with a single column which contains the name of the database

in ADO NET, methods used for retrieving schema information always are overloaded with a version accepting additional string array parameter which is used for passing the restrictions (you can think of it as a filter criteria) which ADO.NET should apply while retrieving resulting set.
Retrieving database schema in our example has only one restriction and that is database name so if we would write something like

   DataTable dt = connection.GetSchema("Databases", new string[] {"Northwind" });

Please notice in that that line that I used "Databases" and not enumeration and that I have passed single string array with "Nortwind" content.
Result of passing that restriction would be that ADO NET would retrieve only databases fulfilling the restriction requirement, which means only Nortwind database data would be returned

GetActiveConnection method creates a new SqlConnection instance using SqlConnectionStringBuilder class which is used to build connection string for given parameters.

Something like this

   1: private static SqlConnection GetActiveConnection(string serverName, string databaseName, string userName,
   2:                                                  string password, bool useIntegratedSecurity)
   3: {
   4:     SqlConnectionStringBuilder connBuilder = new SqlConnectionStringBuilder();
   5:     connBuilder.DataSource = serverName;
   6:     connBuilder.InitialCatalog = databaseName;
   7:     connBuilder.IntegratedSecurity = useIntegratedSecurity;
   8:     connBuilder.UserID = userName;
   9:     connBuilder.Password = password;
  10:     return new SqlConnection(connBuilder.ConnectionString);
  11: }

I'll be using this helper methods also in rest of the examples

How to enumerate tables of the given database

In general, the procedure of retrieval tables is the same as the procedure described for databases, in a sense that the GetSchema method of SqlConnection instance is been called but this time with SqlClientMetaDataCollectionNames.Tables ("Tables") enumerated value.

The big difference between those two is in the fact that tables restriction are contained of four different constraint arguments:

  1. database name
  2. owner/schema name ("dbo")
  3. table name (which should contain null value if we want to retrieve all tables of database)
  4. table type (which can have values "VIEW" for views and "BASE TABLE" for tables

So, to retrieve the list of tables for a given database we could use code similar to the next one:

   1: public static IList<string> GetTables(string serverName, string databaseName, string userId, string password,
   2:                                       bool windowsAuthentication)
   3: {
   4:     string[] restrictions = new string[4];
   5:     restrictions[0] = databaseName; // database/catalog name   
   6:     restrictions[1] = "dbo"; // owner/schema name   
   7:     restrictions[2] = null; // table name   
   8:     restrictions[3] = "BASE TABLE"; // table type    
   9:     Collection<string> result = new Collection<string>();
  10:     using (
  11:         SqlConnection connection =
  12:             GetActiveConnection(serverName, databaseName, userId, password, windowsAuthentication))
  13:     {
  14:         connection.Open();
  15:         DataTable dt = connection.GetSchema(SqlClientMetaDataCollectionNames.Tables, restrictions);
  16:         foreach (DataRow row in dt.Rows)
  17:         {
  18:             if (!row[2].ToString().StartsWith("sys"))
  19:                 result.Add(string.Format(@"{0}", row[2]));
  20:         }
  21:     }
  22:     return result;
  23: }
Column keys of the columns of the data table returned are:
  • Column 0. "table_catalog"
  • Column 1. "table_schema"
  • Column 2. "table_name"
  • Column 3. "table_type"

How to enumerate columns of the given table

The list of restriction parameters for column retrieval is shorter and it contains next 3 string values:

  1. Database name
  2. Owner/schema name
  3. Table name

SqlConnection instance GetSchema method gets this time SqlClientMetaDataCollectionNames.Columns ("Columns") enumerated value and the resulting data table contains next 18 columns:

Column 0 - "TABLE_CATALOG"
Column 1 - "TABLE_SCHEMA"
Column 2 - "TABLE_NAME"
Column 3 - "COLUMN_NAME"
Column 4 - "ORDINAL_POSTION"
Column 5 - "COLUMN_DEFAULT"
Column 6 - "IS_NULLABLE"
Column 7 - "DATA_TYPE"
Column 8 - "CHARACTER_MAXIMUM_LENGTH"
Column 9 - "CHARACTER_OCTET_LENGTH"
Column 10 - "NUMERIC_PRECISION"
Column 11 - "NUMERIC_PRECISION_RADIX"
Column 12 - "NUMERIC_SCALE"
Column 13 - "DATETIME_PRECISION"
Column 14 - "CHARACTER_SET_CATALOG"
Column 15 - "CHARACTER_SET_SCHEMA"
Column 16 - "CHARACTER_SET_NAME"
Column 17 - "COLLATION_CATALOG"

I believe column names are self explanatory and familiar to all of us, so I'll skip explanation of what they stand for

In our little example we would return concatenated string containing the column name and data type, where data type in case of char data types would show maximal number of characters and in case of decimal precision data.

The code doing that might look like this:

   1: public static IList<string> GetColumns(
   2:        string serverName, string databaseName, string userId,
   3:        string password, bool windowsAuthentication, string tableName)
   4:    {
   5:        SqlConnection connection =
   6:            GetActiveConnection(serverName, databaseName, userId, 
   7:                                password, windowsAuthentication);
   8:  
   9:        string[] restrictions = new string[3];
  10:        restrictions[0] = connection.Database; // database/catalog name      
  11:        restrictions[1] = "dbo"; // owner/schema name      
  12:        restrictions[2] = tableName; // table name      
  13:        IList<string> result = new Collection<string>();
  14:        using (connection)
  15:        {
  16:            connection.Open();
  17:            DataTable columns = connection.GetSchema(SqlClientMetaDataCollectionNames.Columns, restrictions);
  18:            foreach (DataRow row in columns.Rows)
  19:            {
  20:                string columnName = row[3].ToString();
  21:                string columnDataType = row[7].ToString();
  22:                if (columnDataType.IndexOf("char") > -1)
  23:                {
  24:                    // row[8] - CHARACTER_MAXIMUM_LENGTH    
  25:                    columnDataType = string.Format("{0}({1})", columnDataType, row[8]);
  26:                }
  27:                if (columnDataType.IndexOf("decimal") > -1)
  28:                {
  29:                    // row[10] - CHARACTER_OCTET_LENGTH    
  30:                    // row[11] - NUMERIC_PRECISION    
  31:                    columnDataType = string.Format("{0}({1},{2})", columnDataType, row[10], row[11]);
  32:                }
  33:                result.Add(string.Format("{0},{1}", columnName, columnDataType));
  34:            }
  35:            return result;
  36:        }
  37:    }

How to enumerate indexes of the table

List of restrictions which can be used for indexes is the same as the one used for table, with 4 elements: database name, schema, table name and table type

We are executing GetSchema method of SqlConnection instance with SqlClientMetaDataCollectionNames.IndexColumns ("IndexColumns") enumerated value sent as a parameter and the resulting data table contains next 9 columns

  • Column 0 - "constraint_catalog"
  • Column 1 - "constraint_schema"
  • Column 2 - "constraint_name"
  • Column 3 - "table_catalog"
  • Column 4 - "table_schema"
  • Column 5 - "table_name"
  • Column 6 - "column_name"
  • Column 7 - "ordinal_position"
  • Column 8 - "KeyType"
  • Column 8 - "index_name"

Column 8 ("KeyType") describes the data type of the index and contains a numeric value which points to certain data type.

There's a list:

34 : image
35 : text
48 : tinyint
52 : smallint
56 : int
58 : smalldatetime
59 : real
60 : money
61 : datetime
62 : float
98 : sql_variant
99 : ntext
104 : bit
106 : decimal
108 : numeric
122 : smallmoney
127 : bigint
165 : varbinary
167 : varchar
173 : binary
175 : char
189 : timestamp
231 : nvarchar
239 : nchar

So to enumerate indexes, one might write next code:

   1: public static IList<string> GetIndexes(SqlConnection connection, string tableName)
   2:       {
   3:           string[] restrictions = new string[3];
   4:           restrictions[0] = connection.Database; // database/catalog name      
   5:           restrictions[1] = "dbo"; // owner/schema name      
   6:           restrictions[2] = tableName; // table name      
   7:           IList<string> result = new Collection<string>();
   8:           using (connection)
   9:           {
  10:               connection.Open();
  11:               DataTable columns = connection.GetSchema(SqlClientMetaDataCollectionNames.IndexColumns, restrictions);
  12:               foreach (DataRow row in columns.Rows)
  13:               {
  14:                   string columnName = row["column_name"].ToString();
  15:                   string indexName = row["index_name"].ToString();
  16:                   bool isPrimaryKey = row["constarint_name"].ToString().StartsWith("PK");
  17:                   result.Add(string.Format("Index:{0}, on column:{1}, PK:{2}", indexName, columnName, isPrimaryKey));
  18:               }
  19:               return result;
  20:           }
  21:       }

How to enumerate parameters of the stored procedure

Enumeration of parameters used in a stored procedure is been done through usage of the SqlCommandBuilder static DeriveParameters method which accepts the SqlCommand instance constructed for a given sql connection and ctored procedure

According to http://www.codeproject.com/useritems/DetermineSql2005SPParams.asp, there is a difference in how SQL 2000 and SQL 2005 and there's a need of handling that problem with some additional approach, but according to my personal experience that's not the case - I never had problems he described.
So, IMHO to enumerate parameters of a stored procedure next simple code should be used regardless of the SQL version:

   1: public static SqlParameter[] DiscoverStoredProcedureParameters(SqlConnection sqlConnection,
   2:                                                                string storedProcedureName)
   3: {
   4:     SqlCommand cmd = new SqlCommand(storedProcedureName, sqlConnection);
   5:     cmd.CommandType = CommandType.StoredProcedure;
   6:     using (sqlConnection)
   7:     {
   8:         sqlConnection.Open();
   9:         SqlCommandBuilder.DeriveParameters(cmd);
  10:     }
  11:     SqlParameter[] discoveredParameters = new SqlParameter[cmd.Parameters.Count];
  12:     cmd.Parameters.CopyTo(discoveredParameters, 0);
  13:     return discoveredParameters;
  14: }

Test drive

Bellow you can find a source code of a small example which enumerates the databases (on left), tables of selected database (top right) and columns selected table (right down).

image[5]

Conclusion

ADO NET 2.0 removes the need of using ADOX or SQLDMO components for the tasks covering examining the structure of the database objects. It is almost trivial (with a bit reading of documentation) to do the thing which were before not-so trivial. But...
Although already very simple to use, I would like to see in future ADO NET 3.0 version next enhancements:

  • Replacing the property bags as a way of passing arguments with DTOs as data carriers instead of string arrays. I guess that would have to be done in some new SQL connection related helper class to preserve compatibilty
  • For the same reasons I don't like property bags as a method parameter data carriers, I don't like the result data tables
    Having LINQ in place, I don't see the reason why we won't replace the returning DataTables with some more OOP friendly solution

You can download source code of this example here

GetHostName 및 GetHostByName

C#/Network 2012. 6. 13. 15:10 Posted by 퓨어레드
// 호스팅 이름을 리턴한다.
string hostName = Dns.GetHostName ();

string result = string.Format ("Local hostname : {0}\r\n", hostName);

// IP 엔트리를 리턴한다.
IPHostEntry myself = Dns.GetHostByName (hostName);

foreach (IPAddress ip in myself.AddressList)

	 result += string.Format ("IP Address : {0}\r\n", ip.ToString ());


txtIpInfo.Text = result;

 

============== 결과 ================
Local hostname : red
 
IP Address : 192.168.219.12

'C# > Network' 카테고리의 다른 글

IPAddress  (0) 2012.06.13
C# POSTDATA 파일 업로드  (0) 2012.06.04
C# HttpWebRequest 클래스를 이용한 POST 전송하기  (0) 2012.06.04
Socket Server 연결 Sample  (0) 2012.04.18
Socket Client 연결 Sample  (0) 2012.04.18

XAML 하위 속성 풀어서 지정하기

C#/WPF 2012. 6. 13. 15:07 Posted by 퓨어레드

속성값에 값을 주는것 풀어서 할수 있다.

태그를 엘리먼트명.속성명이다.

 

Content 가 없는 속성들은 태그를 바로 닫아준다.

 

<Polygon xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Points="144 48, 200 222, 53 114, 235 114, 88 222"
         Stroke="Blue"
         StrokeThickness="5">
    <Polygon.Fill>
        <RadialGradientBrush>
            <GradientStop Offset="0" Color="Blue" />
            <GradientStop Offset="1" Color="Red" />
        </RadialGradientBrush>
    </Polygon.Fill>
</Polygon>

ItemSource 로 데이터를 넣은 뒤.. ItemSource 안에 있는 내용을 수정하여 Control 에 적용하려면

ItemSource 로 들어가는 데이터에

INotifyPropertyChanged 를 구현해주면 된다.

 

샘플소스

public class UploadFileInfo : INotifyPropertyChanged
{
	long recvFileSize = 0;
	public long RecvFileSize
	{
		get { return recvFileSize; }
		set 
		{
			recvFileSize = value;
			NotifyPropertyChanged ("RecvFileSize");
		}
	}

	#region INotifyPropertyChanged Members

	private void NotifyPropertyChanged (string prop)
	{
		PropertyChangedEventHandler handler = PropertyChanged;

		if (handler != null)
			handler (this, new PropertyChangedEventArgs (prop));
	}

	public event PropertyChangedEventHandler PropertyChanged;

	#endregion