C#



Article screenshot

Introduction


I've been working with sockets since 2000, using Delphi 5.0 and some third-party libraries (Synapse). My very first socket application just copied files between many clients and one server. The client app checks a folder to see if files exist, asks the server where to copy the files in the network and, after copying the files, flags the database record indicating that a file has been moved. The server listens to the client connections, and both exchange XML messages indicating the state of each file copy. Synapse is a blocking socket implementation, and I needed a thread pooling mechanism that works like an HTTP server, because I couldn't keep the connection open (one thread per connection). My solution was to use some IOCP functions to pool the client requests (code) and close the connection after the message exchange was terminated.

Now, using C#, I decided to write a socket server and client library that helps me to only have to think about the message exchange (the process) and let .NET do the hard job. So, I needed the following features:

  • Asynchronous processing

  • Some encryption and compression capabilities

  • Encapsulate the socket, and encrypt the services in the interfaces and separate them from the host implementation


Socket Connection


The ISocketConnection is the base interface for the socket connections, and describes all the connection properties and the methods. The ConnectionID property defines a unique connection ID using a GUID string. The CustomData property defines a custom object that can be associated with the connection. The Header property is the socket service header used in each message that is encapsulated in a packet message. Only messages with a defined header will be accepted. The LocalEndPoint and RemoteEndPoint are the socket IP end points used in the connection. SocketHandle is the socket handle given by the OS.

The IClientSocketConnection and IServerSocketConnection inherit the ISocketConnection, and each one has special functions. The IClientSocketConnection can reconnect to the server using the BeginReconnect method, and the IServerSocketConnection can communicate with other connections in the server host using the BeginSendTo and BeginSendToAll methods, and can get the ConnectionId using the GetConnectionById method. Every connection knows the host, the encryption, the compression type, and can send, receive, and disconnect itself from the other part. This interface is used in the ISocketService interface to allow the user to interact with socket connections.

Internally, in the library implementation, all the connection interfaces are created using the base connection implementations: BaseSocketConnection, ClientSocketConnection, and ServerSocketConnection.

Socket Service


The ISocketService describes the connection events. These events are fired by the host, and have a ConnectionEventArgs argument which has an ISocketConnection that identifies the connection. In the OnReceived and OnSent events, a MessageEventArgs is passed, which has the sent or received array of bytes. In the OnDisconnected event, a DisconnectedEventArgs is passed; the Exception property indicates if the disconnection has been caused by an exception.

Here is an example of a ISocketService implementation:
Collapse


public class SimpleEchoService : ISocketService
{
public void OnConnected(ConnectionEventArgs e)
{
//----- Check the host!

if (e.Connection.HostType == HostType.htServer)
{
//----- Enqueue receive!

e.Connection.BeginReceive();
}
else
{
//----- Enqueue send a custom message!

byte[] b =
GetMessage(e.Connection.SocketHandle.ToInt32());
e.Connection.BeginSend(b);
}
}

public void OnSent(MessageEventArgs e)
{
//----- Check the host. In this case both start a receive!

if (e.Connection.HostType == HostType.htServer)
{
//----- Enqueue receive!

e.Connection.BeginReceive();
}
else
{
//----- Enqueue receive!

e.Connection.BeginReceive();
}
}

public override void OnReceived(MessageEventArgs e)
{
//----- Check the host!

if (e.Connection.HostType == HostType.htServer)
{
//----- If server, send the data buffer received!

byte[] b = e.Buffer;
e.Connection.BeginSend(b);
}
else
{
//----- If client, generate another

//----- custom message and send it!

byte[] b = GetMessage(e.Connection.SocketHandle.ToInt32());
e.Connection.BeginSend(b);
}
}

public override void OnDisconnected(DisconnectedEventArgs e)
{
//----- Check the host!

if (e.Connection.HostType == HostType.htServer)
{
//----- Nothing!

}
else
{
//----- Reconnect with server!

e.Connection.AsClientConnection().BeginReconnect();
}
}
}


The ISocketService implementation can be done in the same host assembly, or another assembly referenced by the host. This allows the user to separate the host implementation from the socket service, helping the administration in a server or a domain.

Connection Host


With the ISocketService created, you need to host the service and the service connections. Both the server and the client host have the same parent class, BaseSocketConnectionHost, which keeps a list of connections, encrypts and compresses the data buffers, enqueues the service requests and ensures that all data buffer has been sent or received, checks messages headers, and checks for idle connections. The CheckTimeoutTimer, periodically, at IdleCheckInterval, checks if the connections become idle, using the IdleTimeOutValue as the idle timeout. Header is the socket service header used by the host. HostType indicates if a host is a server or a client host. SocketBufferSize defines the size of the socket send and receive buffer. SocketService is the instance of ISocketService that drives the message exchange between the connections.

Encrypt and Compress


Every time you send and receive messages, the host checks if the data must be encrypted and/or compressed, and this work is made by the CryptUtils static class. The CreateSymmetricAlgoritm creates an ISymmetricAlgoritm based on the encryptType parameter. The DecryptData and DecryptDataForAuthenticate are used, respectively, to decrypt the received message and check the hash sign on the authenticate procedure. The EncryptData and EncryptDataForAuthenticate, respectively, encrypt the data to be sent and sign the authenticated message.

The encrypted data buffer is labelled with the service header and the data buffer length, becoming a packet buffer. This packet buffer is controlled by the MessageBuffer class that keeps information about the packet buffer offset, length, the remaining bytes, and the raw buffer.

Enqueuing requests


Every time you call BeginReceive or BeginSend in ISocketService, the host checks if some request has been initiated. If a request is in process, the host enqueues the request. If not, it fires the request.

Send request


In the BeginSend method, the following enqueuing is used:

internal void BeginSend(BaseSocketConnection connection, byte[] buffer)
{
...
//----- Check Queue!

lock (connection.WriteQueue)
{

if (connection.WriteQueueHasItems)
{
//----- If the connection is sending, enqueue the message!

connection.WriteQueue.Enqueue(writeMessage);
}
else
{

//----- If the connection is not sending, send the message!

connection.WriteQueueHasItems = true;

...


When the message is sent, in the send callback, the host checks the queue again and initiates another send process, if needed:

private void BeginSendCallback(IAsyncResult ar)
{
...
//----- Check Queue!

lock (connection.WriteQueue)
{

if (connection.WriteQueue.Count > 0)
{

//----- If has items, send it!

MessageBuffer dequeueWriteMessage =
connection.WriteQueue.Dequeue();
...

}
else
{
connection.WriteQueueHasItems = false;
}

}
...


Receive request


The same technique applies to the receive method: all the calls to BeginReceive are enqueued if the receive method is in action. If no receive process was initiated, the host starts to receive:
Collapse


internal void BeginReceive(BaseSocketConnection connection)
{
...
//----- Check Queue!

lock (connection.SyncReadCount)
{

if (connection.ReadCanEnqueue)
{

if (connection.ReadCount == 0)
{

//----- if the connection is not receiving, start the receive!

MessageBuffer readMessage = new MessageBuffer
(FSocketBufferSize);

...

}

//----- Increase the read count!

connection.ReadCount++;

}

}
...


After that, when the message is received and parsed in the receive callback, the host checks the read queue again, and initiates another receive process, if needed:

private void BeginReadCallback(IAsyncResult ar)
{
...
//----- Check Queue!

lock (connection.SyncReadCount)
{

connection.ReadCount--;

if (connection.ReadCount > 0)
{

//----- if the read queue has items, start to receive!

...

}

}
...


Ensure send and receive


To ensure that all data buffer is sent, the BaseSocketConnectionHost checks the bytes sent, and compares it to the MessageBuffer class. It continues to send the remaining bytes till all the data buffer is sent:

private void BeginSendCallback(IAsyncResult ar)
{
...
byte[] sent = null;
int writeBytes = .EndSend(ar);

if (writeBytes < writeMessage.PacketBuffer.Length)
{
//----- Continue to send until all bytes are sent!

writeMessage.PacketOffSet += writeBytes;
.BeginSend(writeMessage.PacketBuffer, writeMessage.PacketOffSet,
writeMessage.PacketRemaining, SocketFlags.None ...);
}
else
{
sent = new byte[writeMessage.RawBuffer.Length];
Array.Copy(writeMessage.RawBuffer, 0, sent, 0,
writeMessage.RawBuffer.Length);
FireOnSent(connection, sent);
}
}


The same approach is used in the receive data buffers because, to read data, a MessageBuffer is used as the read buffer. When the receive callback is called, it continues to read till all the bytes in the message are read:
Collapse


private void BeginReadCallback(IAsyncResult ar)
{
...
CallbackData callbackData = (CallbackData)ar.AsyncState;

connection = callbackData.Connection;
readMessage = callbackData.Buffer;

int readBytes = 0;
...
readBytes = .EndReceive(ar);
...

if (readBytes > 0)
{
...
//----- Has bytes!

...
//----- Process received data!

readMessage.PacketOffSet += readBytes;
...

if (readSocket)
{

//----- Read More!

.BeginReceive(readMessage.PacketBuffer,
readMessage.PacketOffSet,
readMessage.PacketRemaining,
SocketFlags.None, ...);
}
}
...


Check message header


If the socket service uses some header, all the send and receive processes need to create a packet message indicating the header and the message length. This packet label is created using the following structure:

The first label's part is the socket service header. The header is an array of bytes of any length, and you need some advice here: if you choose a very small header, maybe you can have a message with the same array of bytes somewhere, and the host will lose the sequence. If you choose a very long array of bytes, the host can spend the processor's time to verify if the message header is equal to the socket service. The second part is the packet message length. This length is calculated adding the raw message data buffer length, encrypted and/or compressed, plus the header length.

Sending packets


As said before, every time you send messages, the host checks if the data must be encrypted and/or compressed, and, if you choose to use some header, the raw buffer is controlled by the MessageBuffer class. This class is created using the GetPacketMessage static method:
Collapse


public static MessageBuffer GetPacketMessage(
BaseSocketConnection connection, ref byte[] buffer)
{

byte[] workBuffer = null;

workBuffer = CryptUtils.EncryptData(connection, buffer);

if (connection.Header != null && connection.Header.Length >= 0)
{
//----- Need header!

int headerSize = connection.Header.Length + 2;
byte[] result = new byte[workBuffer.Length + headerSize];

int messageLength = result.Length;

//----- Header!

for (int i = 0; i < connection.Header.Length; i++)
{
result[i] = connection.Header[i];
}

//----- Length!

result[connection.Header.Length] =
Convert.ToByte((messageLength & 0xFF00) >> 8);
result[connection.Header.Length + 1] =
Convert.ToByte(messageLength & 0xFF);

Array.Copy(workBuffer, 0, result,
headerSize, workBuffer.Length);

return new MessageBuffer(ref buffer, ref result);

}
else
{
//----- No header!

return new MessageBuffer(ref buffer, ref workBuffer);
}
}


Receiving packets


The receive process, if you're using some socket service header, needs to check the header, and continues to read bytes till all the packet message is received. This process is executed in the read callback:
Collapse


private void BeginReadCallback(IAsyncResult ar)
{
...

byte[] received = null
byte[] rawBuffer = null;
byte[] connectionHeader = connection.Header;

readMessage.PacketOffSet += readBytes;

if ((connectionHeader != null) && (connectionHeader.Length > 0))
{

//----- Message with header!

int headerSize = connectionHeader.Length + 2;

bool readPacket = false;
bool readSocket = false;

do
{
connection.LastAction = DateTime.Now;

if (readMessage.PacketOffSet > headerSize)
{
//----- Has Header!

for (int i = 0; i < connectionHeader.Length; i++)
{
if (connectionHeader[i] != readMessage.PacketBuffer[i])
{
//----- Bad Header!

throw new BadHeaderException(
"Message header is different from Host header.");
}
}

//----- Get Length!

int messageLength =
(readMessage.PacketBuffer[connectionHeader.Length] << 8) +
readMessage.PacketBuffer[connectionHeader.Length + 1];

if (messageLength > FMessageBufferSize)
{
throw new MessageLengthException("Message " +
"length is greater than Host maximum message length.");
}

//----- Check Length!

if (messageLength == readMessage.PacketOffSet)
{
//----- Equal -> Get rawBuffer!

rawBuffer =
readMessage.GetRawBuffer(messageLength, headerSize);

readPacket = false;
readSocket = false;
}
else
{
if (messageLength < readMessage.PacketOffSet)
{
//----- Less -> Get rawBuffer and fire event!

rawBuffer =
readMessage.GetRawBuffer(messageLength, headerSize);

//----- Decrypt!

rawBuffer = CryptUtils.DecryptData(connection,
ref rawBuffer, FMessageBufferSize);

readPacket = true;
readSocket = false;

received = new byte[rawBuffer.Length];
Array.Copy(rawBuffer, 0, received, 0,
rawBuffer.Length);
FireOnReceived(connection, received, false);
}
else
{
if (messageLength > readMessage.PacketOffSet)
{
//----- Greater -> Read Socket!

if (messageLength > readMessage.PacketLength)
{
readMessage.Resize(messageLength);
}

readPacket = false;
readSocket = true;
}
}
}
}
else
{
if (readMessage.PacketRemaining < headerSize)
{
//----- Adjust room for more!

readMessage.Resize(readMessage.PacketLength + headerSize);
}

readPacket = false;
readSocket = true;
}

} while (readPacket);

if (readSocket)
{
//----- Read More!

...
.BeginReceive(readMessage.PacketBuffer, readMessage.PacketOffSet,
readMessage.PacketRemaining, SocketFlags.None, ...);
...
}
}
else
{
//----- Message with no header!

rawBuffer = readMessage.GetRawBuffer(readBytes, 0);
}

if (rawBuffer != null)
{
//----- Decrypt!

rawBuffer = CryptUtils.DecryptData(connection,
ref rawBuffer, FMessageBufferSize);

received = new byte[rawBuffer.Length];
Array.Copy(rawBuffer, 0, received, 0, rawBuffer.Length);
FireOnReceived(connection, received, true);

readMessage.Resize(FSocketBufferSize);
...


The read callback method first checks if the connection has some header and, if not, just gets the raw buffer and continues. If the connection has some header, the method needs to check the message header against the socket service header. Before doing that, it checks if the packet message length is greater than the connection header length, to ensure that it can parse the total message length. If not, it reads some bytes. After checking the header, the method parses the message length, and checks with the packet length. If the length is equal, it gets the raw buffer and terminates the loop. If the message length is less than that of the packet message, we have the message plus some data. So, the method gets the raw buffer and continues to read using the same MessageBuffer class. If the length of the message is greater than that of the packet message, before reading some data, it just resizes the packet buffer to the message size, ensuring enough room for more read bytes.

Checking idle connections


Using the BeginSend and BeginReceive methods of ISocketConnection doesn't return some IAsyncResult to know if the method was completed or not allowing disconnection after some timeout value. To prevent this, the BaseSocketConnectionHost has a System.Threading.Timer that periodically checks the LastAction property of BaseSocketConnection. If LastAction is greater than the idle timeout, the connection is closed.

Crypto Service


The ICryptoService describes the authentication methods fired when the connection is made to the other part. The OnSymmetricAuthenticate method is fired when EncryptType.etRijndael or EncryptType.etTripleDES is used, and OnSSLXXXXAuthentication is fired when EncryptType.etSSL is used. Like ISocketService, the ICryptService can be done in the same host assembly, or another assembly referenced by the host, so you can have one ICryptoService implementation used in many ISocketService implementations.

SSL authentication


There's a new stream class called SslStream in .NET 2.0 which can authenticate SSL streams. The SslStream's constructor accepts a NetworkStream class, and this stream is created using the Socket class. So, using SslStream, you can send and receive data buffers using socket connections.

Server authentication


The SslStream authentication is done in both the client and the server, but each one has different parameters. In the server side, you need to pass a certificate using the X509Certificate2 class, either finding in the certificate store using X509Store, or by creating it from a certification file (.cer). Also, you can request a client authentication and check the certificate's revocation. The following code is an example of an SSL server authentication using ICryptService:

public void OnSSLServerAuthenticate(out X509Certificate2 certificate,
out bool clientAuthenticate, ref bool checkRevocation)
{
//----- Set server certificate, client

//----- authentication and certificate revocation!

X509Store store = new X509Store(StoreName.My,
StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);

X509Certificate2Collection certs =
store.Certificates.Find(X509FindType.FindBySubjectName,
"ALAZ Library", false);
certificate = certs[0];

clientAuthenticate = false;
checkRevocation = false;

store.Close();
}


Client authentication


On the client side of the SSL authentication, you need to pass the host name of the server certificate, and if this name doesn't match, the authentication fails. You can pass a client certificate collection using X509Certificate2Collection. If the server doesn't request a client authentication, you don't need to pass the collection but, if the server requests it, you can find the certificates using X509Store. You can also request a client certificate's revocation. This is an example of SSL client authentication in ICryptoService:

public void OnSSLClientAuthenticate(out string serverName,
ref X509Certificate2Collection certs, ref bool checkRevocation)
{
serverName = "ALAZ Library";
/*
//----- Using client certificate!
X509Store store = new X509Store(StoreName.My,
StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);

certs = store.Certificates.Find(
X509FindType.FindBySubjectName,
serverName, true);
checkRevocation = false;

store.Close();
*/

}


Certificates


To create certificates, you can use the MakeCert.exe tool found in .NET, and there's a lot of information available about it. You can take a look at John Howard's page, this MS post, and this website.

Symmetric authentication


To implement some symmetric encryption and authentication in this library, I decided to put a post in Microsoft newsgroups. Unfortunately, for the post, but luckily for the knowledge sharing (many thanks to Joe Kaplan, Dominick Baier, and Valery Pryamikov), I decided to use William Stacey's implementation example "A generic method to send secure messages using an exchanged session key". In this code, the symmetric key used in the session is encrypted and signed using RSA key pairs, and the client part needs to know the encrypted server's public key, meaning that this key isn't received from the server in the authentication process. Both the client and the server need to know this key through a manual process. To ensure this, the OnSymmetricAuthenticate needs a RSACryptoServiceProvider class providing the key pair for encryption. You can fill the RSACryptoServiceProvider from an XML string, a file, a CspParameters class, or a certificate. Here is an example of symmetric authentication:
Collapse


public void OnSymmetricAuthenticate(HostType hostType,
out RSACryptoServiceProvider serverKey)
{
/*
* A RSACryptoServiceProvider is needed to encrypt and send session key.
* In server side you need public and private key to decrypt session key.
* In client side you need only public key to encrypt session key.
*
* You can create a RSACryptoServiceProvider from a string
* (file, registry), a CspParameters or a certificate.
*/


//----- Using string!

/*
serverKey = new RSACryptoServiceProvider();
serverKey.FromXMLString("XML key string");
*/


//----- Using CspParameters!

CspParameters param = new CspParameters();
param.KeyContainerName = "ALAZ_ECHO_SERVICE";
serverKey = new RSACryptoServiceProvider(param);

/*
//----- Using Certificate Store!
X509Store store = new X509Store(StoreName.My,
StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);

X509Certificate2 certificate = store.Certificates.Find(
X509FindType.FindBySubjectName,
"ALAZ Library", true)[0];
serverKey = new RSACryptoServiceProvider();

if (hostType == HostType.htClient)
{
//----- In client only public key is needed!
serverKey = (RSACryptoServiceProvider)certificate.PublicKey.Key;
}
else
{
//----- In server, both public and private key is needed!
serverKey.FromXmlString(certificate.PrivateKey.ToXmlString(true));
}

store.Close();
*/

}


The authentication message


The symmetric authentication uses the AuthMessage structure to exchange session keys between the client and the server. The SessionKey and SessionIV properties are, respectively, the symmetric key and the initialization vector of the algorithm. The Sign property is the hash code generated by the client using the sign RSACryptoServiceProvider class created internally, and its public key is exchanged using the SourceKey property. This internal sign key pair is necessary to sign the AuthMessage, and the server can ensure that the AuthMessage is accurate. This process is done using the following code:

Client side


Collapse


...
//----- Sign Message!

private byte[] signMessage = new byte[]
{ <sign message array of bytes for authentication> };
...
protected virtual void InitializeConnection(BaseSocketConnection connection)
{
...

//----- Symmetric!

if (connection.EncryptType == EncryptType.etRijndael ||
connection.EncryptType == EncryptType.etTripleDES)
{
if (FHost.HostType == HostType.htClient)
{
//----- Get RSA provider!

RSACryptoServiceProvider serverPublicKey;
RSACryptoServiceProvider clientPrivateKey =
new RSACryptoServiceProvider();

FCryptoService.OnSymmetricAuthenticate(FHost.HostType,
out serverPublicKey);

//----- Generates symmetric algorithm!

SymmetricAlgorithm sa =
CryptUtils.CreateSymmetricAlgoritm(connection.EncryptType);
sa.GenerateIV();
sa.GenerateKey();

//----- Adjust connection cryptors!

connection.Encryptor = sa.CreateEncryptor();
connection.Decryptor = sa.CreateDecryptor();

//----- Create authenticate structure!

AuthMessage am = new AuthMessage();
am.SessionIV = serverPublicKey.Encrypt(sa.IV, false);
am.SessionKey = serverPublicKey.Encrypt(sa.Key, false);
am.SourceKey =
CryptUtils.EncryptDataForAuthenticate(sa,
Encoding.UTF8.GetBytes(clientPrivateKey.ToXmlString(false)),
PaddingMode.ISO10126);

//----- Sign message with am.SourceKey,

//----- am.SessionKey and signMessage!

//----- Need to use PaddingMode.PKCS7 in sign!

MemoryStream m = new MemoryStream();
m.Write(am.SourceKey, 0, am.SourceKey.Length);
m.Write(am.SessionKey, 0, am.SessionKey.Length);
m.Write(signMessage, 0, signMessage.Length);

am.Sign = clientPrivateKey.SignData(
CryptUtils.EncryptDataForAuthenticate(sa,
m.ToArray(), PaddingMode.PKCS7),
new SHA1CryptoServiceProvider());

//----- Serialize authentication message!

XmlSerializer xml = new XmlSerializer(typeof(AuthMessage));
m.SetLength(0);
xml.Serialize(m, am);

//----- Send structure!

MessageBuffer mb = new MessageBuffer(0);
mb.PacketBuffer =
Encoding.Default.GetBytes(Convert.ToBase64String(m.ToArray()));
connection.Socket.BeginSend(
mb.PacketBuffer, mb.PacketOffSet,
mb.PacketRemaining, SocketFlags.None,
new AsyncCallback(InitializeConnectionSendCallback),
new CallbackData(connection, mb));

m.Dispose();
am.SessionIV.Initialize();
am.SessionKey.Initialize();
serverPublicKey.Clear();
clientPrivateKey.Clear();
}
...
}


On the client side of the symmetric authentication, the OnSymmetricAuthenticate is called, getting the RSACryptoServiceProvider to encrypt the session key generated by the CryptUtils.CreateSymmetricAlgoritm method. The AuthMessage is filled with the encrypted session key, session IV, and the sign public key. To sign the message, the SourceKey, SessionKey, and signMessage are used, and the resulting hash is assigned to the Sign property.

Server side


Collapse


protected virtual void InitializeConnection(BaseSocketConnection connection)
{
...
if (FHost.HostType == HostType.htClient)
{
...
}
else
{
//----- Create empty authenticate structure!

MessageBuffer mb = new MessageBuffer(8192);

//----- Start receive structure!

connection.Socket.BeginReceive(mb.PacketBuffer, mb.PacketOffSet,
mb.PacketRemaining, SocketFlags.None,
new AsyncCallback(InitializeConnectionReceiveCallback), ...);
}
}

private void InitializeConnectionReceiveCallback(IAsyncResult ar)
{
...

bool readSocket = true;
int readBytes = ....EndReceive(ar);

if (readBytes > 0)
{

readMessage.PacketOffSet += readBytes;
byte[] message = null;

try
{
message = Convert.FromBase64String(
Encoding.Default.GetString(readMessage.PacketBuffer,
0, readMessage.PacketOffSet));
}
catch (FormatException)
{
//----- Base64 transformation error!

}

if ((message != null) &&
(Encoding.Default.GetString(message).Contains("</AuthMessage>")))
{

//----- Get RSA provider!

RSACryptoServiceProvider serverPrivateKey;
RSACryptoServiceProvider clientPublicKey =
new RSACryptoServiceProvider();

FCryptoService.OnSymmetricAuthenticate(FHost.HostType,
out serverPrivateKey);

//----- Deserialize authentication message!

MemoryStream m = new MemoryStream();
m.Write(message, 0, message.Length);
m.Position = 0;

XmlSerializer xml = new XmlSerializer(typeof(AuthMessage));
AuthMessage am = (AuthMessage)xml.Deserialize(m);

//----- Generates symmetric algorithm!

SymmetricAlgorithm sa =
CryptUtils.CreateSymmetricAlgoritm(connection.EncryptType);
sa.Key = serverPrivateKey.Decrypt(am.SessionKey, false);
sa.IV = serverPrivateKey.Decrypt(am.SessionIV, false);

//----- Adjust connection cryptors!

connection.Encryptor = sa.CreateEncryptor();
connection.Decryptor = sa.CreateDecryptor();

//----- Verify sign!

clientPublicKey.FromXmlString(Encoding.UTF8.GetString(
CryptUtils.DecryptDataForAuthenticate(sa,
am.SourceKey, PaddingMode.ISO10126)));

m.SetLength(0);
m.Write(am.SourceKey, 0, am.SourceKey.Length);
m.Write(am.SessionKey, 0, am.SessionKey.Length);
m.Write(signMessage, 0, signMessage.Length);

if (!clientPublicKey.VerifyData(
CryptUtils.EncryptDataForAuthenticate(sa, m.ToArray(),
PaddingMode.PKCS7),
new SHA1CryptoServiceProvider(), am.Sign))
{
throw new
SymmetricAuthenticationException("Symmetric sign error.");
}

readSocket = false;

m.Dispose();
am.SessionIV.Initialize();
am.SessionKey.Initialize();
serverPrivateKey.Clear();
clientPublicKey.Clear();

FHost.FireOnConnected(connection);

}

if (readSocket)
{
....BeginReceive(readMessage.PacketBuffer,
readMessage.PacketOffSet,
readMessage.PacketRemaining,
SocketFlags.None,
new AsyncCallback(
InitializeConnectionReceiveCallback), ...);
}

}


On the server side of the symmetric authentication, a MessageBuffer is used to receive the socket buffer. The read callback method continues to read till a completed AuthMessage is received. With this message, the method calls the OnSymmetricAuthenticate to get the RSACryptoServiceProvider to decrypt the session key, session IV, and the sign public key. With all the keys decrypted, the method verifies the Sign property to ensure that the AuthMessage is accurate, using the SourceKey, SessionKey, and signMessage.

Connection Creator


Although BaseSocketConnectionHost can manage ISocketConnection connections, it cannot create them. This job is made by BaseSocketConnectionCreator which creates and initializes ISocketConnections. The CompressionType and EncryptType properties define, respectively, the compression and the encryption types that will be used in the connection. The CryptoService defines the ICrytoService instance used to initialize the connection, if needed. The Host property defines the host of the BaseSocketConnectionCreator; it can be a server or a client host. The LocalEndPoint defines the socket IP end point used in the connection, and it can have different behavior depending on the type of the creator.

SocketServer and SocketListener


The SocketServer and SocketListener are the classes needed to create a socket server. SocketServer is derived from BaseSocketConnectionHost, and manages ISocketConnections. The SocketListener is derived from BaseSocketConnectionCreator, and listens for incoming connections, accepts a connection, and creates a new ISocketConnection to be used. A SocketServer can have as many SocketListeners attached as required, each one assigned to a local port to listen.

SocketServer constructor and methods


In the SocketServer constructor, the socketService parameter defines the ISocketService instance used by the server. The header parameters define the array of bytes used in the message header exchange. The socketBufferSize adjusts the socket buffer size. The messageBufferSize defines the maximum message size of the service. The idleCheckInterval indicates the interval for idle connections checking, in milliseconds. The idleTimeoutValue defines the timeout, in milliseconds, to be compared to each connection LastAction property.

To add SocketListener items in SocketServer, the method AddListener must be used. The localEndPoint parameter defines the local socket IP endpoint used to listen to connections. The encryptType and compressionType defines, respectively, the encryption and compression methods used in the new accepted connection. The cryptoService defines the ICryptoService used to authenticate the encryption method chosen. The backLog limits the listen queue of the OS socket to the defined number, and acceptThreads sets the calling number of the socket's BeginAccept to increase the accepted performance.

HostThreadPool


This library uses asynchronous socket communication which, in turn, uses the .NET ThreadPool. In the .NET 2.0 ThreadPool, the thread number can be controlled using the SetMaxThreads and SetMinThreads methods, and I think there are a lot of improvements in this class. But, if you don't want to use the .NET class, you can use a managed thread pool called HostThreadPool, very similar to Stephen Toub's ManagedThreadPool. HostThreadPool uses a list of managed threads that keeps increasing as more enqueueing tasks are provided. To use this class instead of the .NET ThreadPool in SocketServer, just set the minThreads and maxThreads constructor parameters to non-zero numbers.

Here are some examples of using SocketServer and SocketListener:
Collapse


//----- Simple server!

SocketServer server = new SocketServer(new SimpleEchoService());
//----- Simple listener!

server.AddListener(new IPEndPoint(IPAddress.Any, 8087));
server.Start();
//----- Server with header!

SocketServer server = new SocketServer(new SimpleEchoService(),
new byte[] { 0xFF, 0xFE, 0xFD });
//----- Listener with simple encryption!

server.AddListener(new IPEndPoint(IPAddress.Any, 8087),
EncryptType.etBase64, CompressionType.ctNone, null);
server.Start();
//----- Server with header and buffer

//----- sizes, no hostthreadpool and idle check setting!

SocketServer server = new SocketServer(new SimpleEchoService(),
new byte[] { 0xFF, 0xFE, 0xFD },
2048, 8192, 0, 0, 60000, 30000);
//----- More than one listener each one with different listen port number!

server.AddListener(new IPEndPoint(IPAddress.Any, 8087));
server.AddListener(new IPEndPoint(IPAddress.Any, 8088),
EncryptType.etBase64, CompressionType.ctNone, null);
server.AddListener(new IPEndPoint(IPAddress.Any, 8089),
EncryptType.etRijndael, CompressionType.ctGZIP,
new SimpleEchoCryptService(), 50, 10);
server.AddListener(new IPEndPoint(IPAddress.Any, 8090),
EncryptType.etSSL, CompressionType.ctNone,
new SimpleEchoCryptService());
server.Start();


SocketClient and SocketConnector


The SocketClient and SocketConnector are the classes needed to create a socket client. SocketClient is derived from BaseSocketConnectionHost and, like SocketServer, manages ISocketConnections. The SocketConnector is derived from BaseSocketConnectionCreator, and it connects with the socket server and creates a new ISocketConnection to be used. A SocketClient can have as many SocketConnectors attached as required, each one connecting to a socket server, and they can be assigned to a local address and a local port to start the connection.

SocketClient constructor and methods


The SocketClient constructor has the same parameter signature as the SocketServer class. To add SocketConnector items in SocketClient, the method AddConnector must be used. The remoteEndPoint parameter defines the remote socket IP endpoint used for the connection. The encryptType and compressionType define, respectively, the encryption and compression methods used in the new connection. The cryptoService defines the ICryptoService used to authenticate the encrypted method chosen. The reconnectAttempts and reconnectAttemptInterval define, respectively, the number of reconnect attempts when using BeginReconnect method and the time interval to reconnect. The localEndPoint defines the local socket IP endpoint used to start the connection process to the remote endpoint.

Here are some examples of using SocketClient and SocketConnector:
Collapse


//----- Simple client!

SocketClient client = new SocketClient(new SimpleEchoService());
//----- Simple connector!

client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.1"), 8087));
client.Start();
//----- Client with header!

SocketClient client = new SocketClient(new SimpleEchoService(),
new byte[] { 0xFF, 0xFE, 0xFD });
//----- Connector with simple encryption!

client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.1"), 8087),
EncryptType.etBase64, CompressionType.ctNone, null);
client.Start();
//----- Client with header and buffer sizes,

//----- no hostthreadpool and idle check setting!

SocketClient client = new SocketClient(new SimpleEchoService(),
new byte[] { 0xFF, 0xFE, 0xFD },
2048, 8192, 0, 0, 60000, 30000);
//----- Connector with encryption and reconnect!

client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.1"), 8087),
EncryptType.etSSL, CompressionType.ctGZIP,
new SimpleEchoCryptService(),
5, 30000);
client.Start();
//----- Client with header and buffer sizes,

//----- using hostthreadpool and idle check setting!

SocketClient client = new SocketClient(new SimpleEchoService(),
new byte[] { 0xFF, 0xFE, 0xFD },
4096, 8192, 5, 50, 60000, 30000);
//----- Connector with encryption, reconnect and local endpoint!

client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.1"), 8087),
EncryptType.etSSL, CompressionType.ctGZIP,
new SimpleEchoCryptService(),
5, 30000,
new IPEndPoint(IPAddress.Parse("10.10.3.1"), 2000));
client.Start();
//----- Simple client!

SocketClient client = new SocketClient(new SimpleEchoService());
//----- More than one connector each one with different remote socket servers!

client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.1"), 8087));
client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.2"), 8088),
EncryptType.etBase64, CompressionType.ctNone, null);
client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.3"), 8089),
EncryptType.etRijndael, CompressionType.ctGZIP,
new SimpleEchoCryptService());
client.AddConnector(new IPEndPoint(IPAddress.Parse("10.10.1.4"), 8090),
EncryptType.etSSL, CompressionType.ctNone,
new SimpleEchoCryptService(),
5, 30000,
new IPEndPoint(IPAddress.Parse("10.10.3.1"), 2000));
client.Start();


Echo demo project


There's an Echo demo project available in the article download file, using Console, Windows Forms, and Windows Service hosts and clients, and all them use the same EchoSocketService and EchoCryptService. The demos are divided by their type as follows:

Hosts



  • Console

    1. EchoConsoleClient

    2. EchoConsoleServer



  • Windows Forms

    1. EchoFormClient

    2. EchoFormServer

    3. Echo<code>Form (Forms template)



  • Windows Service

    1. EchoWindowsServiceServer




Services



  • EchoSocketService

  • EchoCryptService


Conclusion


There's a lot going on here, and I think this library can help anyone who wants to write asynchronous sockets with encryption and compression. Any comments will be appreciated.

History



  • May 15, 2006: Initial version

  • May 19, 2006: Some English text corrections (sorry, I'm still learning!), and rechecking the demo sources

  • June 06, 2006: Version 1.2 with the following changes:

    • Minor bugs fixed

    • All "Sended" changed to "Sent" (thanks vmihalj)

    • ReadCanEnqueue now works correctly and with HostThreadPool (thanks PunCha)

    • Added reconnectAttempts and reconnectAttemptInterval to allow client connection reconnects as many times as is needed in a timed interval (thanks Tobias Hertkorn)



  • April 01, 2007: Version 1.3 with the following changes:

    • Fixed rawbuffer = null

    • Fixed BeginAcceptCallback: stops accepting if exception occurs

    • Fixed BeginSendCallback: PacketRemaining bytes should be used

    • Socket config section added in demos

    • New message size (64K)

    • HosThreadPool removed

    • Header changed to Delimiter property with new delimiter options:

      1. dtNone: No message delimiter

      2. dtPacketHeader: Version 1.2 backward

      3. dtMessageTailExcludeOnReceive: Use custom delimiter at end of message (Exclude delimiter on receiving)

      4. dtMessageTailIncludeOnReceive: Use custom delimiter at end of message (Include delimiter on receiving)



    • New connection object properties/methods:

      1. Nagle, Linger and TTL Algorithm options

      2. Host and Creator



    • Encrypt sign message in service class

    • Exception event in service class

    • New Creator name property



  • July 22, 2007: Version 1.4 with the following changes:

    • Connection initialize procedures executing in same thread (not queued in ThreadPool)

    • Connection disconnect now checks windows version and executes the correct disconnect procedure

    • Connection Active checking for Disposed

    • CheckSocketConnections disposed check fixed

    • CryptUtils Flush() method included

    • Client Connection BeginConnect() exception fixed

    • Server Connection BeginSendToAll array buffer fixed

    • New SocketClientSync class for synchronous using (WinForms demo included)



  • September 5, 2007: Version 1.5 with the following changes:

    • SocketClient with proxy authentication (SOCKS5, Basic HTTP)

    • BeginRead bug fixed (messagetail)

    • BeginDisconnect changed (threadpool)

    • BeginSendToAll reviewed (disposed check)

    • New OnSSLClientValidateServerCertificate event to validate server's certificate

    • Idle check interval set to 0 and only created when greater than 0

    • Using Buffer.BlockCopy instead of Array.Copy

    • New Chat Demo





License


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors may to use can be found here

About the Author







Andre Azevedo
- Living in S?o Paulo, Brazil- Interesting in
* NFL, NBA
* Lockon, Black Shark
* Dream Theater, drumming

- Developing since 1994 with
* Clipper (Summer '87 and 5.02)
* FoxPro (DOS, 2.6), Visual Foxpro (6, 7, 8, 9)
* Delphi (1, 2, 5, 7)
* C# (1.1, 2.0)









Occupation: Software Developer (Senior)
Location: Brazil Brazil

C#



Introduction


I had been trying to include updater block in my application. The quick starts that came along with the application block had some real neat examples, but it took quite some time to figure out what files must be placed where, what settings needed to be made and how, to get a sample of my own working. So, I thought I would post the sample implementation that I generated, along with a step by step guide so that others who will be trying this point onwards need not struggle much.

Note: A good tutorial for updater block version 1.0 can be found here.

The example below tries to show the usage for the version 2.0 of the Updater block.

Prerequisites



  • The Enterprise library and the Updater application block must be downloaded and installed. The enterprise library can be downloaded from here.

  • The updater block can be downloaded from here.


System Requirements



  • Supported Operating Systems: Windows XP.

  • Windows XP Professional.

  • Internet Information Server version 5.0 or later.

  • Microsoft .NET FrameWork version 1.1 SDK.

  • Microsoft Visual Studio 2003.

  • Background Intelligent Transfer Service (BITS) (for the out-of-the-box downloader to function correctly).


Steps



  1. Create a simple Windows form application .

    • Open VS .NET editor and select File -> New Project -> Windows Application.

    • Change the name to SampleApplication.

    • Change the name of the default form generated to SampleForm.cs

    • Add a label on the form SampleForm and set its text to “Version 1.0.0.0”

    • Add a button to the form and change its text to “Exit”. Add the event handler to exit the application - Application.Exit();.

    • Add a listbox called eventList.

    • Open the AssemblyInfo.cs and change the version of the application to 1.0.0.0: [assembly: AssemblyVersion("1.0.0.0")]

    • Change the line in Main () body to Application.Run(new SampleForm());.

    • Add app.config to the application: Add -> New Item -> Application Configuration File.

    • Build the application.



  2. Add the updater application block to the application.

    • The three assemblies that have to be referenced are present under the folder C:Program FilesMicrosoft Patterns & PracticesUpdater Application Block 2.0srccs (if the default settings were chosen during the installation of the updater block).

    • The three DLLs can be found in the bin/debug folders of the ActivationProcessors, Downloaders and Updater projects present under the common folder mentioned above.

    • Add refernce to the three DLLs to the created sample application:

      1. Microsoft.ApplicationBlocks.Updater.ActivationProcessors.dll

      2. Microsoft.ApplicationBlocks.Updater.Downloaders.dll

      3. Microsoft.ApplicationBlocks.Updater.dll



    • Add the code, present at the end of the document to the application that forms the body for handling the download (from the #region Auto-Update Stuff To #endregion).Note: The downloadable source has this content, but what the heck.

    • Add the following code to the constructor of the SampleForm Class to start off the updater manager:

      InitializeAutoUpdater ();





  3. Update the App.Config file using Enterprise library Configuration Tool.

    • Open the tool from Start -> All Programs -> Microsoft Patterns and Practices -> Updater Application Block V2 -> Enterprise Library Configuration Tool.

    • In the Configuration tool console, select File -> Open Application and browse to the App.Config file, select and click Open.

    • A new item “Application” appears under the root “Enterprise Library Configuration”.

    • Rightclick Application and select New ?> Updater Application Block Configuration.

    • Configuration, Cryptography and Updater Application Blocks are added.

    • Update the properties of the application block:

      1. ApplicationID: SampleApplication.

      2. BasePath: C:TempUpdaterTestUAB.

      3. ManifestUri: http://localhost/ApplicationBlockServer/ServerManifest.xml.Note: The ManifestUri will point to a URL that has to be created later.



    • Rightclick Updater Application Block and select New -> Downloaders.

    • Rightclick Downloaders and select New -> BITSDownloader.

    • Save.



  4. Deploy the Client

    • Build the SampleApplication project.

    • Copy the output of the project from the bin/Debug folder to the folder C:TempUpdaterTest. The files to be copied are:

      1. All the DLLs including the following:

        1. Microsoft.ApplicationBlocks.Updater.ActivationProcessors.dll

        2. Microsoft.ApplicationBlocks.Updater.dll

        3. Microsoft.ApplicationBlocks.Updater.Downloaders.dll



      2. The application exe: SampleApplication.exe

      3. The config file: SampleApplication.exe.config



    • Copy the files updaterconfiguration.config and securitycryptographyconfiguration.config present in the root folder of the project to the folder UpdaterTest.



  5. Change the project to create the server application.The server application will be a newer version of the application deployed at c:temp UpdaterTest.

    • Open the SampleApplication solution in VS.NET editor.

    • Open SampleForm in designer mode and make noticeable changes on the form. Change the label text to “Version 1.0.0.1” and the form text to “Sample Form New Version”.

    • Open AssemblyInfo.cs and change the assembly version to 1.0.0.1: [assembly: AssemblyVersion("1.0.0.1")].

    • Build the application.



  6. Deploy the Server Application.The new version of the application will be deployed at the server, from where it can be downloaded.

    • Create a folder called ApplicationBlockServer under C:inetpubwwwroot.

    • Open IIS manager (Start -> Run -> Inetmgr).

    • In the IIS manager, navigate to Default Web Site.

    • Rightclick on Default Web Site and select “New -> Virtual Directory”.

    • Create a virtual directory with alias ApplicationBlockServer and the folder pointing to ApplicationBlockServer folder created above.

    • Create a new folder called 1.0.0.1 under the folder c:inetpubwwwroot ApplicationBlockServer.

    • Copy the file SampleApplication.exe built in the previous step to the newly created folder 1.0.0.1.



  7. Build the Manifest file for the server

    • Open the Manifest Editor tool that was also installed along with the updater block (Start -> All Programs -> Microsoft Patterns and Practices -> Updater Application Block V2 -> Manifest Editor Tool.

    • Under Manifest Properties Tab, click the Generate button and generate the manifest id. Check the Mandatory check box.

    • Enter the description “Sample Application Version 1.0.0.1”.

    • In the application properties tab, enter the application id as “SampleApplication” and location as “.”

    • The entry point is “SampleApplication.exe”.

    • The File URI is http://localhost/ApplicationBlockServer/1.0.0.1.

    • The source folder is “C:InetpubwwwrootApplicationBlockServer1.0.0.1”.

    • Click the “Add” button and select SampleApplication.exe from the 1.0.0.1 folder. The file must appear in the Files list.

    • In the activation process tab, enter the process name as AppDeploy and processor type as “Application Deploy” and press “Add”.

    • Enter process name as “WFE” and processor type as “Wait For Exit” and press Add. A new window prompts to add a process name. Press Cancel.

    • Click the Validate button to validate the generated manifest.

    • Click the Save button to Save the manifest at “C:InetpubwwwrootApplicationBlockServer” as “ServerManifest.xml”.



  8. Run the application at “C:TempUpdaterTest”.The application, after some time, will pops up a dialog box telling that a newer version is available and do you want to download it. Click yes. The newer version will be downloaded which will be displayed in the list box eventList. After downloading, it will prompt you to restart the application. Close the application and start it again. The version 1.0.0.1 will open up.

    Addendum:

    • Once the update of the application happens, a folder called UAB gets created in the UpdaterTest folder. This folder gives the information about the latest version present.

    • From what I could understand, the manifest ID is maintained at the server and if an update occurs for the client, the manifest ID is placed in the UAB folder. If the manifest ID of the server is different from that of the client (or if the client does not have the UAB folder, meaning no updates have yet taken place), the updater block swings into action.

    • To deploy a newer version of the application on the server, create a new folder 1.0.0.2 and dump all the files at that location (the naming convention is just a convention for convenience, not a rule) and generate a new server manifest file with a new Manifest ID and replace the old manifest file.

    • I have not checked the auto update feature, i.e. the client can be scheduled to ping the server at regular intervals. But this must be straight forward as setting some property somewhere.

    • The code below has a thread to ping the server every 10 seconds. That part can be removed.




Hey, this was just a vanilla implementation.

Auto Update Code to be pasted in the application
Collapse


#region Auto-Update Stuff

private Thread pollThread = null;
private int manifestDownloaded = 0;

private void CheckAndUpdate()
{
try
{
// Get the updater manager

ApplicationUpdaterManager updater =
ApplicationUpdaterManager.GetUpdater();

// Subscribe for various events

updater.DownloadStarted +=
new DownloadStartedEventHandler(updater_DownloadStarted);
updater.DownloadProgress +=
new DownloadProgressEventHandler(updater_DownloadProgress);
updater.DownloadCompleted +=
new DownloadCompletedEventHandler(updater_DownloadCompleted);
updater.DownloadError +=
new DownloadErrorEventHandler(updater_DownloadError);
updater.ActivationInitializing +=
new ActivationInitializingEventHandler(updater_ActivationInitializing);
updater.ActivationStarted +=
new ActivationStartedEventHandler(updater_ActivationStarted);
updater.ActivationInitializationAborted +=
new ActivationInitializationAbortedEventHandler(
updater_ActivationInitializationAborted);
updater.ActivationError +=
new ActivationErrorEventHandler(updater_ActivationError);
updater.ActivationCompleted +=
new ActivationCompletedEventHandler(updater_ActivationCompleted);

// Loop till the updates are available


Manifest[] manifests = null;
while(true)
{
manifests = updater.CheckForUpdates();
if(manifests.Length > 0)
{
// Prompt user if he wants to apply the updates

if( MessageBox.Show(this,
"Update for Auto Inproc Application is available,"+
" do you want to apply the update?",
"Update",MessageBoxButtons.YesNo)== DialogResult.Yes)
{
foreach(Manifest m in manifests)
{
m.Apply = true;
}
// update the application as per manifest details.

updater.Download( manifests, TimeSpan.MaxValue );
if(manifestDownloaded == manifests.Length)
{
updater.Activate( manifests );
manifestDownloaded = 0;
}
break;
}
else
{
Thread.Sleep(10000);
}
}
else
{
Thread.Sleep(10000);
}
}
}
catch(ThreadAbortException)
{
// Do nothing if the thread is being aborted,

//as we are explicitly doing it

}
catch(Exception ex)
{
MessageBox.Show(this,ex.Message,"Error",
MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}

private void exitButton_Click(object sender, System.EventArgs e)
{
Application.Exit();
}

private void updater_DownloadStarted(object sender,
DownloadStartedEventArgs e)
{
UpdateList("DownloadStarted for manifest: " + e.Manifest.ManifestId);
}

private void updater_DownloadProgress(object sender,
DownloadProgressEventArgs e)
{
UpdateList("DownloadProgress for manifest: "+ e.Manifest.ManifestId +
"- Files: "+e.FilesTransferred+"/"+e.FilesTotal+
" - Bytes: "+e.BytesTransferred+"/"+e.BytesTotal);
}

private void updater_DownloadCompleted(object sender,
ManifestEventArgs e)
{
UpdateList("DownloadCompleted for manifest: " +
e.Manifest.ManifestId);
manifestDownloaded++;
}

private void updater_DownloadError(object sender,
ManifestErrorEventArgs e)
{
UpdateList("DownloadError for manifest: " +
e.Manifest.ManifestId +"n"+e.Exception.Message);
}

private void updater_ActivationInitializing(object sender,
ManifestEventArgs e)
{
UpdateList("ActivationInitializing for manifest: " +
e.Manifest.ManifestId);
}

private void updater_ActivationStarted(object sender, ManifestEventArgs e)
{
UpdateList("ActivationStarted for manifest: " + e.Manifest.ManifestId);
}

private void updater_ActivationInitializationAborted(object sender,
ManifestEventArgs e)
{
UpdateList("ActivationInitializationAborted for manifest: " +
e.Manifest.ManifestId);
MessageBox.Show(this,
"The Application needs to restart for applying the updates," +
" please restart the application.",
"Auto Inproc Updates",MessageBoxButtons.OK,
MessageBoxIcon.Information);
}

private void updater_ActivationError(object sender,
ManifestErrorEventArgs e)
{
UpdateList("ActivationError for manifest: " + e.Manifest.ManifestId +
"n"+e.Exception.Message);
}

private void updater_ActivationCompleted(object sender,
ActivationCompleteEventArgs e)
{
UpdateList("ActivationCompleted for manifest: " + e.Manifest.ManifestId);
}

private void UpdateList(string displayString)
{
eventList.Items.Add(displayString);
eventList.Update();
}

private void InitializeAutoUpdater ()
{
// Seperate thread is spun to keep polling for updates

ThreadStart checkUpdateThreadStart = new ThreadStart(CheckAndUpdate);
pollThread = new Thread(checkUpdateThreadStart);
pollThread.Start();
}
#endregion




License


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors may to use can be found here

About the Author







Praveen Nayak












Occupation: Web Developer
Location: United Kingdom United Kingdom

C#



Sample Image - maximum width is 600   pixels

<!-- Add the article text. Please use simple formatting (

, etc) -->

Introduction


Got Bored.

The Library Project


I created a ChatLibrary that will contain the valid commands and a Message that will contain the parsing.
Collapse


public enum Command
{
Login = 0,
PersonalMessage = 1,
ClientList = 2,
Conference = 3,
Logout = 4
};

public class Message
{
string strSender;
string strReceiver;
Command cmdMessageCommand;
string strMessageDetail;
public Message ()
{
}
public Message (byte [] rawMessage)
{
string strRawStringMessage = System.Text.Encoding.ASCII.GetString (rawMessage);
string [] strRawStringMessageArray = strRawStringMessage.Split(new char []{'|'});
this.strSender = strRawStringMessageArray[1];
this.strReceiver = strRawStringMessageArray[2];
this.cmdMessageCommand = (Command) Convert.ToInt32(strRawStringMessageArray[3]);
this.MessageDetail = strRawStringMessageArray[4];
}
...

public byte [] GetRawMessage ()
{
System.Text.StringBuilder sbMessage = new System.Text.StringBuilder ("John");
sbMessage.Append("|");
sbMessage.Append(strSender);
sbMessage.Append("|");
sbMessage.Append(strReceiver);
sbMessage.Append("|");
sbMessage.Append((int)cmdMessageCommand);
sbMessage.Append("|");
sbMessage.Append(strMessageDetail);
sbMessage.Append("|");
return System.Text.Encoding.ASCII.GetBytes(sbMessage.ToString());
}
...


The Server Project


I created a SocketServer that calls the TCPListener.Start() method

IPEndPoint endPoint = new IPEndPoint (ipaAddress, iPort);
listener = new TcpListener (endPoint);
listener.Start();


Upon calling Listen, a new thread will be created that will listen for incoming clients

thrListenForClients = new Thread(new ThreadStart(ListenForClients));
thrListenForClients.Start();


The ListenForClients method will wait for connections and will assign the incoming socket to a new Client instance.

Client acceptClient = new Client();
acceptClient.Socket = listener.AcceptTcpClient();
listenForMessageDelegate = new ListenForMessageDelegate (ListenForMessages);
listenForMessageDelegate.BeginInvoke(acceptClient, new AsyncCallback(ListenForMessagesCallback), "Completed");


The Client, by the way is a class that contains a TCPClient, so we can keep track of our connections

public class Client {
string strName;
TcpClient tcpClient;
public Client()
{
}
public string Name
{
get{return strName;}
set{ this.strName = value;}
}
public TcpClient Socket
{
get{return tcpClient;}
set{ this.tcpClient = value;}
}
public void SendMessage (Message sendMessage)
{
NetworkStream stream = tcpClient.GetStream();
stream.Write(sendMessage.GetRawMessage() , 0, sendMessage.GetRawMessage().Length);
}
}


Our server is now ready to listen for incoming messages. To do this, we pass the client socket that we received, then make a loop. We use a NetworkStream to read the message

NetworkStream stream = client.Socket.GetStream();
byte [] bytAcceptMessage = new byte [1024];
stream.Read(bytAcceptMessage, 0, bytAcceptMessage.Length);
Message message = new ChatLibrary.Message(bytAcceptMessage);


Once we receive the message, we can do anything that we want

txtStatus.Text += "rn" + strDisplayMessageType + strWriteText.TrimStart(new char[]{'r','n'});


My SocketServer makes use of a few events that makes coding a little easier

public event ClientConnectedEventHandler ClientConnected;
public event ClientDisconnectingEventHandler ClientDisconnecting;
public event MessageReceivedEventHandler MessageReceived;


In my ServerForm codes, what I did was I kept a copy of each connected Client in a ClientCollection that inherits from System.Collections.CollectionBase. With this, I can iterate through the Clients.

The Client Project


The Client does basically the same thing. I created a ClientSocket that will create a TCPListener and call Connect()

IPEndPoint serverEndpoint = new IPEndPoint (ipaAddress , iPort);
tcpClient = new TcpClient ();
tcpClient.Connect(serverEndpoint);
thrListenForMessages = new Thread (new ThreadStart(ListenForMessages));
thrListenForMessages.Start();


What ListenForMessages will do is to loop with NetworkStream.Read()

stream = tcpClient.GetStream();
byte [] bytRawMessage = new byte [1024];
stream.Read(bytRawMessage, 0, bytRawMessage.Length);
ChatMessage receivedMessage = new ChatLibrary.Message (bytRawMessage);


Then we do the same process, create a Message using the received bytes.

Again, my goal is to create a YM/MSN - looking Instant Messenger, so I made two UI forms. The MessengerForm and the ClientWindow. The MessengerForm is the class that instantiates the ClientSocket and receives the messages. upon receiving a message, it calls the MessengerWindow that should display the text.

Note that I didn't do a regular instantiation. I called Invoke to be able to make my controls thread safe

this.Invoke(createNewClientDelegate, new object []{receivedMessage});


History


June 2006 : Initial Version



License


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors may to use can be found here

About the Author







massivegas


John lives in the Philippines with his family, working as a programmer. He used to program VB6 but is now... ummm... trying to learn C# .Net.









Occupation: Web Developer
Location: Philippines Philippines

  1. Blsmphhd 2008.12.14 04:30 신고

    Thanks!,

C#



Screenshot - MyDownloader1.png

Introduction


MyDownloader is an open source application written in C# that is almost a complete download manager. MyDownloader has many features to manage downloads:

  • Segmented downloads from HTTP and FTP

    • With smart segments: when one segment ends, starts another segment to help to terminate another segment more fast



  • Allow downloads to be paused and resumed

  • (NEW) New friendly "New Video Download" window to download videos from: (you need save the file as *.flv)

    • You Tube

    • (NEW) Google Video

    • (NEW) Break

    • (NEW) PutFile

    • (NEW) Meta Cafe



  • (NEW) Speed Limit ? to avoid to use all your bandwidth

  • (NEW) Download Scheduler

    • (NEW) Download files only on allowed times

    • (NEW) Limit the number of simultaneous downloads

    • (NEW) When one download ends, starts another automatically



  • (NEW) Support for FTP site that requires authentication

  • (NEW) Support for Mirrors

  • (NEW) Download from HTTPS

  • Notification download completion with sounds and XP balloon

  • Anti-virus integration

  • Automatic retry when a segment or download fails

  • Batch downloads (enter a generic URL such as http://server/file(*).zip and MyDownloader generates a set of URLs with numbers or letters)


How a Segmented Download Works


Downloads can be segmented because both HTTP and FTP protocols allow the client to specify the start position of the stream. First, MyDownloader performs a request to the server to discover the file size. After that, MyDownloader calculates the segment size as follows:

segment size = min( (file size / number of segments), 
minimum allowed segment size )


With the segment size, MyDownloader creates another request specifying the start position of the stream. In this way, we can have multi-requests for the same files running in parallel using multi-threading techniques. This technique speeds up the transfer rate even more if you are using mirrors.

Using the Code: MyDownloader API


To start a segmented download using the MyDownloader API is very simple. Check the code below, extracted from the MyDownloader source code. When the download is finished, an XP balloon is displayed near the windows clock:

Screenshot - MyDownloader2.png
Collapse


// starts to listen to the event 'DownloadEnded' from DownloadManager

DownloadManager.Instance.DownloadEnded +=
new EventHandler<DownloaderEventArgs>(Instance_DownloadEnded);

// indicates that download should start immediately

bool startNow = true;

Downloader download = DownloadManager.Instance.Add(
"http://jogos.download.uol.com.br/videos/pc/thewitcher12.wmv",
@"c:tempthewitcher12.wmv",
3, // Three segments

startNow // Start download now

);

static void Instance_DownloadEnded(object sender, DownloaderEventArgs e)
{
if (Settings.Default.ShowBallon &&

AppManager.Instance.Application.NotifyIcon.Visible)
{
// Display the XP Balloon

AppManager.Instance.Application.NotifyIcon.ShowBalloonTip(
Settings.Default.BallonTimeout,
AppManager.Instance.Application.MainForm.Text,
String.Format("Download finished: {0}", e.Downloader.LocalFile),
ToolTipIcon.Info);
}
}


Plug-in Architecture


Many features from MyDownloader are implemented using the concept of extensibility. Because the most important classes in MyDownloader offer a lot of events, extensions can listen to those events to change the application behavior. Another nice thing is that each extension has its own settings. Therefore the Options dialog needs to be created based on extensions. If you open Options at design time, you will only see an empty Panel.

Screenshot - MyDownloader3.pngBelow, you can see how we load settings from the extension to populate the tree view:

for (int i = 0; i < App.Instance.Extensions.Count; i++)
{
IExtension extension = App.Instance.Extensions[i];
IUIExtension uiExtension = extension.UIExtension;

Control[] options = uiExtension.CreateSettingsView();

TreeNode node = new TreeNode(extension.Name);
node.Tag = extension;

for (int j = 0; j < options.Length; j++)
{
TreeNode optioNd = new TreeNode(options[j].Text);
optioNd.Tag = options[j];
node.Nodes.Add(optioNd);
}

treeOptions.Nodes.Add(node);
}


The DownloadManager that I showed in the beginning of this article also doesn't know anything about HTTP or FTP. DownloadManager accepts protocols registered on ProtocolProviderFactory, and the HTTP and FTP protocols are registered by an extension. Check the HTTP/FTP download extension:

public class HttpFtpProtocolExtension: IExtension
{
#region IExtension Members

public string Name
{
get { return "HTTP/FTP"; }
}

public IUIExtension UIExtension
{
get { return new HttpFtpProtocolUIExtension(); }
}

public HttpFtpProtocolExtension()
{
ProtocolProviderFactory.RegisterProtocolHandler("http",
typeof(HttpProtocolProvider));
ProtocolProviderFactory.RegisterProtocolHandler("https",
typeof(HttpProtocolProvider));
ProtocolProviderFactory.RegisterProtocolHandler("ftp",
typeof(FtpProtocolProvider));
}

#endregion
}


When we think of an HTTP download, what are the settings that an HTTP downloader would require? Proxy is one of the answers. Many users are behind an HTTP proxy and connecting directly to an HTTP server is not allowed in most companies.

So, to expose the settings for our HttpFtpProtocolExtension, we need to create an IUIExtension and return it through UIExtension property of IExtension. On this class we implement the method CreateSettingsView, that returns all settings that will be displayed on Options dialog.

public class HttpFtpProtocolUIExtension : IUIExtension
{
public System.Windows.Forms.Control[] CreateSettingsView()
{
// create the Proxy user control an return it.

return new Control[] { new Proxy() };
}

public void PersistSettings(System.Windows.Forms.Control[] settingsView)
{
...
}

...
}


The HttpFtpProtocolUIExtension class provides a factory method named CreateSettingsView. This creates an array of Controls that are the visualization of the extension settings. The Options dialog uses this array to populate the TreeView of options and display the setting on the right panel.

Protocol Abstraction


On previous versions of MyDownloader, the protocols support was implemented by classes that inhererited from Downloader. This was because the previous version didn't support Mirrors, so at the time, a single download could only come from one source. But now, with Mirrors features, we can have one piece of a download coming from HTTP and another piece coming from an FTP server.

For that reason, I have refactored the code and now all supported protocols (HTTP, FTP, HTTPS) are implemented by classes that implement IProtocolProvider. The concrete instance of IProtocolProvider is created by ProtocolProviderFactory, protocols providers classes are implemented in a different class hierarchy from the Downloader class. This is done to address the restriction of using a single protocol for the download.

To make it easier to retrive the correct IProtocolProvider, the ResourceLocation class has a factory method. This method is used by the Downloader class.

Screenshot - MyDownloader6.png

Video Downloads Abstraction


Like many MyDownloader features, video downloads is just another extension. The secret is at VideoDownloadExtension and the "New Video Download" window. All URLs in MyDownloader are represented by the ResourceLocation class ? this class has the method GetProtocolProvider which returns the apropriated instance of IProtocolProvider interface ? the only thing that we need to do (at "New Video Download") is to force the correct protocol provider type by setting the property ProtocolProviderType of ResourceLocation.

Setting this property, when ResourceLocation class calls GetProtocolProvider, the created protocol provider will be the type stored in ProtocolProviderType, and not the provider registed on ProtocolProviderFactory. In this way we can replace the default protocol provider, and avoid that the HTML content be saved, and force to download the video from web site.

The first step is register the Video protocol providers on VideoDownloadExtension:

public VideoDownloadExtension()
{
handlers = new List<VideoDownloadHandler>();
handlers.Add(new VideoDownloadHandler(YouTubeDownloader.SiteName,
YouTubeDownloader.UrlPattern, typeof(YouTubeDownloader)));
handlers.Add(new VideoDownloadHandler(GoogleVideoDownloader.SiteName,
GoogleVideoDownloader.UrlPattern, typeof(GoogleVideoDownloader)));
// ... register other sites here ...

}


After registering, we need to discover which video handler we need to use and also, set the corret protocol provider on the ProtocolProviderType property of ResourceLocation. This is done at "New Video Download" window, check bellow :

Screenshot - MyDownloader4.png

VideoDownloadExtension extension;
...
extension = (VideoDownloadExtension)App.Instance.GetExtensionByType(
typeof(VideoDownloadExtension));
...
handler = extension.GetHandlerByURL(txtURL.Text);
...
ResourceLocation rl = ResourceLocation.FromURL(txtURL.Text);
rl.ProtocolProviderType = handler.Type.AssemblyQualifiedName;


How a Download from YouTube Video Site Works


Basically, a video download from any site has three steps:

  • Download the HTML page from the video site

  • Parse the HTML to discover the video URL

  • Download the video URL


All common things are on BaseVideoDownloader class. This class retrieves the HTML and starts to download the video. The inherited classes (YouTubeDownloader, GoogleVideoDownloader) are responsible to parse the HTML text and return the video URL to the base class. Check the code:
Collapse


public abstract class BaseVideoDownloader : HttpProtocolProvider
{
private ResourceLocation mappedUrl;

protected abstract ResourceLocation ResolveVideoURL(string url,
string pageData);

public override Stream CreateStream(ResourceLocation rl,
long initialPosition, long endPosition)
{
return base.CreateStream(mappedUrl ?? rl, initialPosition, endPosition);
}

public override RemoteFileInfo GetFileInfo(ResourceLocation rl,
out Stream stream)
{
stream = null;

mappedUrl = null;
String pageData;

using (StreamReader sr = new StreamReader(this.CreateStream(rl, 0, 0)))
{
pageData = sr.ReadToEnd();
}

mappedUrl = ResolveVideoURL(rl.URL, pageData);

WebRequest request = this.GetRequest(mappedUrl);

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
RemoteFileInfo result = new RemoteFileInfo();
result.FileSize = response.ContentLength;
result.AcceptRanges = String.Compare(
response.Headers["Accept-Ranges"], "bytes", true) == 0;

if (response.ResponseUri != null)
{
mappedUrl.URL = response.ResponseUri.OriginalString;
}
else
{
stream = response.GetResponseStream();
}

return result;
}
}
}

public class YouTubeDownloader: BaseVideoDownloader
{
public const string SiteName = "You Tube";

//https://www.youtube.com/watch?v=5zOevLN3Tic

public const string UrlPattern =
@"(?:[Yy][Oo][Uu][Tt][Uu][Ee].[Cc][Oo][Mm]/watch?v=)(w[w|-]*)";

protected override ResourceLocation ResolveVideoURL(string url,
string pageData)
{
return ResourceLocation.FromURL(
String.Format("{0}/get_video?video_id={1}&t={2}",
TextUtil.GetDomain(url), TextUtil.JustAfter(url, "v=", "&"),
TextUtil.JustAfter(pageData, "t:'", "',sk:")));
}
}


Download Scheduler


The Download Scheduler is activated (or deactivated) thought the "two arrows" button in MyDownloader toolbar. When this feature is enabled, MyDownloader starts to work as a batch downloader, accomplishing each download on download queue.

The maximum number of downloads is configured in the "Options" dialog. Another nice thing is that the user is able to choose at which times the "Download Scheduler" will work. This is done easily by selecting the "time grid":

Screenshot - MyDownloader5.pngThe Download Scheduler, works using events (DownloadAdded, DownloadEnded, DownloadEnded) from DownloadManager. When some of these events were raised, the extension starts the download respecting the maximum number of simultaneous downloads:

using (DownloadManager.Instance.LockDownloadList())
{
int count = GetActiveJobsCount();
int maxJobs = Settings.Default.MaxJobs;

if (count < maxJobs)
{
for (int i = 0;
i < DownloadManager.Instance.Downloads.Count && (count < maxJobs);
i++)
{
if (DownloadManager.Instance.Downloads[i].State !=
DownloaderState.Ended &&
! DownloadManager.Instance.Downloads[i].IsWorking())
{
DownloadManager.Instance.Downloads[i].Start();
count ++;
}
}
}
}


Future Ideas


This kind of project is "infinite," so below I have listed some ideas for future implementations. As any open source project, it would be very nice if you wish to contribute.

  • Add and remove segments while downloading

  • Download only required files from a ZIP file (see this article)

  • Improve download rate limit

    • Option to disable the speed limit while screen saver is running



  • Integrate with FireFox and Internet Explorer

  • Improve mirrors feature by choosing the fasters mirrors sites

  • Support authentication on HTTP sites

  • Support MMS protocol

  • Create downloads category and allow downloads to be labeled

  • XY graph to show the bandwidth usage

  • Up Arrow / Down Arrow to allow the use to reorganize the download queue

  • Auto shutdown after download end

  • Hang-Up internet connection after download end

  • Support metalink

  • Video downloads:

    • Create a media monitor integrated with IE and FF that allows the user to download videos from any site

    • Options to convert videos from .FLV to .AVI, .MPG and .MP3



  • Clipboard Monitor, so when a URL is copied into the clipboard, the application prompts the user to download the file using the SetClipboardViewer API


I hope you enjoyed the code! If you have any questions or feedback, feel free to contact me.



License


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors may to use can be found here

About the Author







Guilherme Labigalini












Occupation: Web Developer
Location: Brazil Brazil

  1. Weelltalkpiota 2008.12.01 23:46 신고

    Hi. I regularly announce this forum. This is the oldest period undisputed to ask a ridiculous.
    How numberless in this forum are references progressive behind, artful users?
    Can I bank all the facts that there is?

  2. Digital Angel Master 2008.12.04 16:15 신고

    Here's source address :
    http://www.codeproject.com/KB/IP/MyDownloader.aspx

  3. ruiseabookessefab 2008.12.28 02:18 신고

    hello it is test. WinRAR provides the full RAR and ZIP file support, can decompress CAB, GZIP, ACE and other archive formats.
    qvwpidpoipkoxfgbajsnlhprjcjhjnyfouchello

  4. Paxuttele 2009.03.25 06:59 신고

    Excellent site digitalangelmaster.wordpress.com and I am really pleased to see you have what I am actually looking for here and this this post is exactly what I am interested in. It's taken me literally 2 hours and 18 minutes of searching the web to find you (just kidding!) so I shall be pleased to become a regular visitor :)

  5. Shailen Sobhee 2009.04.22 03:19 신고

    When I enter my username and password in the New Download form, I get a 13Kb html page.

    My ideas:
    -Rapidshare determines premium account using a cookie. Do you have to build a cookie container? Or will NetworkCredentials work?
    [webclient1.Credentials = new NetworkCredential("username", "password";);]


    Does anyone know a work around for this?

    PS: Why is there no C# rapidshare downloader?

  6. Shailen Sobhee 2009.04.22 03:38 신고

    The Downloader does not download rapidshare file using premium account details.

    When I enter my username and password in the New Download form, I get a 13Kb html page.

    My ideas:
    -Rapidshare determines premium account using a cookie. Do you have to build a cookie container? Or will NetworkCredentials work?
    [webclient1.Credentials = new NetworkCredential("username", "password";);]

    Does anyone know a work around for this?

    PS: Why is there no C# rapidshare downloader?

  7. Mabcypopy 2009.08.10 20:51 신고

    Hi,

    visit my blog: http://abraexchen.wordpress.com
    no spam!!!! no spam!!!

    visit us!!!!

  8. hypnoticgenius 2009.09.20 19:13 신고

    Hi all,

    New to the forum, just thought I'd introduce myself :-)

  9. HenryZB 2009.10.23 16:43 신고

    yep nice method .
    Till now I was using http://www.tubeleecher.com

  10. FlivaTawwew 2010.02.26 10:44 신고

    Hello People,

    I am new member here

    I lately discovered this place and so far i have found a lot of great information right here.
    I'm looking forward to connecting and adding to the forum.

  11. lotoobselve 2010.04.04 04:01 신고

    Hello People,

    I am new member here

    I just discovered this place and so far i have discovered lots of good information here.
    I'm looking forward to connecting and contributing to the forum.

  12. mrjohnkenwood 2010.05.24 23:00 신고

    Hey guys,

    Which is the best FLV Player, i don't want to spend money and i want it to be a good one and that supports Windows, with playlist, snap pictures.

    Thanks You for your help.

  13. fausiaroarivy 2010.05.30 12:23 신고

    hello to every one.Wish you all on be ok.

  14. whatiifthooughtt 2010.05.31 18:54 신고

    Just saying Hi for now!

  15. Silapolxxzz 2010.10.21 05:46 신고

    Hello !

    I'm new on this forum so I introduce me...

    My name is Jason I'm 21 years old, I'm Deutsch.

    I like: horses and kitesurf...

    Nice to meet you

C#
윈도 API를 사용하셔야할 것 같습니다.

using System.Runtime.InteropServices;

// API 정의
[DllImport("User32")]
private static extern int ShowWindow(IntPtr handle, int ShowMode)
private const int WM_SHOWNOACTIVATE = 4;

//?API 사용
myForm frm = new myForm();
ShowWindow(frm.Handle, WM_SHOWNOACTIVATE);

---------------------------------------- [원문] ----------------------------------------
cs 구조로 프로그램이 짜져 있으며

서버로 부터 어떤 메세지가 오면 , 네이트 온처럼 하단에서 팝업 창이 뜹니다.

문제는 팝업창이 떳을때 Form? 의 속성중에?? TopMost = True 주어서 띄우면

다른 프로그램에서 다른 작업을 하고 있을때 팝업이 떠 버리면 포커스가 그 팝업으로 가버립니다.

팝업 창은 최상위에 뜨게 하고 포커스는 현재 사용중인 프로그램으로 유지할수 있는 방법이 있을까요?

C#


Figure 1 - Kangaroo Hopping? Movie


Introduction


Just got back from a three week trip to Australia and all I can say is, "Give me a home among the gum trees." (Australian programmers will get what I'm saying here.).?Most people know what a kangaroo looks like, but most haven't seen one up close.?Needless to say, they are strange creatures if you are coming from the New York City.?Unfortunately, the?AVI kangaroo video taken by the digital camera was too large to upload to the site due to the size of the file. In any case, some of you are probably asking yourselves, "Kangaroos or not, how exactly do I play an AVI file in .NET?". This article will show you how by demonstrating the?implementation of a WinForm Video Player.


The Player


The Video Player takes advantage of the DirectX AudioVideoPlayback library. This library mindlessly allows you to play videos inside a Video object.?The methods of the Video class are very straight forward (e.g. Play, Stop, Pause) and you simply construct the video object with the name of the file (e.g. "roo.avi").? The tables below illustrate some important? methods and properties of the Video class.


 
































Method Description
Open(string filename) Opens an avi file with the passed parameter path name
Play Plays the video
Stop Stops the video
Pause Pauses the video
SeekCurrentPosition(double time,? SeekPositionFlags) Moves to a particular time position in the avi file relative to the SeekPositionFlag.? Time is in 1 x 10-7 seconds (or? 0.1 microseconds)
StopWhenReady Waits for the video object to be ready for stopping, and stops the video





































Property Type Description
Owner System.Windows.Forms.Control Sets The Window Forms Control that contains the video.
Fullscreen bool Sets whether or not the video is shown fullscreen
Size Size Sets the size of the video
Duration double Gets the time (in seconds) of the full video
CurrentPosition double Sets the position of the video
Audio Microsoft.DirectX.AudioVideoPlayback.Audio Audio object allows you to control things like the volume, balance and playing of the sound in the video

Coding


You must have DirectX 9 SDK installed to use the avi playing feature described in this article.? You can get this SDK from the Microsoft MSDN site.? (Note:? It may require an MSDN subscription to get the full SDK, but the redistributable that runs the video is a free download).? Once you have the DirectX SDK installed, you can include the Microsoft.DirectX.AudioVideoPlayback? assembly as a reference to your project.? Just right click on your project References in the Solution Explorer and add the reference as shown below.? (If this reference isn't in the .NET assembly list, you probably don't have the DirectX 9 SDK installed):



Figure 2 - Adding the DirectX AudioVideoPlayback Reference


Now you just need to add the using statement in your Form to begin using the Video class:


using Microsoft.DirectX.AudioVideoPlayback;


So now let's take a look at the implementation of the Video Class. The first step is to construct a Video object with the name of the video file which we retrieve from a OpenFile dialog.? We then assign the Video.Owner property to the panel inside our winform.? Also we resize the video to fit the original dimensions of the panel.? Finally we quickly play and pause the video, in order to see the first frame.

/// <summary>
/// opens a video from an avi file
/// and plays the first frame inside the panel
/// </summary>
void OpenVideo()
{
openFileDialog1.InitialDirectory = Application.StartupPath;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// open the video
// remember the original dimensions of the panel
int height = videoPanel.Height;
int width = videoPanel.Width;
// dispose of the old video to clean up resources
if (_video != null)
{
_video.Dispose();
}
// open a new video
_video = new Video(openFileDialog1.FileName);
// assign the win form control that will contain the video
_video.Owner = videoPanel;
// resize to fit in the panel
videoPanel.Width = width;
videoPanel.Height = height;
// play the first frame of the video so we can identify it
_video.Play();
_video.Pause();
}
// enable video buttons
ControlLogic();
}

That's really all there is to using the video object.? If we want to play the video until the end, we simply call the Play method on the video object .

/// <summary>
/// Plays the video
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnPlay_Click(object sender, System.EventArgs e)
{
if (_video != null)
{
_video.Play();
}
}

Conclusion

The Video class in the Microsoft.DirectX.AudioVideoPlayback library is a powerful graphics class with a very simple implementation.? Using this class, you can create powerful applications that include your favorite movie clips in the common avi format.? I suspect it will play other movie formats as well (such as mpeg), however, I haven't tried it.? Good luck with this powerful multimedia tool and using it to see sharp videos.

  1. 이전 댓글 더보기
  2. Digital Angel Master 2008.11.21 07:11 신고

    Ricky,
    No need distribute SDK to client.
    that program is using DirectX Runtime only.
    you can find the document of distribution in MSDN and http://download.microsoft.com

  3. Ricky 2008.11.22 20:50 신고

    SDk size is the same of the runtime :(

  4. Digital Angel Master 2008.11.24 15:20 신고

    no way.
    SDK imports runtime.
    in Download center, SDK was over then 300MB

  5. sehresh 2008.12.07 03:38 신고

    Hello
    can you plz tell me the exact link from where i can download the activeX SDk........
    plz tell me.....i really need. i m not getting in msdn site

  6. Digital Angel Master 2008.12.08 11:32 신고

    here it is.
    http://www.microsoft.com/downloads/details.aspx?FamilyID=5493f76a-6d37-478d-ba17-28b1cca4865a&amp;DisplayLang=en

  7. Alessandro 2009.02.01 01:55 신고

    Hi, nice tutorial. I have a qestion. How can I set to fullscreen with a double click on videoPanel?

  8. Digital Angel Master 2009.02.01 04:18 신고

    it can control from event.
    in designer dialog, usually right panel, you can find some "Thunder" icon.
    when "mouse over" when "mouse out" like that events can be control.

    you can double click to event contents, visual studio will give you "to do".
    &gt; video1.FullScreen(); &lt;
    put only this code. that's all.

  9. Alessandro 2009.02.01 09:45 신고

    I have already tryed it...
    This is the code:

    private void panel2_DoubleClick(object sender, EventArgs e)
    {
    MessageBox.Show("Test";);
    }

    If there is no video, I can see the messagebox. When a video starts and making a double click on panel, the megebox don't appear.
    I tryed to create a eventhandler on _video.owner, I get the same situation...

  10. rspercy58 2009.03.22 00:32 신고

    Alexander, the LoaderLock exception can be turned off. Click Debug, then Exceptions, then Managed Debugging Assistants. Scroll down till you see LoaderLock, Uncheck it.
    This is a By Project Only check.

    I made a AVI player that is error free. If you would like a copy w/full code, e-mail me at rspercy58@comcast.net and I'll send you a copy.

    I based my player on this same concept, but I got the same code from c-sharp corner. The guy that posted it is the owner of the site. Is this you?

    Regards

  11. theodora 2009.03.29 04:21 신고

    hello nice program...i made my own project using directX in order to play sounds like this
    filepath = My.Application.Info.DirectoryPath
    filepath = filepath.Substring(0, filepath.Length - 9)
    Dim MySound1 As New Microsoft.DirectX.AudioVideoPlayback.Audio(filepath &amp; "soundsAm.wav";)
    MySound1.Play()

    the program works fine but when i publish it the sounds wont play because of some problems with directX
    i know that the problem is that in project properties--&gt;publish--&gt;Application files where Microsoft.DirectX.AudioVideoPlayback.dll
    Microsoft.DirectX.Direct3D.dll
    Microsoft.DirectX.dll
    are not in the download group but i don't know what to do ....please help me...
    thanks in advance...sorry for my english
    theodora

  12. tibs 2009.04.24 03:10 신고

    I use visual c# 2005. does this code works with it?



    using Microsoft.DirectX.AudioVideoPlayback;

    So now let’s take a look at the implementation of the Video Class. The first step is to construct a Video object with the name of the video file which we retrieve from a OpenFile dialog. We then assign the Video.Owner property to the panel inside our winform. Also we resize the video to fit the original dimensions of the panel. Finally we quickly play and pause the video, in order to see the first frame.

    ///
    /// opens a video from an avi file
    /// and plays the first frame inside the panel
    ///
    void OpenVideo()
    {
    openFileDialog1.InitialDirectory = Application.StartupPath;
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
    // open the video
    // remember the original dimensions of the panel
    int height = videoPanel.Height;
    int width = videoPanel.Width;
    // dispose of the old video to clean up resources
    if (_video != null)
    {
    _video.Dispose();
    }
    // open a new video
    _video = new Video(openFileDialog1.FileName);
    // assign the win form control that will contain the video
    _video.Owner = videoPanel;
    // resize to fit in the panel
    videoPanel.Width = width;
    videoPanel.Height = height;
    // play the first frame of the video so we can identify it
    _video.Play();
    _video.Pause();
    }
    // enable video buttons
    ControlLogic();
    }

    That’s really all there is to using the video object. If we want to play the video until the end, we simply call the Play method on the video object .

    ///
    /// Plays the video
    ///
    ///
    ///
    private void btnPlay_Click(object sender, System.EventArgs e)
    {
    if (_video != null)
    {
    _video.Play();
    }
    }

  13. fatih 2009.05.09 00:12 신고

    I want to play automatically 3 avi videos which are called v1.avi, v2.avi, v3.avi, but I want to send send (1) to D1, D2, D3 pins of the parallel port when first (v1.avi) video is playing at the end, and second video is playing at the end and the last one... respectively, Can you help me about it?

  14. Digital Angel Master 2009.05.10 00:07 신고

    Tail to nose :D

  15. Dusan 2009.05.16 21:54 신고

    Hey m8, did anyone have solution for that?

    thanks

  16. Dusan 2009.05.16 22:07 신고

    edit: I found solution :D
    what i did is, i set mouse down event, and used e.Clicks, it works same as doubleclick

    void Owner_MouseDown(object sender, MouseEventArgs e)
    {
    if (e.Clicks == 2)
    {
    _video.Fullscreen = !_video.Fullscreen;
    }
    }

    I hope it helps, i know i had a lot of trouble to make that.

  17. sara 2009.06.14 17:57 신고

    i read ur artile ,which is very good well done .
    thank u for publishing it,however i have a problem,LoaderLock message i tried the solution u said that to uncheck the loader i did it but still got another error
    it says error in application in the bellow line:


    _video = new Video(openFileDialog1.FileName);

    please advice me to run it ,iam in ergent need for my gratuate project.
    thank u

  18. Digital Angel Master 2009.06.16 19:36 신고

    compile with release mode :D

    maybe almost loaderlock will be solved with that.

  19. Vincent 2009.10.13 20:10 신고

    I tried to use your solution for detecting a mouse click in the video but it doesn't work. If I set the mouse down event and i click on the video the event doesn't raise.

    Any help?

    Thank you

  20. a 2009.10.14 04:41 신고

    I think you nalso need to add a reference to DirectPlay ang DirectSound. Thi will solve the issue...

  21. TAN TH 2009.11.16 12:53 신고

    how do we repeat the video? that is, when it has reached the end, I want to start all over again.
    thanks

C#
How do I beep the computer's speaker in a Windows Form application




There is no Windows Form function to beep your computer's speaker. But you can just invoke the Win32 API MessageBeep.





using System.Runtime.InteropServices;





...





 





[DllImport("user32.dll")]





public static extern int MessageBeep(uint n);





 





private void button2_Click(object sender, System.EventArgs e)





{





MessageBeep(0x0);





}





 





Another method (suggested by msauper@sauper.com on microsoft.public.dotnet.framework.windowsforms)





 





Reference the VB.NET runtime support and just use the Beep() method.





 





The method is in:





 





Microsoft.Visual Basic.NET Runtime





 





The method is:





 





Microsoft.VisualBasic.Interaction.Beep();





 





 

이것 이외의 다른 방법은...



using System;
using System.Runtime.InteropServices;
using System.IO;

namespace Usecase
{
/// <summary>
/// 사운드
/// </summary>
public class WPlaySound
{
[DllImport("winmm.dll", EntryPoint="PlaySound",CharSet=CharSet.Auto)]
private static extern int PlaySound(String pszSound, int hmod, int falgs);
public enum SND
{
SND_SYNC ? ? ? ?= 0x0000 ?,/* play synchronously (default) */
SND_ASYNC ? ? ? ?= 0x0001 , /* play asynchronously */
SND_NODEFAULT ? ? ? ?= 0x0002 , /* silence (!default) if sound not found */
SND_MEMORY ? ? ? ?= 0x0004 , /* pszSound points to a memory file */
SND_LOOP ? ? ? ?= 0x0008 , /* loop the sound until next sndPlaySound */
SND_NOSTOP ? ? ? ?= 0x0010 , /* don't stop any currently playing sound */
SND_NOWAIT ? ? ? ?= 0x00002000, /* don't wait if the driver is busy */
SND_ALIAS ? ? ? ?= 0x00010000 ,/* name is a registry alias */
SND_ALIAS_ID ? ? ? ?= 0x00110000, /* alias is a pre d ID */
SND_FILENAME ? ? ? ?= 0x00020000, /* name is file name */
SND_RESOURCE ? ? ? ?= 0x00040004, /* name is resource name or atom */
SND_PURGE ? ? ? ?= 0x0040, ?/* purge non-static events for task */
SND_APPLICATION ? ? ? ?= 0x0080 ?/* look for application specific association */
}

/// <summary>
/// Wave 파일 재생
/// </summary>
/// <param name="pszSound">파일 경로</param>
public static void PlaySound(String pszSound)
{
if(File.Exists(pszSound))
{
PlaySound(pszSound,0,(int) (SND.SND_ASYNC | SND.SND_FILENAME |
SND.SND_NOWAIT));
}
}

/// <summary>
/// 시스템 사운드 이벤트 HKEY_CURRENT_USERAppEventsSchemesApps.Default
/// </summary>
/// <param name="pszSound">이벤트 이름</param>
public static void PlaySoundEvent(String pszSound)
{
PlaySound(pszSound,0,(int) (SND.SND_ASYNC | SND.SND_ALIAS | SND.SND_NOWAIT));
}
}
}
C#

Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report this article.





Introduction


These are some tips for commonly faced problems in .NET . Some of these tips are mine and some of these i have got from different sources. My aim is not to claim the ownership of these tips,but as a newcomer I had faced these problems and had to do lot of googling. So just to help my fellow programmers I am putting this together. One more reason is Codeproject.com ranks quiet ahead as compared to other sites of same nature, but still I was not able to find some basic solutions as below. So it is small effort from my side.

Windows Application


.NET Framework


1. How to get the path for "My Documents" and other system folders?
2. How to get the path to my running EXE?
3. How to determine which operating system is running?
4. How to get a file's name from the complete path string?
5. How to get a file's extension from the complete path string?
6. What is difference beween VB.NET and C#.NET?
7. How to find whether your system has mouse or the number of buttons, whether it has wheel, or whether the mouse buttons are swapped or size of your monitor and many such information?
8. What is the purpose of the [STA Thread] attribute for the Main method of a C# program?
9. How to import CSV data using .NET application?
10. How to find size of logical drives using .NET?
11. How can I get the index of substring in a sentence irrespective of it's case?
12. How to extract unique values from an array? Sample screenshot

OOPS


1. What are Copy Constructors?
2. What are Read-Only Constants?

VS.NET IDE


1. How to manage code snippets in VS.NET IDE?
2. How to display Line Numbers in code editor?
3. How to change the color of the regions?

Controls


Forms


1. How to create a form with resizing borders and no title bar?
2. How to use XP Themes with Windows Forms using the .NET?
3. How to prevent a form from being shown in the taskbar?
4. How to open default E-mail client on your system with all parameters entered in it,like Outlook Express or Eudora, from your .NET windows or Web Application?
5. How to create Pop-Up Alert windows like messengers?
6. What is difference between Anchoring and Docking?

Buttons


1. How to set the default button for a form?
2. How to set the Cancel button for a form?
3. How to trigger a button click event?

Combo Box


1. How to fill a ComboBox with the available fonts?

Text Box


1. How to disable the default ContextMenu of a TextBox?
2. How to enter multiline text in textbox through code?
3. Some useful TextBox Validations
4. How to unselect the text in textbox after it receives focus?

DateTime Picker


1. How to make the DateTimePicker show empty text if no date is selected?

Data Grid


1. How to remove the indeterminate status of checkbox in datagrid?
2. How to group columns in DataGrid?

Panel


1. How to make a Panel or Label semi-transparent on a Windows Form?

WebBrowser Control


1. How to print the contents of Web Browser control?
2. How to assign custom Header and Footer and other page settings while printing the contents of Web Browser control?

ADO.NET


1. How to bind two controls to the same DataTable without having changes in one control also change the other control?

Crystal Reports


1. How to hide the status bar of Crystal Report in Report Viewer?
2. How to generate PDF version of Crystal Report programmatically?
3. How to select a printer while printing through Crystal Report programmatically?

Deployment


1. How to install database while deploying .NET application ?
2. How to install MSDE while deploying .NET application?
3. How to create conditional shortcuts while deploying .NET application?

Miscellaneous


1. How to enable the mnemonics (underline) being displayed when an application is launched
2. An easy way to build connection string.
3. How to add a custom or destination folder to SendTo menu?

Windows Application


.NET Framework


#1. How to get the path for "My Documents" and other system folders?


Use the GetFolderPath method of the System.Environment class to retrieve this information.



  MessageBox.Show( Environment.GetFolderPath( Environment.SpecialFolder.Personal ) );

#2. How to get the path to my running EXE?


The Application class has a static member ExecutablePath that has this information.



string appPath = Application.ExecutablePath;

Alternative: The tip below is provided by cbono2000



System.Reflection.Assembly.GetExecutingAssembly().Location

#3. How to determine which operating system is running?


Use System.Environment's OSVersion static (shared) property.



OperatingSystem os = Environment.OSVersion;
MessageBox.Show(os.Version.ToString());
MessageBox.Show(os.Platform.ToString());

#4. How to get a file's name from the complete path string?


Use System.IO.Path.GetFileName and System.IO.Path.GetFileNameWithoutExtension static methods.



#5. How to get a file's extension from the complete path string?


Use System.IO.Path.GetExtension static method.



#6. What is difference beween VB.NET and C#.NET?


Hi friends, click here to find the best comparison ever between VB.NET and C#.NET .



#7. How to find whether your system has mouse or the number of buttons, whether it has wheel, or whether the mouse buttons are swapped or size of your monitor and many such information?



Use System.Windows.Forms.SystemInformation.
SystemInformation provides static (Shared in Visual Basic) methods and properties that can be used to get information such as Windows display element sizes, operating system settings, network availability, and the capabilities of hardware installed on the system.This class cannot be instantiated. e.g
MousePresent:    SystemInformation.MousePresent.ToString()
MouseButtonsSwapped: SystemInformation.MouseButtonsSwapped.ToString()

#8. What is the purpose of the [STA Thread] attribute for the Main method of a C# program?


That marks the thread as being Single 
Thread Apartment which means any multiple threaded calls need to be marshaled
over to that thread before they are called. That's there because Windows Forms
uses some OLE calls (Clipboard for example), which must be made from the thread
that initialized OLE.

#9. How to import CSV data using .NET application?


Importing CSV files using .NET application

#10. How to find size of logical drives using .NET?



Sample image
There is direct method in .NET for computing the file size but there is no such method for computing directory size and logical drive size.One may think of just adding file size to get directory size and then drive size. But this method has some drawbacks. But we can use Win32 API function GetDiskFreeSpaceEx for this purpose.
The GetDiskFreeSpaceEx function retrieves information about the amount of space that is available on a disk volume, which is the total amount of space, the total amount of free space, and the total amount of free space available to the user that is associated with the calling thread. You can do it as following: Enlist the drives:
string[] tempString = Directory.GetLogicalDrives();
foreach(string tempDrive in tempString)
{
cmbDrives.Items.Add(tempDrive);
}
cmbDrives.SelectedIndex=0;

public sealed class DriveInfo
{

[DllImport("kernel32.dll", EntryPoint="GetDiskFreeSpaceExA")]
private static extern long GetDiskFreeSpaceEx(string lpDirectoryName,
out long lpFreeBytesAvailableToCaller,
out long lpTotalNumberOfBytes,
out long lpTotalNumberOfFreeBytes);

public static long GetInfo(string drive, out long available, out long total, out long free)
{
return GetDiskFreeSpaceEx(drive,out available,out total,out free);
}

public static DriveInfoSystem GetInfo(string drive)
{
long result, available, total, free;
result = GetDiskFreeSpaceEx(drive, out available, out total, out free);
return new DriveInfoSystem(drive,result,available,total,free);
}

}

public struct DriveInfoSystem
{
public readonly string Drive;
public readonly long Result;
public readonly long Available;
public readonly long Total;
public readonly long Free;

public DriveInfoSystem(string drive, long result, long available, long total, long free)
{
this.Drive = drive;
this.Result = result;
this.Available = available;
this.Total = total;
this.Free = free;
}
}

and then you can use it as
DriveInfoSystem info = DriveInfo.GetInfo("c:");

#11. How can I get the index of substring in a sentence irrespective of it's case?


The IndexOf method of the string class is case-sensitive. There are two possible ways to overcome this problem.


1. Convert the case of whole sentence and the substring into any one case and then find the index of particular substring.



string strParent = "The Codeproject site is very informative.";
string strChild = "codeproject";

// The line below will return -1 when expected is 4.
int i = strParent.IndexOf(strChild);

// The line below will return proper index
int j = strParent.ToLower().IndexOf(strChild.ToLower());

2. Use IndexOf method of CompareInfo class in System.Globalization namespace. This is a more professional and elegant way of doing this.



using System.Globalization;

string strParent = "The Codeproject site is very informative.";
string strChild = "codeproject";

// We create a object of CompareInfo class for a neutral culture or a culture insensitive object
CompareInfo Compare = CultureInfo.InvariantCulture.CompareInfo;

int i = Compare.IndexOf(strParent,strChild,CompareOptions.IgnoreCase);

#12. How to extract unique values from an array? Sample screenshot


The solution is tricky. Use hashtable and fill the array elements as keys of Hashtable. When there is duplication of KEY values, hashtable will naturally throw exception, just skip that element and continue. To implement this, use recursion to add array elements to Hashtable and in Catch block (Try .. Catch block) call same function again with next index. Please find the code below.


Collapse



static string [] strObj = {"A","A","B","C","C","D","E","F","B","C","G","F"};
static Hashtable UniqueHT = new Hashtable();
static int i =0;
[STAThread]
static void Main(string[] args)
{
FindUniqueElements(0);
}

private static void FindUniqueElements(int index)
{
try
{
for(i=index; i< strObj.Length; i++)
{
// Start adding the elements from array as value for KEY in HashTable
UniqueHT.Add(strObj[i], "Any Value");
Console.WriteLine(strObj[i]);
}

Console.ReadLine();
}
catch(Exception)
{
// When there is duplication of KEY value in HashTable, the exception will be raised
// which can be handled in Catch block by just executing the same function with next index as parameter.
FindUniqueElements(i+1);
}
}

OOPS


#1. What are Copy Constructors?


We know that a constructor is a special method that has the same name as the class and returns no value.
It is used to initialize the data in the object we're creating.

There's another kind of constructor?the copy constructor. When we copy one object to another, C# will copy the reference to the first object to the new object, which means that we now have two references to the same object. To make an actual copy, we can use a copy constructor, which is just a standard constructor that takes an object of the current class as its single parameter. For example, here's what a copy constructor for the Student class might look like. Note that we're copying the name field to the new object.



public Student(Student student)
{
this.name = student.name;
}

Now we can use this constructor to create copies. The copy will be a separate object, not just a reference to the original object.
class Student
{
private string name;

public Student(string name)
{
this.name = name;
}

public Student(Student student)
{
this.name = student.name;
}

public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
}

class Final
{
static void Main()
{
Student student = new Student ("A");
Student NewStudent = new Student (student);
student.Name = "B";
System.Console.WriteLine("The new student's name is {0}", NewStudent.Name);
}
}

The new student's name is A.

#2. What are Read-Only Constants?


There are situations where we would like to decide the value of a constant member at run-time. We may also like to have different constant values for different objects of class. To overcome these shortcomings, C# provides another modifier known as readonly to be used with data members. This modifier is designed to set the value of the member using a constructor method, but cannot be modified later. The readonly members may be declared as either static fields or instance fields. When they are declared as instance fields, they can take different values with different objects. Consider the code below:



class Numbers
{
public readonly int m;
public static readonly int n;
public Numbers (int x)
{
m=x;
}

static Numbers ()
{
n=100;
}
}

The value for m is provided at the time of creation of an object using the constructor with parameter x. This value will remain constant for that object. Remember, the variable n is assigned a value of 100,even before the creation of any objects of Numbers.



VS.NET IDE


#1. How to manage code snippets in VS.NET IDE?


In VS.NET Editor in Code View you can select and drag code to a Tab (other than the Clipboard ring) in the ToolBox and then you can drag the code from the Tab to the desired location.



#2. How to display Line Numbers in code editor?


In the VS.NET IDE , from Menu select TOOLS > OPTIONS>TEXT EDITOR (in left window) >ALL LANGUAGES > LINE NUMBERS You can show Line Numbers depending on languages by selecting specific language in TEXT EDITOR like C# or Basic and checking Line Numbers option



#3. How to change the color of the regions?


In the VS.NET IDE , from Menu select TOOLS > OPTIONS > ENVIRONMENT (in left window) > FONTS AND COLORS > DISPLAY ITEMS (on right side) >COLLAPSIBLE TEXT . After selecting this you can set the color.



Controls


Forms


#1. How to create a form with resizing borders and no title bar?


Set the form's Text and ControlBox properties.



 
form1.Text = string. Empty;
form1.ControlBox = false;

#2. How to use XP Themes with Windows Forms using the .NET?


You need to install XP on your machine and the theme should be set to XP.You also need to ensure that the FlatStyle property of the control is changed to System and then add following line of code in your Main() method



static void Main() 
{
Application.EnableVisualStyles();
Application.DoEvents();
Application. Run(new Form1());
}

#3. How to prevent a form from being shown in the taskbar?


Set the form's ShowInTaskbar property to False to prevent it from being displayed in the Windows taskbar.



#4. How to open default E-mail client on your system with all parameters entered in it,like Outlook Express or Eudora, from your .NET windows or Web Application?


This can be achieved very easily though it seems complicated in beginning. Use MailTo command for this .I had faced this problem while developing Windows Application. This is very common command and known to many web developers but the great thing about this command is that it works as smoothly with windows application as it works with Web Application.

Syntax:


MailTo:email@address1.com

Some other features of this commands are discussed below:




























Features Syntax
Address message to multiple recipients , ? (comma separating e-mail addresses)
Add entry in the "Subject" field ?subject=Subject Field Text
Add entry in the "Copy To" or "CC" field &cc=id@internet.node;
Add entry in the "Blind Copy To" or "BCC" field &bcc=id@internet.node
Add entry in the "Body" field &body=Your message here

Following is the complete syntax:

Web Applications:


A href="mailto:email@address1.com,email@address2.com?cc=email@address3.com&Subject=Hello&body=Happy New 

Year"

Windows Application:


Use System.Diagnostics.Process
Process process = new Process();
process.StartInfo.FileName = "mailto:email@address1.com,email@address2.com?subject=Hello&cc=email@address3.com
&bcc=email@address4.com&body=Happy New Year"
;
process.Start();

#5. How to create Pop-Up Alert windows like messengers?



Sample image

I always thought about the ways to create alert windows like messenger pop-ups.This is one such attempt. The logic is simple. Just open the form below taskbar and slowly bring it up using timer so we can have the animated effect. Similarly you can close it. One thing we should be careful about is the 'Resolution' of monitor, since the location of form will change accordingly. So instead of directly locating the form with pre-defined co-ordinates, we will calculate the working area of the screen and place our form accordingly. To calculate the working area of the screen we can use Screen. GetWorkingArea(control), which gives the working area of the screen without taskbar.



We can position the form initially using following method:
X=Screen.GetWorkingArea(this).Width; // This line gives the width of working area
Y=Screen.GetWorkingArea(this).Height; // This line gives the width of working area
this.Location=new Point(X-this.Width,Y+this.Height); // This line sets the initial location of the form

Now we will open the form as below:
int i = this.Location.Y; 

if(i>Y-this.Height)
{
this.Location=new Point(X-this.Width,i-8);
}
else
{
timer1.Stop();
timer1.Enabled=false;

timer3.Start();
timer3.Enabled=true;
}

Similarly we'll close the form
   timer3.Stop();
timer3.Enabled=false;
int i = this.Location.Y;

if(i<Y)
{
this.Location=new Point(X-this.Width,i+8);
}
else
{
timer2.Stop();
timer2.Enabled=false;
this.Close();
}

#6. What is difference between Anchoring and Docking?


Though both Anchoring and Docking are helpful while resizing application windows, Anchoring helps control in retaining its size and location with respect to container controls when the container is not attached to particulae edge of the container but somewhere in middle.


The Docking feature attaches a control to the edge of its container. When a control is docked to an edge of it's container, it will always stick to that edge. The control will also resize itself to fully fit the edge of the container and also resizes as the container is resized. The Dock property of the Form control can be set to any one of the six values, Top, Bottom, Left, Right, Fill, and None.




In simple words, there cannot be gap between edge of child control and edge of container control when docked.

Anchoring specifies how a control anchors to the edges of its container. When a control is anchored to an edge of its container, the distance between the control and the specified edge remains constant when the container resizes. For example, if a control is anchored to the right edge of its container, the distance between the right edge of the control and the right edge of the container remains constant when the container resizes. A control can be anchored to any combination control edges. If the control is anchored to opposite edges of its container (for example, to the top and bottom), it resizes when the container resizes.




In simple words, there can be or cannot be gap between edge of child control and edge of container control when anchored.

Buttons


#1. How to set the default button for a form?


Default Button of a form means that button on form whose click event fires when Enter key is pressed. To make a button on form as default set the form's AcceptButton property. You can do this either through the designer, or through code such as



form1.AcceptButton = button1;

#2. How to set the Cancel button for a form?


Cancel Button of a form means that button on form whose click event fires when ESC key is pressed. To make a button on form as Cancel set the form's CancelButton property. You can do this either through the designer, or through code such as



form1.CancelButton = button1;

#3. How to trigger a button click event?


In VB 6.0 it was possible to call CommandButton click event from anywhere like any other method or function (Sub). But in .NET it is not possible in same way. But .NET provides a very simple way to do this. Just use the button's public method PerformClick.



button1.PerformClick();

Alternative: The tip below is provided by kaminm
You can trigger a button (Web and Win) by calling Buttonclick with null parameters
btnClear_Click(null,null)

Alternative: The tip below is provided by Paul Brower
You can use it this way, if you're planning on doing something with the sender object, you have a reference to it.
button1_click(button1,EventArgs.Empty)

Combo Box


#1. How to fill a ComboBox with the available fonts?


comboBox1.Items.AddRange (FontFamily.Families);

Text Box


#1. How to disable the default ContextMenu of a TextBox?


To prevent the default context menu of a TextBox from showing up, assign a empty context menu as shown below:



textBox1.ContextMenu = new ContextMenu ();

#2. How to enter multiline text in textbox through code?


Sometimes it is needed to show data on different lines. The first idea that comes is to set MULTILINE Property to true and use 'n' escape sequence for this. But this escape sequence is not supported in .NET textbox. Still it very easy to overcome this problem. To assign multiline text at design time, in the designer window use the LINES property of TextBox control. For achieving this at runtime, create an array of string and assign it to LINES property of Textbox as shown below.



string [] strAddress = {"Mukund Pujari","Global Transformation Technologies","Pune, India"};
textBox1.MultiLine=true;
textBox1.Lines=strAddress;

Alternative: The tip below is provided by joelycat
.NET text boxes don't recognize n but they do recognize rn. Try:

textBox1.Text="Line 1rnLine2rnLine3.";

Alternative: The tip below is provided by Robert Rohde
Actually "System.Environment.NewLine" should be used instead. This way you are platform independant.

Alternative: The tip below is provided by Redgum
simply use a "RichTextBox" for those areas on your form that require multiple lines
of randomly output text, and use a simple text box for those that do not.

#3. Some useful TextBox Validations


Numeric TextBox

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if ( !( char.IsDigit( e.KeyChar ) || char.IsControl( e.KeyChar ) ) )
{
e.Handled = true;
}
}

Numeric TextBox with Decimals

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if ( !( char.IsDigit( e.KeyChar) || char.IsControl( e.KeyChar ) ||(e.KeyChar== (char )46)) )
{
e.Handled = true;
}
}

TextBox Allowing Characters Only

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if ( !( char.IsLetter( e.KeyChar ) || char.IsControl( e.KeyChar ) ) )
{
e.Handled = true;
}
}

TextBox Allowing Upper Case Characters Only

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if ( !( char.IsUpper( e.KeyChar ) || char.IsControl( e.KeyChar )) )
{
e.Handled = true;
}
}

TextBox Allowing Lower Case Characters Only

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if ( !( char.IsLower( e.KeyChar ) || char.IsControl( e.KeyChar )) )
{
e.Handled = true;
}
}

Check For Unfilled TextBox

// Call this function and pass the Textbox as parameter to this function
public static bool ChkEmpty(params System.Windows.Forms.TextBox[ ] tb)
{
int i;
for (i = 0; i < tb.Length; i++)
{
if (tb[i].Text.Trim() == "")
{
MessageBox.Show("Don't keep field empty");
tb[i].Focus();
return false;
}
}
return true;
}

Localizing Validations - Country Specific Decimal Character

The tip below is provided by curt
Here he tells us, how different characters can be used for decimals depending upon the countries. For e.g. people in France may use character other than dot (.) for decimal point.
string DecimalSeparator = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if ( !( char.IsDigit( e.KeyChar) || char.IsControl( e.KeyChar ) || (DecimalSeparator.IndexOf(e.KeyChar) != -1 ) ) )
{
e.Handled = true;
}
}

#4. How to unselect the text in textbox after it receives focus?


Whenever a textbox having text gets focus, the text in it is selected. To avoid this just set the SelectionStart property of this textbox to length of the text in it, mostly in ENTER. event of the textbox.If anyone has better idea please suggest.
textBox1.SelectionStart = textBox1.Text.Length;

DateTime Picker


#1. How to make the DateTimePicker show empty text if no date is selected?


Use following code in some Button Click event:
dateTimePicker1.CustomFormat=" ";
dateTimePicker1.Format=DateTimePickerFormat.Custom;

Data Grid


#1. How to remove the indeterminate status of checkbox in datagrid?


The checkbox in checkbox column of datagrid shows indeterminate status by default. To remove this behaviour set AllowNull property of the CheckBox column to false as below:
DataGridTableStyle ts1 = new DataGridTableStyle(); // Create New TableStyle
ts1.MappingName = "Items"; // Assign the name of Data Table to which Style is applied
DataGridColumnStyle boolCol = new DataGridBoolColumn(); // Create a CheckBox column
boolCol.MappingName = "ch"; // Assign the name of Data Column
boolCol.AllowNull=false; // This property actually removes the indeterminate status of checkboxes

#2. How to group columns in DataGrid?



Sample image
Hi friends, you may be knowing better ways of doing it, but I managed to find this solution in the time limit I had been given. The logic is that, while looping through datatable we save the values of current column and previous column and we compare it. If Current Value is same as Previous Value, we don't show it in grid and if it is not same then we show it.

Collapse


Collapse


Collapse


Collapse



/* The logic is that, while looping through datatable we save the 
values of current column and previous column and we compare it.
If Current Value is same as Previous Value, we don't show it in grid
and if it is not same then we show it.

1. We save value of current column in variable 'strCurrentValue'.
2. After the loop we assign the value in 'strCurrentValue' to
variable 'strPreviousValue'.
3. And in next loop, we get new value in 'strCurrentValue'.
4. Now we can compare value in 'strCurrentValue' and 'strPreviousValue'
and accordingly show or hide values in the column.
*/

int m;
for(m=0;m<8;m++)
{

object cellValue = dt.Rows[m]["Category"]; // Here we catch the value form current column
strCurrentValue=cellValue.ToString().Trim(); // We assign the above value to 'strCurrentValue'

if(strCurrentValue!=strPreviousValue) // Now compare the current value with previous value
{
dt.Rows[m]["Category"]=strCurrentValue; // If current value is not equal to previous
// value the column will display current value
}
else
{
dt.Rows[m]["Category"]=string.Empty; // If current value is equal to previous value
// the column will be empty
}
strPreviousValue=strCurrentValue; // assign current value to previous value
}
strCurrentValue=string.Empty; // Reset Current and Previous Value
strPreviousValue=string.Empty;

Panel


#1. How to make a Panel or Label semi-transparent on a Windows Form?


You can make a panel or label transparent by specifying the alpha value for the Background color.
panel1.BackColor = Color.FromArgb(65, 204, 212, 230);

NOTE:In the designer you have to enter these values
manually in the edit box. Don't select the color using the ColorPicker.

WebBrowser Control


#1. How to print the contents of Web Browser control?


Though there is no direct Print method for printing the contents of web browser but there is very easy way which does more than printing. Use ExecWB method of Web Browser control. This method executes a command on an OLE object and returns the status of the command execution using the IOleCommandTarget interface. By using this method you can print, preview ,set up the page and do many more things. You can also decide whether the dialogs should be prompted to user or not.

For details of syntax and values of attributes please refer MSDN.

In the example given below, we are printing the contents by specifying it in first parameter and we are prompting the Printer Selection Dialog to user by passing second parameter
object em =null;
axWebBrowser1.ExecWB (SHDocVw.OLECMDID.OLECMDID_PRINT,SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_PROMPTUSER,
ref em, ref em);

Similarly you can use this for setting Page Set Up. E.g.
object em =null;
axWebBrowser1.ExecWB (SHDocVw.OLECMDID.OLECMDID_PAGESETUP,SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_PROMPTUSER,
ref em, ref em);

#2. How to assign custom Header and Footer and other page settings while printing the contents of Web Browser control?


I came across many codes on codeproject itself where people have suggested very good ways of assigning custom Header and Footer. But all these code were in C++. So, I being a C# programmer felt it difficult to convert this code. But I came across an alternative and very easy way of doing it. Just change the values of header and footer in registry programmatically.

Web Browser control shares same page settings as Internet Explorer. You can see the header and footer of IE by going to File > Page Set Up …> Header & Footer.

The following steps outline how Microsoft Internet Explorer accesses the printer settings:

1. Internet Explorer tries to obtain the values from the following registry key:

HKEY_CURRENT_USERSoftwareMicrosoftInternet ExplorerPageSetup

2. If the key in step 1 does not exist, Internet Explorer tries to create this key by copying the values from the following key:

HKEY_LOCAL_MACHINESoftwareMicrosoftInternet ExplorerPageSetup

3. If the key in step 2 does not exist, default values are provided.

NOTE: These registry values are system-wide and affect all instances of the WebBrowser control and Internet Explorer for the current user. Following e.g. shows how to set custom header for IE or WebBrowser control.
public void SetupHeaderWB()
{
string strPath = "SoftwareMicrosoftInternet ExplorerPageSetup";
Microsoft.Win32.RegistryKey oKey = null;

/* The following lines of code takes care that error does not occur if registry settings are not at proper path.*/
oKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey (strPath, true);
if (oKey! =null)
{
oKey = microsoft.Win32.Registry.CurrentUser.OpenSubKey (strPath, true);
}
else
{
oKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (strPath, true);
}

string strKey = "header";
object oValue = "Test header";
oKey.SetValue (strKey, oValue);
/* You can also get the value in registry by following line of code
string strValue=oKey.GetValue (strKey).ToString();*/

oKey.Close();
}

ADO.NET


#1. How to bind two controls to the same DataTable without having changes in one control also change the other control?


This is very common problem, as a newcomer I had spent great deal of time to solve this. Suppose you have two controls viz, Combobox and Listbox on same form and Datasource property of both these controls is same. Then the selection in one control selects same item in other control. This problem occurs because of BindingContext property of controls. By default the BindingContext member of each of the two controls is set to the Form's BindingContext. Thus, the default behavior is for the ComboBox and Listbox to share the same BindingContext, and that's why the selection in the ComboBox is synchronized with the current item of Listbox. If you do not want this behavior, create a new BindingContext member for at least one of the controls.
comboBox1.DataSource = dataset.Tables[ "Items" ]; 
comboBox1.ValueMember = "CustomerID";
comboBox1.DisplayMember = "CustomerID";

listBox1.BindingContext = new BindingContext(); // Set the BindingContext property of ListBox to new BindingContext
listBox1.DataSource = dataset.Tables[ "Items" ];
listBox1.ValueMember = "CustomerID";
listBox1.DisplayMember = "CustomerID";

Crystal Reports


#1. How to hide the status bar of Crystal Report in Report Viewer?


The following block makes the status bar of Crystal Report invisible.
foreach(object obj in this.crystalReportViewer1.Controls)
{
if( obj.GetType()== typeof(System.Windows.Forms.StatusBar))
{
StatusBar sBar=(StatusBar)obj;
sBar.Visible=false;
}
}

#2. How to generate PDF version of Crystal Report programmatically?


Following block of code generates PDF version of Crystal Report programmatically.
ReportDocument O_Report=new ReportDocument();
ExportOptions exportOpts = new ExportOptions();
PdfRtfWordFormatOptions pdfFormatOpts = new PdfRtfWordFormatOptions ();
DiskFileDestinationOptions diskOpts = new DiskFileDestinationOptions();

exportOpts = O_Report.ExportOptions;

// Set the PDF format options.
exportOpts.ExportFormatType = ExportFormatType.PortableDocFormat;
exportOpts.FormatOptions = pdfFormatOpts;

// Set the disk file options and export.
exportOpts.ExportDestinationType = ExportDestinationType.DiskFile;
diskOpts.DiskFileName = "C://Trial.pdf"; // This is the path where the file will be saved
exportOpts.DestinationOptions = diskOpts;

O_Report.Export ();

#3. How to select a printer while printing through Crystal Report programmatically?


You can accomlish this using PrintDialog control and get the computer name using printDialog1.PrinterSettings.PrinterName
// Create a Report Document
ReportDocument O_Report=new ReportDocument();

private void btnPrint_Click(object sender, System.EventArgs e)
{
try
{ // Create a Print Dialog
PrintDialog printDialog1 = new PrintDialog();

// Create a Print Document
PrintDocument pd = new PrintDocument();

printDialog1.Document=pd;
printDialog1.ShowNetwork=true;
printDialog1.AllowSomePages=true;

DialogResult result = printDialog1.ShowDialog();
if (result == DialogResult.OK)
{
PrintReport(printDialog1.PrinterSettings.PrinterName);
}
}

catch(Exception ex)
{
MessageBox.Show(ex.Message);
}

}

private void PrintReport(string printerName)
{
// Select the printer.
O_Report.PrintOptions.PrinterName = printerName;

/* Print the report. Set the startPageN and endPageN
parameters to 0 to print all pages.*/

O_Report.PrintToPrinter(1, false,0,0);
}

Deployment


#1. How to install database while deploying .NET application ?


Solution 1
Solution 2

#2. How to install MSDE while deploying .NET application?


Installing MSDE with .NET Application

#3. How to create conditional shortcuts while deploying .NET application?


Creating Conditional shortcuts

Miscellaneous


#1. How to enable the mnemonics (underline) being displayed when an application is launched


Usually the underline appears only after you press the Alt Key, but you can enable it by changing the Operating System Settings. On Windows XP, Right Click Desktop to bring up the Display Properties Dialog and then choose Appearance tab and then the Effects Button and uncheck the checkbox "Hide Underlined letters for keyboard navigation until I press the ALT Key".

#2. An easy way to build connection string.


Though this in not related to .NET directly but it is useful while working with ADO.NET
1) Open a New notepad and save it with "udl" extension, suppose "New.udl".
2) Now you will see that it's icon is changed.
3) Open it, you will find Data Link properties dialog box.
4) For SQl Server connection string select <CODE>Microsoft OLE DB Provider For SQL Server in Provider Tab.
5) Click button "Next" or select Connection Tab
6) Here you can select all connection details and press button
Test Connection. If it is successful close this dialog box.
7) Now open this file using "Notepad", you will find the connection string. Though it is built for OLE DB
type of connection, you can use for SQL Server connection by removing Provider attribute.

NOTE: If you are using SQL Authentication with password, then check the checkbox Allow Saving Password.
This is necessary so that password appears in connection string.

#3. How to add a custom or destination folder to SendTo menu?


Every one knows about SendTo menu that appears after right click on any file.By default there are 4 options or destinations in this menu. But you can add custom destinations to this menu.

Adding other locations to the Send To menu is convenient if you frequently perform the same file management tasks. For example, if you back up files on another network computer or on same machine where you have to navigate through a deep path every day, having the computer on the Send To menu can save you time.

To add a destination to the Send To menu follow the steps given below:

  1. Open My Computer.

  2. Double-click the drive where Windows is installed (usually drive C, unless you have more than one drive on your computer). If you can't see the items on your drive when you open it, under System Tasks, click Show the contents of this drive.

  3. Double-click the Documents and Settings folder.

  4. Double-click the folder of a specific user.

  5. Double-click the SendTo folder. The SendTo folder is hidden by default. If it is not visible, on the Tools menu, click Folder Options. On the View tab, click Show hidden files and folders.

  6. On the File menu, point to New, and then click Shortcut.

  7. Follow the instructions on your screen.





About Mukund Pujari








*****

Click here to view Mukund Pujari's online profile.








Other popular C# Controls articles:



+ Recent posts