Marshaling Unions

Before You Start

If this is your first time you hear about unions or you need to know more about them, please refer to our article “A short speech about Unions” first.

How to Marshal a Union

You can marshal a union the same way you marshal structures. However, because of the way that unions laid-out into memory, you will need to explicitly set variable positions inside the type.

You can marshal a union in few steps:

  1. Create your marshaling type, no matter whether your marshaling type is a managed structure or class. However, you should consider the passing mechanism when working with reference types like classes.
  2. Decorate the type with the StructLayoutAttribute attribute specifying LayoutKind.Explicit to control exactly the memory location of every member inside the type.
  3. Add your required fields only. Because we are controlling the memory layout explicitly, order of fields is no important.
  4. Decorate every field with FieldOffsetAttribute attribute specifying the absolute position -in bytes- of the member from the start of the structure.

Example

Consider the following union:

union SOME_CHARACTER {
	int iCode;
	char cChar;
};

Now, it’s the time for the meat of our lesson. The following code snippets defines the marshaling type of our union:

    [StructLayout(LayoutKind.Explicit)]
    public struct SOME_CHARACTER
    {
        // Both members located on the same
        // position in the beginning of the union

        // This is the continer. it is 4 bytes
        [FieldOffset(0)]
        [MarshalAs(UnmanagedType.I4)]
        public int iCode;

        // This is only 1 byte.
        [FieldOffset(0)]
        public char cChar;
    }

    static void Main()
    {
        SOME_CHARACTER character = new SOME_CHARACTER();

        // The code for letter 'A'
        character.dwCode = 65;
        // Should prints 'A'
        Console.WriteLine("wcChar = {0}", character.wcChar);

        character.wcChar = 'B';
        // Should prints 66
        Console.WriteLine("Code = {0}", character.dwCode);
    }

From the previous code, we learn that€¦

  • Unions marshaled like structures, they can be marshaled as either managed structures or classes.
  • Setting StructLayoutAttribute.LayoutKind to LayoutKind.Explicit allows us to exactly control the memory location of the members.
  • We use the FieldOffsetAttribute to specify the starting location in bytes of the field into the type in memory.
  • To create the union between the fields, we set both the fields to the same memory location.
  • In the example, iCode begins from byte 0 to byte 4. And cChar begins from byte 0 to byte 1.
  • If we do not need to take advantage of the union, we can emit cChar because it is contained inside the range of iCode. But, we cannot emit iCode because it is the container.
  • When we change either one of the union variables, the other variable changes too because they share the same memory address. Notice that in our example, int is 4-bytes and char is only 1 byte. Therefore, iCode interprets the whole value, while cChar interprets only the first byte (8 bits) of the value.

Unions with Arrays

Now, consider the following union:

union UNION_WITH_ARRAY
{
    int nValue;
    char str[10];
};

This union must be marshaled in a special way because managed code does not permit value types and reference types to overlap.

As a refresher, a value-type is the type stored into the stack memory; it inherits from System.ValueType. Value-types represented in all primitive data types, structures, and enumerations. On the other hand, reference-types are types stored in the memory heap; they inherit from System.Object. Most types in .NET are reference-types (except System.ValueType of course.)

As a result, we cannot union both members of our example, because whether marshaling the second variable str as an array, a System.Text.StringBuilder, or a System.String, it is still a reference-type. Therefore, we have to leave the advantage of unions, and marshal only a single member. For our example, we will create two marshaling types for our union, one with the first member marshaled, and the other with the other member.

As we know, the layout and size of the type inside the memory is the most crucial. Therefore, we must preserve the layout and size of our union. This union has a 10-bytes array as a container and only one member contained, and this member is only 4-bytes. Therefore, we have two choices, to marshal the union with the container member, or to marshal it with the contained member but to extend it enough to be as large as the container. In this example, we will take the two approaches.

The following are two code segments. The first demonstrates how to marshal only the second member which is the container, while the second demonstrates how to marshal the first member.

    // Setting StructLayoutAttribute.CharSet
    // ensures the correct encoding for all
    // string members of the union in our example
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public struct UNION_WITH_ARRAY_1
    {
        // As we know, character arrays can be marshaled
        // as either an array or as a string

        // Setting MarshalAsAttribute is required
        // for the array and the string

        // That is another way:
        //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        //public char[] charArray;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string charArray;
    }

    // StructLayoutAttribute.Size determines
    // the size -in bytes- of the type.
    // If the size specified is larger than
    // members' size, the last member will be extended
    // Because this is only a single
    // member, we laid it out sequentially.
    [StructLayout(LayoutKind.Sequential, Size = 128)]
    public struct UNION_WITH_ARRAY_2
    {
        [MarshalAs(UnmanagedType.I2)]
        public short number;
    }

Try it out!

If you are brave enough, you might try to marshal DEVMODE structure; that is one of the most complex structures in the Windows API. If you are interested you can refer to the MSDN library for the documentation of DEVMODE structure. Don’t be shocked when you first see that structure. (My advice is to pray for God before you think about marshaling DEVMODE structure.)

Sending Mails in .NET Framework

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

فيديو AR002: إرسال رسائل البريد الإلكتروني في ASP.NET

App: Mail+.msi
Code: Mail+ Source-Code.msi

Contents

Contents of this article:

  • Overview
  • Introduction
  • Type Overview
    • System.Net.Mail Types
    • System.Web.Mail Types
  • SMTP Servers
  • Implementation
  • Changing Mail Delivery Method
    • Configuring IIS Default Pickup Directory
    • Programmatically Changing Delivery Method
  • A Sample Application
  • Summary

Overview

This lesson focuses on how to send mail messages in .NET Framework via a SMTP server. It firstly discusses the techniques which .NET Framework provides you to send mail messages. After that, it discusses types available for you when working with SMTP servers. Next, it discusses how to implement these techniques and to send mails from a .NET client.

At the end of this lesson, there is a sample application, Geming Mail+, which is used to send mails from a various SMTP servers. This application is open-source, so you can download its code freely.

Introduction

Simple Mail Transport Protocol or simply SMTP provides a way for applications to connect to the mail server and send mail messages via server’s exposed SMTP service.

Before .NET 2.0, you were to access SMTP via classes in System.Web.Mail namespace which resides in System.Web.dll library. With the release of .NET 2.0, System.Web.Mail classes became deprecated and replaced with classes in System.Net.Mail namespace which exists in System.dll library. That means that you still can use classes of System.Web.Mail, however, you will receive warnings indicate that those classes are deprecated and you should use classes from System.Net.Mail namespace.

Type Overview

System.Net.Mail Types

System.Net.Mail namespace includes many types each of which provides a special feature. In fact, the most time you will not need to use all of them or to know them at all. However, being aware of what .NET provides to you for accessing SMTP is better to help you evolving your SMTP client application in many sides and in various degrees. Here are the most common classes of System.Net.Mail:

  • SmtpClient:
    One of the essential classes provides you with means of connecting to the SMTP server and sending mail messages. Before starting using this class and send a message, you must initialize server properties like Host, Port, and EnableSsl to allow communicating with the SMTP server. SmtpClient also provides you with some methods like the Send method that sends a specific message synchronously, and SendAsync to send it asynchronously.
  • MailMessage:
    The message to be sent using the SmtpClient class. This class exposes many properties specific to the message like To, CC, Bcc, Subject, and Body properties that corresponds to the message fields.
  • MailAddress:
    Encapsulates a mail address. Provides the DisplayName and Address properties.
  • MailAddressCollection:
    A collection of MailAddress objects. This collection is used inside the MailMessage object in the properties To, CC, and Bcc.
  • Attachment:
    Encapsulates an attached file.
  • AttachmentCollection:
    A collection of Attachment objects. Used in the MailMessage class in its Attachments property.
  • SmtpException:
    Represents an exception thrown from the SmtpClient if it failed to send a message. Use SmtpException’s StatusCode property to determine the error occurred. In addition, see the inner exception for more details.
  • SmtpFailedRecipientException and SmtpFailedRecipientsException:
    Represent exceptions thrown when the SmtpClient fails to send a message to a specific recipient or a group of recipients. Both classes are derived from SmtpException.
  • SmtpPermission and SmtpPermissionAttribute:
    If you are aware of your code running from various locations or from an unsecure environment, you can use these classes to control how your application should access SMTP servers. You use SmtpPermission to control application permissions imperatively. SmtpPermissionAttribute is used to control the permissions declaratively. Consult MSDN documentation for more information about these types and how to use them.

In addition, System.Net.Mail includes various enumerations each represents a set of options for a specific feature. For example, MailPriority enumeration is exposed via the Priority property of a MailMessage object; it can take one of three values, Low, Normal, and High, and it is used to mark your message with a specific priority flag.

System.Web.Mail Types

Besides types in System.Net.Mail, for whose interested in .NET 1.0 and descendent before .NET 2.0, we will cover types of System.Web.Mail briefly. In fact, they are very few types, actually, they are only three classes and three enumerations, and they serve the same as types in System.Net.Mail.

Classes in System.Web.Mail:

  • SmtpMail:
    Serves the same as System.Net.Mail.SmtpClient. However, it exposes only a single property SmtpServer. Plus, it exposes methods for sending mail messages.
  • MailMessage:
    Encapsulates message related information and data like To, CC, BCC, Subject, and Body fields.
  • MailAttachment:
    Encapsulates an attachment. MailMessage exposes a list of MailAttachment objects via its Attachments property.

Besides those only three classes, System.Web.Mail also includes three enumerations, MailEncoding, MailFormat, and MailPriority. I think that those enumerations have expressive names enough and do not need to be explained. If you need some explanation consult MSDN documentation or continue reading this article. Although, this article concentrates on types from System.Net.Mail, they are very similar to the types in System.Web.Mail.

SMTP Servers

In order to connect to a SMTP server you need to be aware of four things:

  • Server address:
    Like smtp.example.com.
  • Port number:
    Usually 25, and sometimes 465. Depends on server’s configuration.
  • SSL:
    You need to know if the server requires a SSL (Secure Socket Layer) connection or not. To be honest, most servers require SSL connections.
  • Credentials:
    You need to know if the server accepts default credentials of the user or requires specific credentials. Credentials are simply the username and password of the user. All e-mail service providers require specific credentials. For example, to connect to your Gmail’s account and send mails via Gmail’s SMTP server, you will need to provide your mail address and password.

The following is a list of some of the major e-mail service providers who provide SMTP services for their clients:

Name Server Address Port SSL Required?
Live smtp.live.com 25 Yes
Gmail smtp.gmail.com 465, 25, or 587 Yes
Yahoo! plus.smtp.mail.yahoo.com 465, 25, or 587 Yes
Only for Plus! accounts. Consult Yahoo! documentation for more help about selecting the right port number.
GMX mail.gmx.com 25 No

Implementation

The following is a simple code segment uses classes from System.Net.Mail namespace to send mail messages via Gmail’s SMTP server.

Do not forget to add a using statement (Imports in VB.NET) for the System.Net.Mail namespace.

// C# Code

MailMessage msg = new MailMessage();

// Your mail address and display name.
// This what will appear on the From field.
// If you used another credentials to access
// the SMTP server, the mail message would be
// sent from the mail specified in the From
// field on behalf of the real sender.
msg.From = new MailAddress("example@gmail.com", "Example");

// To addresses
msg.To.Add("friend_a@example.com");
msg.To.Add(new MailAddress("friend_b@example.com", "Friend B"));

// You can specify CC and BCC addresses also

// Set to high priority
msg.Priority = MailPriority.High;

msg.Subject = "Hey, a fabulous site!";

// You can specify a plain text or HTML contents
msg.Body =
    "Hello everybody,<br /><br />" +
    "I found an interesting site called " +
    "<a href="http://JustLikeAMagic.com">" +
    "Just Like a Magic</a>. Be sure to visit it soon.";
// In order for the mail client to interpret message
// body correctly, we mark the body as HTML
// because we set the body to HTML contents.
msg.IsBodyHtml = true;

// Attaching some data
msg.Attachments.Add(new Attachment("C:\Site.lnk"));

// Connecting to the server and configuring it
SmtpClient client = new SmtpClient();
client.Host = "smtp.gmail.com";
client.Port = 578;
client.EnableSsl = true;
// The server requires user's credentials
// not the default credentials
client.UseDefaultCredentials = false;
// Provide your credentials
client.Credentials =
    new System.Net.NetworkCredential("example@gmail.com", "buzzwrd");
client.DeliveryMethod = SmtpDeliveryMethod.Network;

// Use SendAsync to send the message asynchronously
client.Send(msg);
' VB.NET Code

Dim msg As New MailMessage()

' Your mail address and display name.
' This what will appear on the From field.
' If you used another credentials to access
' the SMTP server, the mail message would be
' sent from the mail specified in the From
' field on behalf of the real sender.
msg.From = New MailAddress("example@gmail.com", "Example")

' To addresses
msg.To.Add("friend_a@example.com")
msg.To.Add(New MailAddress("friend_b@example.com", "Friend B"))

' You can specify CC and BCC addresses also

' Set to high priority
msg.Priority = MailPriority.High

msg.Subject = "Hey, a fabulous site!"

' You can specify a plain text or HTML contents
msg.Body = _
    "Hello everybody,<br /><br />" &amp; _
    "I found an interesting site called " &amp; _
    "<a>" &amp; _
    "Just Like a Magic</a>. Be sure to visit it soon."
' In order for the mail client to interpret message
' body correctly, we mark the body as HTML
' because we set the body to HTML contents.
msg.IsBodyHtml = True

' Attaching some data
msg.Attachments.Add(New Attachment("D:Site.lnk"))

' Connecting to the server and configuring it
Dim client As New SmtpClient()
client.Host = "smtp.gmail.com"
client.Port = 578
client.EnableSsl = True
' The server requires user's credentials
' not the default credentials
client.UseDefaultCredentials = True
' Provide your credentials
client.Credentials = _
    New System.Net.NetworkCredential("example@gmail.com", "buzzwrd")
client.DelieryMethod = SmtpDeliveryMethod.Network

' Use SendAsync to send the message asynchronously
client.Send(msg)

Changing Mail Delivery Method

You can specify that messages sent do not go to the SMTP server. Instead, it is sent to a directory in your computer that you specify. Actually, it is a good idea when it comes to testing your application. Thus, decreases the testing time.

SmtpClient supports two properties for changing mail delivery location; they are DeliveryMethod and PickupDirectoryLocation properties. DeliveryMethod specifies the delivery method that would be taken when sending the message. This property is of type SmtpDeliveryMethod enumeration; therefore, it can be set to one of three values:

  • Network: (default)
    The message is sent via the network to the SMTP server.
  • PickupDirectoryFromIis:
    The message is copied to the mail default directory of the Internet Information Services (IIS).
  • SpecifiedPickupDirectory:
    The message is copied to the directory specified by the property PickupDirectoryLocation.

Configuring IIS Default Pickup Directory

To change the IIS default pickup directory in IIS 7 follow the following steps:

  1. Start Internet Information Services (IIS) 7 Manager.
  2. From the Home view, select SMTP E-mail item. Figure 1 shows the SMTP E-mail item in the IIS 7 MMC snap-in.

    Figure 1 - Selecting SMTP E-mail Item in IIS 7
    Figure 1 - Selecting SMTP E-mail Item in IIS 7
  3. From the SMTP E-mail configuration view, change the default pickup directory by choosing the option €œStore e-mail in pickup directory€ and selecting your desired directory using the Browse button. Figure 2 shows the SMTP E-mail view while changing pickup directory options.

    Figure 2 - Configuring SMTP E-mail Pickup Directory
    Figure 2 - Configuring SMTP E-mail Pickup Directory
  4. From the right pane, click Apply to save your current settings.

Programmatically Changing Delivery Method

The following lines change the delivery location to a specific location in the drive C. You can add the following lines before the line that calls Send() method of the SmtpClient.

In order for the example to run correctly, the specified directory must be existed or you will receive an exception when executing the Send() method.

    // C# Code
    client.DeliveryMethod =
        SmtpDeliveryMethod.SpecifiedPickupDirectory;
    client.PickupDirectoryLocation = "C:\mails";
    ' VB.NET Code
    client.DeliveryMethod =
        SmtpDeliveryMethod.SpecifiedPickupDirectory
    client.PickupDirectoryLocation = "C:mails"

A Sample Application

Geming Mail+ is an application that is used to send mails via extendable variety of SMTP servers. This application created using .NET 2.0 and Visual Studio 2008. The following are snapshots of the application:

Geming Mail+ Splash Geming Mail+

Download the application here

Download the source code Here

Summary

This lesson was a great introduction to e-mail programming in .NET Framework. You learned how to send mails via a SMTP server. Soon we will cover how to receive mails in .NET Framework.

Have a nice day…

Working with SQL Server Logins

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Overview

This lesson discusses all the details of SQL Server logins. It begins by discussing how to create SQL Server logins. After that, it focuses on how to change the properties of existing login. Next, it discusses how to delete an existing login. Moreover, we will focus on how to enumerate a list of existing logins and roles. Lastly, we will talk a look on how to manage login permissions in SQL Server. In addition, we will link between SQL Server and .NET Framework and we will teach you many techniques other than what this lesson is focusing on.

Table of Contents

This is the table of contents of this lesson:

  • Overview
  • Table of Contents
  • Introduction
  • Creating a SQL Server Login
    • Creating a Login via SQL Server Management Studio
    • Creating a Login via the CREATE LOGIN T-SQL Statement
      • Creating a Login from a Windows Domain Account
      • Creating a Login Specific to SQL Server
    • Creating a Login via a System Stored Procedure
    • Creating a Login via .NET
  • Using the Login to Access SQL Server
    • Accessing SQL Server via SQL Server Management Studio
    • Accessing SQL Server via .NET
  • Changing an Existing Login
    • Changing a Login via SQL Server Management Studio
    • Changing a Login via the ALTER LOGIN T-SQL Statement
      • Changing the Name and Password of a Login
      • Enabling/Disabling a Login
    • Changing a Login via .NET
  • Deleting an Existing Login
    • Deleting a Login via SQL Server Management Studio
    • Deleting a Login via the DROP LOGIN T-SQL Statement
    • Deleting a login via a System Stored Procedure
    • Deleting a Login via .NET
  • Enumerating Existing Logins
  • Working with Permissions
    • Changing User Permissions via Login Properties Dialog
    • Changing User Permissions via Server Properties Dialog
  • References
  • Summary

Introduction

Today, we are concentrating on how to work with SQL Server logins. A login is simply credentials for accessing SQL Server. For example, you provide your username and password when logging on to Windows or even your e-mail account. This username and password build up the credentials. Therefore, credentials are simply a username and a password.

You need valid credentials to access your SQL Server instance or even to access a database from a .NET application for instance. Like Windows credentials, SQL Server uses multiple credentials to secure each of its granules differently from the other. For example, Windows links the user’s identity with multiple roles. Therefore, user is allowed to access only the resources that are allowed for him based on his identity and roles. In addition, using ACL you can limit access to some system resources and allow others. SQL Server on the other hand uses credentials to manage what the user is allowed to do with SQL Server. For instance, a specific user may not be allowed to access the Northwind database or even to modify it only.

For those reasons and more, we decide to discuss in this lesson how to work with SQL Server logins.

SQL Server allows four types of logins:

  1. A login based on Windows credentials.
  2. A login specific to SQL Server.
  3. A login mapped to a certificate.
  4. A login mapped to asymmetric key.

Actually, we are interested in only logins based on Windows Credentials and logins specific to SQL Server. For more information about mapped logins, consult MSDN documentation.

Logins based on Windows credentials, allows you to log in to SQL Server using a Windows user’s name and password. If you need to create your own credentials (username and password,) you can create a login specific to SQL Server.

Creating a SQL Server Login

To create, alter, or remove a SQL Server login, you can take one of three approaches:

  1. Using SQL Server Management Studio.
  2. Using T-SQL statements.
  3. Using system stored procedures.

Of course, you can combine the last two approaches with either the SQL Server IDE or through .NET code.

If you are using SQL Server Express, you can skip the first way that creates the login using the SQL Server Management Studio.

Creating a Login via SQL Server Management Studio

To create a login via the SQL Server Management Studio, follow those steps:

  1. Open the SQL Server Management Studio.
  2. Connect to the Database Engine.
  3. From the Object Explorer step down to the Security object node then to the Logins node.
  4. Right-click the Logins node and choose New Login. This brings up the New Login dialog. Figure 1 shows SQL Server Management Studio while in the Logins view.

    Figure 1. - Creating a Login
    Figure 1. - Creating a Login
  5. 2. In the New Login dialog, select your required login type and enter the required information. If you want to create a login from a Windows domain account, select ‘Windows authentication’ and enter the domain name and account name in the ‘Login name’ field. You may use the Search button to determine if the name exists. It is worth mentioning that you can add a Windows domain group login too not a user only. If you want to create a login specific to SQL Server, select ‘SQL Server authentication’ and enter your desired username and password. Be sure to review the password settings. In addition, from the page General you can select the default database and language for the new login. Furthermore, you can edit user’s privileges at a more granular level from other pages like Server Rules, User Mapping, and Status. The last section of this lesson is devoted for this. More help in the MSDN documentation. Figure 2 shows the New Login dialog while adding the new SQL Server login.
  6. Click OK. Your new login is now available and ready for use.

What about ‘Mapped to certificate’ and ‘Mapped to asymmetric key’ logins? Actually, these logins cannot be created through New Login window. However, you can create it through the CREATE LOGIN statement which is covered soon. However, we would not cover these two types. Therefore, it is useful checking MSDN documentation.

What about security settings in the New Login dialog? Enforcing password policy means enforcing password rules like password complexity requirement and password length. Enforcing password expiration means that the user will be required to change his password from time to time every a specific period specified by SQL Server. In addition, you can require the user to change his password the next time he logs on to SQL Server. Notice that the three settings are related to each other. For example, disabling the enforcement of password policy disables other settings. It is worth mentioning that these settings are only available for logins specific to SQL Server only.

Creating a Login via the CREATE LOGIN T-SQL Statement

Another way to create a new login is through the CREATE LOGIN T-SQL statement. The syntax of this statement is as following:

CREATE LOGIN login_name
    { WITH  | FROM  } ::=
    WINDOWS [ WITH  [ ,... ] ]
    | CERTIFICATE certname
    | ASYMMETRIC KEY asym_key_name ::=
    PASSWORD = 'password' [ HASHED ] [ MUST_CHANGE ]
    [ ,  [ ,... ] ] ::=
    SID = sid
    | DEFAULT_DATABASE = database
    | DEFAULT_LANGUAGE = language
    | CHECK_EXPIRATION = { ON | OFF}
    | CHECK_POLICY = { ON | OFF}
    [ CREDENTIAL = credential_name ] ::=
    DEFAULT_DATABASE = database
    | DEFAULT_LANGUAGE = language

Actually this statement can be used to create a login of any type. However, because of the needs of our lesson, we will focus on how to create logins based on Windows domain accounts -and groups- and logins specific to SQL Server.

Creating a Login from a Windows Domain Account

Now we are going to create the login ‘Mohammad Elsheimy’ which is based on the user account ‘Mohammad Elsheimy’ which exists on the machine ‘BillGates-PC’. In addition, we will change the default database to Northwind and the default language to English.

CREATE LOGIN [BillGates-PCMohammad Elsheimy] FROM WINDOWS
WITH DEFAULT_DATABASE=[Northwind], DEFAULT_LANGUAGE=[English];

Actually, changing default database and default language is optional. Therefore, you can omit both or only one.

If you need to create a login of the Windows domain group change the login name to the group name.

When working with T-SQL statements, be sure to refresh the Logins node after executing your T-SQL statement to see your new baby.

If you are using SQL Server Express, of course you would not find SQL Server Management Studio to execute the commands. However, you can execute these commands via .NET which is covered soon.

Some T-SQL statements -and stored procedure- require the current login to have some privileges to execute them. If you faced a security problem executing any of the T-SQL statements found here, check the MSDN documentation for more help about the required permissions. Although, be sure to check the last section of this lesson.

Creating a Login Specific to SQL Server

Now we are going to create the login ‘My Username’ with the password ‘buzzword’. In addition, this user will have to change his password at the next logon. Moreover, password policy and expiration are turned on. Furthermore, default database is set to Northwind and default language is set to English.

CREATE LOGIN [My Username] WITH PASSWORD=N'buzzword'
MUST_CHANGE, CHECK_EXPIRATION=ON, CHECK_POLICY=ON,
DEFAULT_DATABASE=[Northwind], DEFAULT_LANGUAGE=[English];

Again, changing default database and default language is optional. In addition, explicitly setting password settings is optional too; you can omit one of them or all of them. However, if you omit the password policy enforcement setting, it is still turned on. If you want to turn it off, set it explicitly.

Creating a Login via a System Stored Procedure

You can create a new login via the system stored procedure sp_addlogin. The definition of this stored procedure is as following:

sp_addlogin [ @loginame = ] 'login'
    [ , [ @passwd = ] 'password' ]
    [ , [ @defdb = ] 'database' ]
    [ , [ @deflanguage = ] 'language' ]
    [ , [ @sid = ] sid ]
    [ , [ @encryptopt= ] 'encryption_option' ]

This stored procedure accepts the following arguments:

  • @loginname:
    The name of the login. In other words, the username.
  • @passwd:
    Optional. The password of the login. Default is NULL.
  • @defdb:
    Optional. The default database. Default is MASTER.
  • @deflanguage:
    Optional. The default language. Default is NULL which means .
  • @sid:
    Optional. Used to set a Security Identifier (SID) for the new login. If NULL, SQL Server automatically generates one. Default is NULL. Notice that if this is a Windows domain user -or group- login, this argument is automatically set to the Windows SID of this user -or group.-
  • @encryptopt:
    Optional. Default is NULL. Specifies whether the password is set as plain text or hashed. This argument can take one of three values:

    • NULL:
      Specifies that the password is set as clear (plain) text.
    • skip_ecryption:
      Specifies that the password is already hashed. Therefore, the Database Engine would store the database without hashing it.
    • skip_encryption_old:
      Specifies that the password is already hashed but with an earlier version of SQL Server. Therefore, the Database Engine would store the database with our re-hashing it. This option is used for compatibility purposes only.

This function returns 0 if succeeded or 1 otherwise.

Here is an example creates again the login ‘My Username’ that was created earlier.

EXEC sys.sp_addlogin  N'My Username', N'buzzword';

As you might expect, you will receive an error if you tried to execute the last line while a login with the same name exists.

Creating a Login via .NET

As you know, you can execute any SQL Server command through the SqlCommand object. Therefore, we are going to combine the last two approaches for creating the login with C#. We will create the login programmatically via .NET and C# through our T-SQL statements. Here is the code:

// Connecting to SQL Server default instance
// to the default database using current
// Windows user's identity.
// The default database is usually MASTER.
SqlConnection conn = new SqlConnection
    ("Data Source=;Initial Catalog=;Integrated Security=True");
// Creating a login specific to SQL Server.
SqlCommand cmd = new SqlCommand
    ("CREATE LOGIN [My Username] WITH PASSWORD=N'buzzword' " +
    "MUST_CHANGE, CHECK_EXPIRATION=ON, CHECK_POLICY=ON, " +
    "DEFAULT_DATABASE=[Northwind], DEFAULT_LANGUAGE=[English];",
    conn);
// In addition, you can use this command:
// EXEC sys.sp_addlogin  N'My Username', N'buzzword'
// Moreover, you can set the command type to stored procedure,
// set the command to sys.sp_addlogin,
// and add parameters to the command to specify the arguments.
try
{
    conn.Open();
    cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
    if (ex.Number == 15025)
        Console.WriteLine("Login already exists.");
    else
        Console.WriteLine("{0}: {1}", ex.Number, ex.Message);
}
finally
{
    cmd.Dispose();
    conn.Close();
}

Notice the numbers assigned to errors.

Using the Login to Access SQL Server

Here, we will cover the two techniques for accessing SQL Server. We will cover accessing SQL Server through its IDE (SQL Server Management Studio) and accessing SQL Server programmatically via .NET.

If you are using SQL Server Express, you can step the SQL Server Management Studio section and dive directly into .NET.

Accessing SQL Server via SQL Server Management Studio

After you start SQL Server Management Studio, you face the ‘Connect to Server’ dialog that allows you to connect to SQL Server using valid credentials (login in other words.) Figure 3 shows the ‘Connect to Server’ dialog.

Figure 3 - Connect to Server dialog
Figure 3 - Connect to Server dialog

If you cancelled this dialog, you will not be able to connect to the server. However, as you know, you can connect again through either the Object Explorer window or File->Connect Object Explorer command.

From this dialog, you can choose between two types of authentication:

  1. Windows Authentication:
    Logs on to the server with the credentials of the current user.
  2. SQL Server Authentication:
    Logs on to the server with credentials specific to SQL Server. You may provide your username as password to access SQL Server. It is worth mentioning that the administrator user ‘sa’ is also specific to SQL Server.

Accessing SQL Server via .NET

In .NET, you can access SQL Server through another login the same way as you do while accessing it via the ‘sa’ login but with changing the username and password to the new information.

The following example shows how to access SQL Server through Windows authentication.

// Connecting to SQL Server default instance
// to the default database using current
// Windows user's identity.
// The default database is usually MASTER.
SqlConnection conn = new SqlConnection
    ("Data Source=;Initial Catalog=;Integrated Security=True");

try
{
    conn.Open();
    // Connected
}
catch (SqlException ex)
{
    Console.WriteLine("{0}: {1}", ex.Number, ex.Message);
}
finally
{
    conn.Close();
}

Now, it is the time for the code that accesses SQL Server through SQL Server authentication. This code tries to log-in to SQL Server via our newly created login ‘My Username.’ You can specify your username and password via the User ID (or UID) and Password (or PWD) settings in the connection string.

// Connecting to SQL Server default instance
// to the default database using the user
// "My User" and his password "buzzword"
// The default database is usually MASTER.
SqlConnection conn = new SqlConnection
    ("Data Source=;Initial Catalog=;" +
    "User ID=My Username;Password=buzzword");
try
{
    conn.Open();
    // Connected
}
catch (SqlException ex)
{
    if (ex.Number == 18456)
        Console.WriteLine("Bad username or password.");
    else
        Console.WriteLine("{0}: {1}", ex.Number, ex.Message);
}
finally
{
    conn.Close();
}

Notice that if you created the user with MUST_CHANGE setting specified, you will not be able to access SQL Server with this user unless you change his password. Notice the error number returned.

Changing an Existing Login

While you can create a new login using SQL Server Management Studio, T-SQL statements, or stored procedures, you cannot change (alter) your login using the third way. Therefore, you have only two ways to change your new login, either using SQL Server Management Studio or using the ALTER LOGIN T-SQL statement.

Changing a Login via SQL Server Management Studio

To change a login via SQL Server Management Studio, step down to the Logins node in the Object Explorer then double-click your login to show the Login Properties dialog. This dialog is very similar (yet identical) to the New Login dialog; it is used to change the login properties. Figure 4 shows the Login Properties dialog.

Figure 4 - Login Properties dialog
Figure 4 - Login Properties dialog

Actually, if this is a Windows authentication login, you would not be able to change any information in the General tab except the default database and default language. However, you can change other characteristics in the other tabs.

If this is a SQL Server authentication login, you are allowed only to change the password besides the default database and default language. However, as with Windows authentication logins, you can change other properties in the other tabs.

Changing a Login via the ALTER LOGIN T-SQL Statement

What if you need more control over the changing process? What if you need to alter (change) other mapped logins? The answer is you can do this via the T-SQL statement ALTER LOGIN. The syntax of this statement is as following:

ALTER LOGIN login_name
    {
    
    | WITH  [ ,... ]
    }
 ::=
        ENABLE | DISABLE
 ::=
    PASSWORD = 'password'
    [
            OLD_PASSWORD = 'oldpassword'
      |  [  ]
    ]
    | DEFAULT_DATABASE = database
    | DEFAULT_LANGUAGE = language
    | NAME = login_name
    | CHECK_POLICY = { ON | OFF }
    | CHECK_EXPIRATION = { ON | OFF }
    | CREDENTIAL = credential_name
    | NO CREDENTIAL

 ::=
    MUST_CHANGE | UNLOCK

Changing the Name and Password of a Login

While you cannot change the name of a user via the Login Properties dialog, you can do this through the ALTER LOGIN statement. The following T-SQL statement changes our user ‘My Username’ to be ‘someuser’ and changes his password too to be ‘newbuzzword’.

ALTER LOGIN [My Username]
    WITH NAME = [someuser] , PASSWORD = N'newbuzzword';

As a refresher, some T-SQL statements require special permissions. If you faced a security problem executing statements found here, then you are not authorized. Check the MSDN documentation for more help about permissions required.

Again, if you do not have SQL Server Management Studio, you can use the Server Explorer in Visual Studio .NET.

Enabling/Disabling a Login

The following statement disables the login ‘someuser’ so that nobody can access it.

ALTER LOGIN [someuser] DISABLE;

To get your login back, change the DISABLE keyword to the ENABLE keyword.

Changing a Login via .NET

As we did earlier, you can use the SqlCommand object combined with a SqlConnection object to execute T-SQL statements against your database. The following code segment disables a login and tries to login to SQL Server using it.

// Log in using Windows authentication
SqlConnection conn = new SqlConnection
    ("Data Source=;Initial Catalog=;Integrated Security=True");
SqlCommand cmd =
    new SqlCommand("ALTER LOGIN [someuser] DISABLE;", conn);

try
{
    conn.Open();
    // Connected
    cmd.ExecuteNonQuery();
    // Succeeded
    conn.Close();

    // Another technique to create your connection string
    SqlConnectionStringBuilder builder =
        new SqlConnectionStringBuilder(conn.ConnectionString);
    // Use this line to remove the Windows auth keyword
    // builder.Remove("Integrated Security");
    // Or else, set Windows authentication to False
    builder.IntegratedSecurity = false;
    builder.UserID = "someuser";
    builder.Password = "newbuzzword";

    conn.ConnectionString = builder.ToString();

    // The following line would raise the error 18470
    conn.Open();
    // Connected
    conn.Close();
    // Closed
}
catch (SqlException ex)
{
    if (ex.Number == 18470)
        Console.WriteLine("Account disabled.");
    else
        Console.WriteLine("{0}: {1}",
            ex.Number, ex.Message);
}
finally
{
    cmd.Dispose();
    conn.Close();
}

Notice that new technique of building connection string; it is using the ConnectionBuilder object.

Deleting an Existing Login

Like creating a new login, deleting (dropping) an existing login can be done through a way of three:

  1. Using the SQL Server Management Studio.
  2. Using T-SQL Statements.
  3. Using System Stored Procedures.

Again, you can combine either the second or the last way with .NET.

If you are using SQL Server Express, you can skip the first way that creates the login using the SQL Server Management Studio.

Deleting a Login via SQL Server Management Studio

Form SQL Server Management Studio, step down to the logins object in the Object Explorer and select your login. From the context menu of the login, you can select Delete to delete the login.

Deleting a Login via the DROP LOGIN T-SQL Statement

To remove a login from SQL Server using a T-SQL statement, you can use the DROP LOGIN statement. The following is the syntax for this statement:

DROP LOGIN login_name

As you know, to delete the login ‘someuser’, use the following example:

DROP LOGIN [someuser];

Actually, you cannot delete a user that already logged on.

This way is used for all types of logins. Just specify the login name.

Deleting a login via a System Stored Procedure

The system stored procedure sp_droplogin is the procedure responsible for dropping an existing login. The definition of this function is as following:

sp_droplogin [ @loginame = ] 'login'

This function accepts only a single argument which is the name of the login. This is the T-SQL statement that deletes the login ‘someuser’.

EXEC sp_droplogin 'someuser';

Again and again, some T-SQL statements and procedures require special permissions. Check MSDN for details.

Deleting a Login via .NET

As we said earlier, you can execute a T-SQL statement or stored procedure in .NET via the SqlCommand and SqlConnection object. Here is the code that deletes the login ‘someuser’.

SqlConnection conn = new SqlConnection
    ("Server=.;Data Source=;UID=someuser;PWD=newbuzzword");

SqlCommand cmd = new SqlCommand
    ("DROP LOGIN [asomeuser];", conn);
// In addition, you can use this command:
// EXEC sp_droplogin 'someuser';

try
{
    conn.Open();
    cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
    if (ex.Number == 15151)
        Console.WriteLine("Login ds not exist.");
    else if (ex.Number == 15007)
        Console.WriteLine("Login already logged on.");
    else
        Console.WriteLine("{0}: {1}", ex.Number, ex.Message);
}
finally
{
    conn.Close();
}

Enumerating Existing Logins

You can enumerate existing logins through the system table server_principals. This table encapsulates SQL Server principals’ information such as logins and roles. The following query statement retrieves all data from the sys.server_principals table.

SELECT * FROM sys.server_principals
    ORDER BY type, [name];

Figure 5 shows a snapshot of the results on my SQL Server instance.

Contents of table sys.server_principals
Contents of table sys.server_principals

From the names of column names you can know what every column stores. However, server_principals encapsulates much security data that we are not interested in. For example, it encapsulates roles information that we are not interested in here. The columns ‘type’ and ‘type_desc’ both specifies data type. The ‘type’ column specifies the type while the ‘type_desc’ stores a simple description of that type.

The ‘type’ column could store several values including:

  • R:
    Specifies that the data is for a SERVER_ROLE which means that the data is for SQL Server role.
  • U:
    Specifies that the data is for a login of the type WINDOWS_LOGIN which means that the data is for a Windows domain account -based login.
  • G:
    Specifies that the data is for a login of the type WINDOWS_GROUP which means that the data is for a Windows domain group -based login. For example, a login based on the Windows domain group Administrators.
  • S:
    Specifies that the data is for a login of the type SQL_LOGIN which means that the data is for a SQL Server -specific user.
  • C:
    Specifies that the data is for a login of the type CERTIFICATE_MAPPED_LOGIN which means that the data is for a login mapped to a certificate.
  • K:
    Specifies that the data is for a login of the type ASYMMETRIC_KEY_MAPPED_LOGIN which means that the data is for a login mapped to an asymmetric key.

It is worth mentioning that the column is_disabled specifies whether the account is disabled (which equals 1,) or enabled (which equals 0.)

Worth mentioning too that the column sid specifies the SID (Security Identifier) of the login. If this is a Windows principal (user or group,) it matches Windows SID. Otherwise, it stores the SID created by SQL Server to that login (or role.)

Working with Permissions

We have faced many times permission problems. Here, we will talk about how to work with permissions and to grant or deny a user a specific permission.

You have seen many times how the user can be prevented from executing some T-SQL statements due to his privileges. You can change a user’s permission from many places including Login Properties dialog and Server Explorer dialog.

Changing User Permissions via Login Properties Dialog

Take a second look at the Properties dialog of the login. You might notice that other property pages exist such as Server Roles, User Mapping, Securables, and Status pages. Take your time playing with these settings and do not forget to check MSDN documentation.

Changing User Permissions via Server Properties dialog

Another way to change user permissions is through the Server Properties dialog. You can right-click the server and choose Properties to open the Server Properties dialog. Figure 6 shows the Server Properties dialog showing the Permissions page.

Figure 6 - Permissions page in Server Properties dialog
Figure 6 - Permissions page in Server Properties dialog

As you might think, changing the permissions done through the Permissions dialog. It is worth mentioning that all of those options can be changed through the Securable page of the Login Properties dialog. However, here you can change permissions for many logins -or roles- easily. But with Login Properties dialog, you need to change every login separately.

Notice that, from this page you can change permissions for a login -or role- explicitly. Which means that if you did not change that permission explicitly it (the login or role,) will get that permission from another membership that it belongs to. For example, if you did not specify explicitly the permission ‘Alter any login’ for the Windows user Administrator login, he will get that permission from -for instance- the Windows group Administrators login. If that login denied the permission, then the Administrator login would be denied. You can call this technique ‘Intersection’ as with Windows ACLs.

Take a time playing with the Server Properties dialog especially in the Security and Permissions pages. And be sure to have the MSDN documentation with your other hand.

References

If you want more help, it is always helpful to check the MSDN documentation. It is useful using the search feature to search for a T-SQL statement or for help on a dialog or window.

Summary

At the end of this lesson, you learned many techniques about SQL Server and .NET. You learned all the bits of logins and how to deal with them. Plus, you learned many .NET techniques that help you coding better.

Have a nice day!

Requesting Admin Approval at Application Start

Introduction

User Access Control (UAC) is a feature of Windows that can help prevent unauthorized changes to your computer. UAC does this by asking you for permission or an administrator password before performing actions that could potentially affect your computer’s operation or that change settings that affect other users.

With UAC, Administrator users, by default, don’t have administrative privileges. Every Windows process has two security tokens associated with it, one with normal user privileges and one with admin privileges. With applications that require administrative privileges, the user can change the application to run with Administrator rights. And that process called Elevation.

Therefore, when a normal user logs on to the system he assigned the standard user access security token that does not allow him to access administrator resources. On the other hand, when an administrator logs on to the system, Windows creates two security tokens for him: a standard user access token and an administrator access token. And he assigned the latter. When he tries to access a resource requires administrator privileges, he is asked for elevation. Unless he approved the elevation request, he cannot access that resource. It is worth mentioning that standard users cannot access protected resources. However, they are requested for the elevation, by entering an administrator username and password. Therefore, the administrator accesses the protected resource on behalf of the standard user.

Now, there is a question. Why I need administrator privileges? Means, what are the resources that are protected? The answer is very simple. Most operations that may affect the system or other users on the machine are access protected. For example, writing a file on the system drive requires admin approval, reading from the registry requires admin approval, and changing file association requires admin approval.

After all, in this lesson, we will learn how to request admin approval at the application start to allow the application to access protected administrator resources.

Requesting Admin Approval via a Manifest

To request the admin approval, you can need to embed a manifest with specific form to the application.

An application manifest is an XML file similar to the application configuration file but it has another construction.

To embed a manifest to the application, you will need to add it to the project and ask Visual Studio to embed it.

The Manifest Construction

The following is the manifest construction:

Download this file here.


    
    
        
            
                
            
        
    

You can also add this manifest file via the Add New Item dialog. However, VB.NET adds it automatically. But be sure to edit it.

This manifest should be named the way you name the configuration file. That means that its name should be app.manifest, so Visual Studio can treat it the right way.

This manifest is nothing more than a simple XML file with a specific construction. You cannot change any element name or a namespace. However, you can set the application required privileges through the attributes level and uiAccess of the requestedExecutionLevel element.

The level attribute specifies the security level that we need to grant the application. It can be one of three values:

  • requireAdministrator:
    Means that the application requires administrator privileges (elevation, in other words.) If this is an administrator, he will be asked for approval. If this is a standard user, he will be asked to provide an administrator’s username and password. Therefore, the administrator executes the application of behalf of the standard user.
  • highestAvailable:
    The application gets the privileges the user has but only after getting the consent from the user. Means that if the user is a standard user, the application gets standard user privileges. On the other hand, if the user is an administrator, the application gets the admin privileges but after the request for elevation.
  • asInvoker:
    The application is running with the security token of the user. Means that if the user is a standard user or an administrator, the application gets the standard user privileges without elevation, and does not request it.

While VB.NET automatically adds the manifest file, it sets requestedExecutionLevel to asInvoker.

The uiAccess option comes handy if your application requires input to a higher-privilege-level window on the desktop. For example, if your application is an onscreen keyboard. Set uiAccess to true to allow that type of input, or false otherwise.

Actually, you will not be granted the UIAccess privilege unless your application is installed in a secure location like the Program Files directory. If you need to allow all applications located in any place to be granted the UIAccess privilege, you will need to change system policy in the Local Security Policy MMC snap-in. Lean more here.

Automatically Creating the Manifest

To embed the manifest to your application, follow these steps:

  1. Add the manifest file (app.manifest) to the project.
  2. Open the Project Properties dialog.
  3. Switch to the Application tab.
  4. In the Resources section and in the Manifest field, you can choose to embed a default manifest to the application that has the asInvoker level set, to create the application without a manifest and that has the same effect as the previous option, or to choose from a list of manifest files added to the project.

Figure 1 shows how to embed the manifest file.

Figure 1. Embedding a Manifest
Figure 1. Embedding a Manifest

Trying the Example

Now, we are going to write a simple example illustrates how to request admin approval at the application how this affects the application progress.

For the example to work well, it is better not to start Visual Studio .NET with admin privileges because if you ran the application from the Visual Studio environment, it will be granted its permissions automatically. However, to see the results, run the application from its file.

Now, start a new project and add the following code to the Main() function:

static void Main()
{
    // Change the drive C to
    // the system drive
    System.IO.File.WriteAllText("C:\MyFile.txt", "Hello, World");
    Console.WriteLine("Completed");
    Console.ReadKey(true);
}

The last code tries to write a file to the system drive which is access protected and requires admin approval to allow the writing.

Now, try to run the application. Unfortunately, because you are not granted the administrator access token, the application will be failed you will be faced with System.UnauthorizedAccessException.

Again, if you started Visual Studio .NET with admin privileges, you will not see how the UAC affects the whole application. In that case, you will need to run the application from its file.

Now, add the manifest to the application and embed it and try to run the application again.

Cheers, succeeded. Now, you are faced with the admin approval message. The following figures show the two types of admin approval messages. Figure 2 shows the prompt for consent message for administrator users, while figure 3 shows the prompt for credentials message for standard users.

Figure 2. Prompt for Consent Message
Figure 2. Prompt for Consent Message
Figure 3. Prompt for Credentials Message
Figure 3. Prompt for Credentials Message

Requesting Admin Approval via the Registry

While you can easily request admin approval via a manifest file during the development process, it will not be the case if the application already deployed.

Actually, you can request an application to start with admin privileges by right-clicking the application file and choosing €œRun as Administrator€ item. However, you will need to do this every time you try to run the application.

Another way is to change the application to request admin approval every time you execute it. This is done through the compatibility options in the Properties dialog of the application file. See figure 4.

Figure 4. Compatibility Options
Figure 4. Compatibility Options

Setting this option adds the compatibility flag RUNASADMIN to the registry at SOFTWAREMicrosoftWindows NTCurrentVersionAppCompatFlagsLayers that resides in HKCU if you change current user settings or HKLM if you choose to change the settings for all users. Figure 5 shows our application item in the registry.

Figure 5. Compatibility Flags in Registry
Figure 5. Compatibility Flags in Registry

Therefore, you can register an application to run as administrator if you added the compatibility flag RUNASADMIN in the right place.

Actually, you can replace the manifest approach with this way. You make the application installer add this compatibility flag in the installation process which is -by default- runs in admin privileges mode.

The Last Word

It is worth mentioning that this does not apply to Windows Vista only, it applies to Windows 7 -and maybe later versions- also. Working with UAC is very exhausting. However, you should relax! Windows 7 fixes major UAC problems. Now, you are not required to grant the permission for such these simple operations like changing system date and time.

It is worth mentioning that it is better not to request admin approval for the whole application. It is recommended that you request admin approval for the specific operations that require it only. And this can be done through the Windows Vista SDK.

In addition, you can read more about UAC and how it affects your application flow in these articles:

Good day!

Moving a Form without the Title Bar

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Sample: Geming.Samples.FormDragging.zip

What is that?

Today, we are talking about how to move a form without its title bar.

You might have noticed that some applications with fancy UIs do not allow the user to move the window from its title bar. Honestly, some hide the overall title bar from the user. An example of these applications is Microsoft Windows Media Player -when in skin mode,- and Microsoft Windows Live Messenger. Both applications allow you to drag their windows using the client area not the title bar.

In this lesson, you will learn how to do this trick to move the form without its title bar.

At the end of this lesson, a sample application is available for download. It is a simple application with an outstanding UI illustrates how to move the form using its client area.

How?

Theoretically, you cannot drag any form without its title bar. However, we can simulate the dragging process which implies clicking with the left mouse button on the title bar and moving the cursor without releasing the left mouse button.

You can simulate this process using the SendMessage() function. This function is used to send a specific message (you can say command/order) to a specific object -specified by its handle.- This specific message can be attached with another messages (commands) to produce a new command. For example, in our lesson we will attach the message WM_NCLBUTTONDOWN with the message HTCAPTION to simulate the left mouse button clicking on the caption (title bar) of a window (form.)

Honestly, every object is a window. Every button -even the Close button- is a window, the menu item is a window, the status bar is a window, and the tooltip is another window!

The definition of SendMessage() is as following:

LRESULT SendMessage(
    HWND hWnd,
    UINT Msg,
    WPARAM wParam,
    LPARAM lParam
    );

This function takes four arguments:

  • hWnd:
    The handle of the object (window.) to send the message to. Can be set to a window handle, HWND_DESKTOP (to send the message to the desktop,) HWND_BROADCAST (to send the message to all windows.)
  • Msg:
    The primary message that will be sent.
  • wParam:
    A secondary message to be attached to the primary message. Set to 0 to indicate NULL.
  • lParam:
    Another message that can be attached to the primary message. Set to 0 to indicate NULL. If wParam was not set, you cannot set lParam.

The return value of this function depends on the message sent. In our example, the function may return 0 if succeeded, or non-zero if failed.

It is worth mentioning that, in our example, another function must be called before SendMessage(); it is the ReleaseCapture() function. This function releases the mouse capture from a window (object) and restores the normal mouse processing. A window (object) that has captured the mouse receives all mouse input. Therefore, calling the ReleaseCapture() allows our form to release this mouse input (left-clicking) simulated.

The ReleaseCapture() function is very simple; its definition is as following:

BOOL ReleaseCapture(VOID);

This function returns TRUE if succeeded, or FALSE otherwise.

Let’s Code!

Now, we are going to put things together and mix them up.

The first step is to hide the title bar of the form. This can be done through the FormBorderStyle property of the form. You can set this property to FormBorderStyle.None to hide the toolbar and borders of the form.

The next step to take is to create the PInvoke methods for the functions. Here is the full code:

    // C# Code

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.I4)]
static extern int SendMessage(
    IntPtr hWnd,
    [param: MarshalAs(UnmanagedType.U4)]
    uint Msg,
    [param: MarshalAs(UnmanagedType.U4)]
    uint wParam,
    [param: MarshalAs(UnmanagedType.I4)]
    int lParam);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool ReleaseCapture();

const uint WM_NCLBUTTONDOWN = 0xA1; // 161
const uint HTCAPTION = 2;
' VB.NET
Declare Function SendMessage Lib "user32.dll" ( _
    ByVal hWnd As IntPtr, _
    ByVal Msg As Integer, _
    ByVal wParam As Integer, _
    ByVal lParam As Integer) As Integer

Declare Auto Function ReleaseCapture _
    Lib "user32.dll" () As Boolean

Const WM_NCLBUTTONDOWN As Integer = 161
Const HTCAPTION As Integer = 2

Again and again, PInvoke stands for Platform Invocation; it is the CLR service allows .NET to call unmanaged code. This service requires special changes to the PInvoke method. Also, specific rules applied when PInvoking an unmanaged function.

The last code demonstrates the PInvoke methods for the functions, and the constants required.

The last step is to add the implementation code required to the MouseDown event of any control that you wish to allow the user to drag the form from. For instance, you can add the code to the MouseDown event of a PictureBox control that will act as the new and fancy title bar. In addition, you can add the code to the form’s MouseDown event to allow the user to drag the form from any point of its client area.

The following code demonstrates how to allow the user to drag the form from its client area:

    // Code

private void MainForm_MouseDown
    (object sender, MouseEventArgs e)
{
    // Releasing the mouse capture
    // to allow the form to receive
    // the order
    ReleaseCapture();
    // Ordering the form
    // Simulating left mouse button clicking
    // on the title bar
    SendMessage(this.Handle, // Form handle
        WM_NCLBUTTONDOWN, // Simulating the click
        HTCAPTION, // Attaching it to the title bar
        0); // No further options required
}
' VB.NET
Private Sub Form1_Load(ByVal sender As Object,ByVal e As EventArgs) _
    Handles MyBase.Load
    ReleaseCapture()
    SendMessage(Me.Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0)
End Sub

It is better to check the return value of every call to determine whether the operation succeeded or failed.

A problem occurred!

It is wonderful to allow the user to drag the form from its client area. But, what if the user tried to drag the form from a label on the client area? It will not be dragged.

To overcome this situation, you can add the same code to the MouseDown event of the label. In this case, for better code maintenance and to avoid code repetition, you can define a method that contains the code, and call it from the MouseDown event of every control that you need to allow the user to drag the form from such as a label or a PictureBox. Another solution is to create a single MouseDown event handler for all controls that you are interested in.

Well! What’s next?

You can use this technique when creating applications with hot skins to allow the user to drag the form from its client area or from a specific control like a PictureBox that acts as the new hot title bar.

It is worth mentioning that you would better follow the guidelines when interoperating with unmanaged code. For example, PInvoke methods and constants should be declared inside an internal class called -in our example- SafeNativeMethods. In addition, it is better creating a wrapper method for the PInvoke methods. For example, instead of calling many functions to drag the form, you can create a single function named -for instance- MoveForm() that acts as a wrapper for the PInvoke methods. And that results in code that is more readable and easier to maintain. Plus, it prevents code repetition.

For more information about the functions, consult the MSDN documentation:

WOW! A code sample!

This is a very simple application that illustrates moving a form using its client area.

This sample created using Microsoft Visual Studio 2008 and .NET Framework 2.0.

The following is a snapshot from the application:

Moving Form without Title Bar Sample Snapshot

Download Here

Changing Display Settings Programmatically

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Code: Geming.DisplayMgr.msi

Introduction

Previously, we have talked about how to change screen resolution and color system via DirectX. Today, we are talking about how to change all display settings -not the resolution and color system only- via API. We will change screen resolution (bounds,) color system (bit count,) rotation (orientation,) and refresh rate (frequency) via API with C# and the .NET Framework.

Overview

This lesson firstly discusses the required functions and structures. Then, it focuses on how to retrieve current display settings. After that, it discusses how to get all modes supported by your display. As you already know, a mode is a combination of may display settings including bounds, bit count, orientation, and frequency; therefore, we will refer to display settings as display mode.

Finally, this lesson discusses how to change the current display settings. Along with the discussion, you will learn additional techniques like how to PInvoke Win32 API functions, and to marshal unmanaged data types.

In addition, this lesson comes with a sample application used for changing the display settings.

Now, we are going to discuss the required functions and structure and how to use them. After that, we will focus on the implementation code. Get ready.

EnumDisplaySettings() Function

This function resides in user32.dll. It is used to retrieve one of the modes supported by a graphics device.

The definition of this function is as following:

BOOL EnumDisplaySettings(
    LPCTSTR lpszDeviceName,  // display device
    DWORD iModeNum,          // graphics mode
    [In, Out] LPDEVMODE lpDevMode      // graphics mode settings
    );

This function accepts only three parameters:

  • lpszDeviceName:
    Specifies the display device name that will be used to retrieve its modes. This parameter can be either NULL to indicate the default device, or the name of the display device. You can enumerate display devices using the EnumDisplayDevices() function.
  • iModeNum:
    Specifies the type of information to retrieve. It could be either a mode index or one of these values:

    • ENUM_CURRENT_SETTINGS = -1
      Retrieves current display mode.
    • ENUM_REGISTRY_SETTINGS = -2
      Retrieves current display mode stored on the registry.
  • lpDevMode:
    A reference (In/Out) parameter represents the DEVMODE object encapsulates the retrieved display mode information. The DEVMODE’s dmSize member is used for input to represents the structure size, while other members are used for output.

As you might expect, to retrieve the current mode (settings) of the current display device, you will need to pass a NULL value as the lpszDeviceName parameter to indicate the current display, and the value -1 to the iModeNum parameter to indicate the current mode.

Unfortunately, EnumDisplaySettings() can return only one mode per call, and that mode is encapsulated into the DEVMODE object. To retrieve all modes (or few) supported by a display device, you need to call EnumDisplaySettings() many times specifying iModeNum as the mode index. Mode indexes start from zero. Therefore, to retrieve all modes, you will need to call the EnumDisplaySettings() function many times specifying 0 for iModeNum on the first time, and increment that index every call until EnumDisplaySettings() returns FALSE, which indicates that the previous mode was the last mode supported.

If you want to retrieve a mode (or all modes) supported by other display device, you will need to change the lpszDeviceName to the name of that device. You can get a list of all devices connected using the EnumDisplayDevices() function.

Now, it is the time for the PInvoke method. We can PInvoke this function in C# as following:

[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern Boolean EnumDisplaySettings(
    [param: MarshalAs(UnmanagedType.LPTStr)]
    string lpszDeviceName,
    [param: MarshalAs(UnmanagedType.U4)]
    int iModeNum,
    [In, Out]
    ref DEVMODE lpDevMode);

What is Platform Invocation (PInvoke)? You already know, there is no such compatibility between managed code (.NET) and unmanaged code (Win32 API in our case.) Therefore, they cannot call each other directly. Rather, you make use of the PInvoke service to call unmanaged functions from the managed environment.

What is Marshaling? Marshaling is another service of the CLR. Again, there is no such compatibility between managed code and unmanaged code. Therefore, they cannot communicate directly. To send data between the managed client and unmanaged server, and vice versa, you will need to use marshaling to allow sending and receiving of the data. Marshaling converts managed data types to unmanaged data and vice versa.

As you suggested, now we are going to talk about the DEVMODE structure.

DEVMODE Structure

This structure encapsulates information about a printer or a display device.

This structure is fairly a complex structure, but we will try to break it down to be simple and easier to marshal.

The definition of this structure is as following:

typedef struct _devicemode {
  TCHAR dmDeviceName[CCHDEVICENAME];
  WORD  dmSpecVersion;
  WORD  dmDriverVersion;
  WORD  dmSize;
  WORD  dmDriverExtra;
  DWORD dmFields;
  union {
    struct {
      short dmOrientation;
      short dmPaperSize;
      short dmPaperLength;
      short dmPaperWidth;
      short dmScale;
      short dmCopies;
      short dmDefaultSource;
      short dmPrintQuality;
    } ;
    struct {
      POINTL dmPosition;
      DWORD  dmDisplayOrientation;
      DWORD  dmDisplayFixedOutput;
    } ;
  } ;
  short dmColor;
  short dmDuplex;
  short dmYResolution;
  short dmTTOption;
  short dmCollate;
  TCHAR dmFormName[CCHFORMNAME];
  WORD  dmLogPixels;
  DWORD dmBitsPerPel;
  DWORD dmPelsWidth;
  DWORD dmPelsHeight;
  union {
    DWORD dmDisplayFlags;
    DWORD dmNup;
  } ;
  DWORD dmDisplayFrequency;
#if (WINVER &gt;= 0x0400)
  DWORD dmICMMethod;
  DWORD dmICMIntent;
  DWORD dmMediaType;
  DWORD dmDitherType;
  DWORD dmReserved1;
  DWORD dmReserved2;
#if (WINVER &gt;= 0x0500) || (_WIN32_WINNT &gt;= 0x0400)
  DWORD dmPanningWidth;
  DWORD dmPanningHeight;
#endif
#endif
} DEVMODE, *PDEVMODE, *LPDEVMODE

Really complex, Isn’t it? Yeah, DEVMODE is one of the large and complex structures.

You might have noticed that two unions defined inside the structure. In addition, a structure is defined inside the first union. Notice that this structure is only available if it is a printer device. Plus, the union defined the structure also is for printer devices only. Therefore, for display devices, you can omit the structure, and define other members of the union sequentially, no additional work is required.

In addition, the last eight members are not supported by Windows NT, while the last two members are not supported by Windows ME and its ascendants. To solve this dilemma and support all versions, you can define three versions of the structure, one for Windows ME and its ascendants, one for Windows NT, and the last for Windows 2000 and higher versions. In addition, you will need to create three overloads of the function for the three structures. For simplicity, we will marshal the whole structure as for Windows 2000 and higher versions.

Notice that there are arrays that are defined with the length CCHFORMNAME which equals 32.

Last but not least, the second union of the structure defined two members inside, dmDisplayFlags and dmNup. For simplicity, we will take away the union and one of its members and define the other. Because both members are 4-bytes wide, we can omit anyone of them.

We can marshal that structure in C# as following:

    [StructLayout(LayoutKind.Sequential,
CharSet = CharSet.Ansi)]
public struct DEVMODE
{
    // You can define the following constant
    // but OUTSIDE the structure because you know
    // that size and layout of the structure
    // is very important
    // CCHDEVICENAME = 32 = 0x50
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmDeviceName;
    // In addition you can define the last character array
    // as following:
    //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    //public Char[] dmDeviceName;

    // After the 32-bytes array
    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmSpecVersion;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmDriverVersion;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmSize;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmDriverExtra;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmFields;

    public POINTL dmPosition;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayOrientation;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayFixedOutput;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmColor;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmDuplex;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmYResolution;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmTTOption;

    [MarshalAs(UnmanagedType.I2)]
    public Int16 dmCollate;

    // CCHDEVICENAME = 32 = 0x50
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string dmFormName;
    // Also can be defined as
    //[MarshalAs(UnmanagedType.ByValArray,
    //    SizeConst = 32, ArraySubType = UnmanagedType.U1)]
    //public Byte[] dmFormName;

    [MarshalAs(UnmanagedType.U2)]
    public UInt16 dmLogPixels;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmBitsPerPel;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPelsWidth;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPelsHeight;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayFlags;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDisplayFrequency;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmICMMethod;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmICMIntent;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmMediaType;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmDitherType;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmReserved1;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmReserved2;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPanningWidth;

    [MarshalAs(UnmanagedType.U4)]
    public UInt32 dmPanningHeight;
}

We will cover the PONTL structure soon.

Actually, these dozens of MarshalAsAttribute attributes are not all required. Honestly, it is not required for marshaling DWORD into UInt32 because they are counterparts. On the hand, MarshalAsAttribute attribute must be applied to arrays.

From all of those members, we are interested only in a few:

  • dmPelsWidth and dmPelsHeight:
    Represents the bounds (width and height) of the display. These values can be used also to determine whether the display orientation is portrait or landscape.
  • dmBitsPerPel:
    Represents the bit count (color system) of the display.
  • dmDisplayOrientation:
    Represents the orientation (rotation) of the display. This member can be one of these values:

    • DMDO_DEFAULT = 0
      The display is in the natural orientation. It is the default.
    • DMDO_90 = 1
      The display is rotated 90 degrees (measured clockwise) from DMDO_DEFAULT.
    • DMDO_180 = 2
      The display is rotated 180 degrees (measured clockwise) from DMDO_DEFAULT.
    • DMDO_270 = 3
      The display is rotated 270 degrees (measured clockwise) from DMDO_DEFAULT.
  • dmDisplayFrequency:
    Represents the frequency (refresh rate) of the display.

POINTL Structure

The DEVMODE’s dmPosition member represents the location that display device in reference to the desktop area. It is always located at (0, 0). This member is of the structure POINTL which represents the coordinates (x and y) of a point. As you might expect, this structure is very simple. It is defined as following:

typedef struct POINTL {
    LONG x;
    LONG y;
};

We can marshal this structure easily as following:

    [StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
    [MarshalAs(UnmanagedType.I4)]
    public int x;
    [MarshalAs(UnmanagedType.I4)]
    public int y;
}

However, for code clarity, we have a workaround. You can omit the POINTL structure and replace the dmPosition member with two members, you can call them dmPositionX and dmPositionY, and that will work fine because you know that the size and layout (position of members) of structures is very important. And doing that will not break this rule.

ChangeDisplaySettings() Function

This function resides in user32.dll. It is used to change display settings to the mode specified, but only if the mode is valid.

The definition of this function is as following:

LONG ChangeDisplaySettings(
    LPDEVMODE lpDevMode,  // graphics mode
    DWORD dwflags         // graphics mode options
    );

This function accepts only two arguments:

  • lpDevMode:
    A reference (In/Out) argument of the type DEVMODE represents the new settings (mode) that will be applied to the display device. After retrieving the current settings using the EnumDisplaySettings() function, you can change the desired members of the DEVMODE object and use this function to change the display device to the new settings. Again, this argument is In/Out argument which means that it is used for input and output. DEVMODE’s dmSize member is used for input and other members are used for output.
  • dwflags:
    Indicates how the mode should be changed. Actually, in this example, we are not interested in this argument, so we will set it to zero. If you want more help on this argument, consult the MSDN documentation.

The return value of this function varies based on the success or failure of the settings change. This function can return one of several values including:

  • DISP_CHANGE_SUCCESSFUL = 0
    Indicates that the function succeeded.
  • DISP_CHANGE_BADMODE = -2
    The graphics mode is not supported.
  • DISP_CHANGE_FAILED = -1
    The display driver failed the specified graphics mode.
  • DISP_CHANGE_RESTART = 1
    The computer must be restarted for the graphics mode to work.

Consult MSDN documentation to know more about the ChangeDisplaySettings() return value. The last section of this lesson is devoted for this.

Another point of interest is that ChangeDisplaySettings() changes only the default display. If you want to change another display device, you can use the ChangeDisplaySettingsEx() function. It is very similar to ChangeDisplaySettings(). Consult MSDN documentation for more help.

Now, it is the time for creating the PInvoke method for the ChangeDisplaySettings() function.

    [DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.I4)]
public static extern int ChangeDisplaySettings(
    [In, Out]
    ref DEVMODE lpDevMode,
    [param: MarshalAs(UnmanagedType.U4)]
    uint dwflags);

Now, we are going to mix things together and talk about the implementation code. Get ready.

Retrieving Current Display Mode

The code that obtains the current display settings is very easy. We use the EnumDisplaySettings() function passing it ENUM_CURRENT_SETTINGS (-1) in the iModeNum parameter to get the current settings, and NULL in the lpszDeviceName parameter to indicate the current display device.

Here is the code.

Code abbreviated for clarity.

    public static void GetCurrentSettings()
{
    DEVMODE mode = new DEVMODE();
    mode.dmSize = (ushort)Marshal.SizeOf(mode);

    if (EnumDisplaySettings(null,
        ENUM_CURRENT_SETTINGS,
        ref mode) == true) // Succeeded
    {
        Console.WriteLine("Current Mode:nt" +
            "{0} by {1}, " +
            "{2} bit, " +
            "{3} degrees, " +
            "{4} hertz",
            mode.dmPelsWidth,
            mode.dmPelsHeight,
            mode.dmBitsPerPel,
            mode.dmDisplayOrientation * 90,
            mode.dmDisplayFrequency);
    }
}

Enumerating Supported Display Modes

As a refresher, to get the current mode or even another supported mode of the display device, you make use of the EnumDisplaySettings() function. If you pass ENUM_CURRENT_SETTINGS (-1) in the iModeNum parameter, you get the current mode. On the other hand, you can enumerate through the list of supported modes by passing the mode index in this parameter. We start by 0 which indicates the first mode, and increment it every call to enumerate through the list of the supported modes. If the function returns FALSE, that means that the mode with the index specified is not found. Therefore, the previous mode was the last one. Here is the code.

public static void EnumerateSupportedModes()
{
    DEVMODE mode = new DEVMODE();
    mode.dmSize = (ushort)Marshal.SizeOf(mode);

    int modeIndex = 0; // 0 = The first mode

    Console.WriteLine("Supported Modes:");

    while (EnumDisplaySettings(null,
        modeIndex,
        ref mode) == true) // Mode found
    {
        Console.WriteLine("t" +
            "{0} by {1}, " +
            "{2} bit, " +
            "{3} degrees, " +
            "{4} hertz",
            mode.dmPelsWidth,
            mode.dmPelsHeight,
            mode.dmBitsPerPel,
            mode.dmDisplayOrientation * 90,
            mode.dmDisplayFrequency);

        modeIndex++; // The next mode
    }
}

Changing Display Mode

Now, we are going to change the current display settings. This can be done through the ChangeDispalySettings() function.

Changing Screen Resolution and Bit Count

The following code example loads the current settings and changes only the resolution and the bit count. Actually, you are free to change all settings or few of them that is up to you. However, for the sake of simplicity, we are going to change the screen resolution and bit count in this section, and the orientation in the next section.

static void Main()
{
    // Changing the display resolution
    // to 800 by 600
    // and the color system (bit count)
    // to 16-bit
    ChangeDisplaySettings(800, 600, 16);
}

public static void ChangeDisplaySettings
    (int width, int height, int bitCount)
{
    DEVMODE originalMode = new DEVMODE();
    originalMode.dmSize =
        (ushort)Marshal.SizeOf(originalMode);

    // Retrieving current settings
    // to edit them
    EnumDisplaySettings(null,
        ENUM_CURRENT_SETTINGS,
        ref originalMode);

    // Making a copy of the current settings
    // to allow reseting to the original mode
    DEVMODE newMode = originalMode;

    // Changing the settings
    newMode.dmPelsWidth = (uint)width;
    newMode.dmPelsHeight = (uint)height;
    newMode.dmBitsPerPel = (uint)bitCount;

    // Capturing the operation result
    int result =
        ChangeDisplaySettings(ref newMode, 0);

    if (result == DISP_CHANGE_SUCCESSFUL)
    {
        Console.WriteLine("Succeeded.n");

        // Inspecting the new mode
        GetCurrentSettings();

        Console.WriteLine();

        // Waiting for seeing the results
        Console.ReadKey(true);

        ChangeDisplaySettings(ref originalMode, 0);
    }
    else if (result == DISP_CHANGE_BADMODE)
        Console.WriteLine("Mode not supported.");
    else if (result == DISP_CHANGE_RESTART)
        Console.WriteLine("Restart required.");
    else
        Console.WriteLine("Failed. Error code = {0}", result);
}

Changing Screen Orientation

Now we are going to change the screen orientation clockwise and anti-clockwise.

static void Main()
{
    // 0 degrees ( DMDO_DEFAULT = 0 )

    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 90 degrees (	DMDO_90 = 1 )
    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 180 degrees ( DMDO_180 = 2 )
    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 270 degrees ( DMDO_270 = 3 )
    Console.WriteLine
        ("Press any key to rotate the screen . . .");
    Console.ReadKey(true);
    Console.WriteLine();

    RotateScreen(true); // 0 degrees ( DMDO_DEFAULT = 0 )
}

public static void RotateScreen(bool clockwise)
{
    // Retrieving current settings
    // ...

    // Rotating the screen
    if (clockwise)
        if (newMode.dmDisplayOrientation  DMDO_DEFAULT)
            newMode.dmDisplayOrientation--;
        else
            newMode.dmDisplayOrientation = DMDO_270;

    // Swapping width and height;
    uint temp = newMode.dmPelsWidth;
    newMode.dmPelsWidth = newMode.dmPelsHeight;
    newMode.dmPelsHeight = temp;

    // Capturing the operation result
    // ...
}

Sample Application

The code sample is a simple application used to change display settings and to rotate the screen.

This is a snapshot of the application:

Display Settings Sample Snashot

Download Here

References

It is pleasure receiving your feedbacks and comments.

Programmatically Turning on the Screen Saver

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Overview

This lesson focuses on how to programmatically turn on the screen saver.

Background

In Windows, you can turn it on automatically by leaving the machine inactive for a specific period. You can control this period from the Screen Saver options from the desktop properties dialog. The following figure shows the Screen Saver Settings dialog.

Screen Saver Settings

Programmatically turning on the screen saver

In this section we will learn how to turn on the screen saver in .NET and C#. Of course you can write the code in any language you prefer, but here we will write it in C#.

You can turn on the screen saver by sending the WM_SYSCOMMAND message with the parameter SC_SCREENSAVE.

Sending a message can be done using the SendMessage() function that resides in the User32.dll library.

The definition of this function is as follows:

LRESULT SendMessage(
    HWND hWnd,
    UINT Msg
    WPARAM wParam,
    LPARAM lParam
    );

This function takes four arguments:

  • hWnd:
    Handle to the window to send the message to. You can set this argument to a window handle, the desktop handle (HWND_DESKTOP), or the handle for all top-level windows (HWND_BROADCAST).
  • Msg:
    The message to send.
  • wParam:
    Additional message-specific options.
  • lParam:
    Additional message-specific options.

This function returns a value specific to the message sent. Usually, it returns non-zero if it succeed or zero otherwise.

Here is the full code:

// C# Code

[DllImport("User32.dll")]
static extern int SendMessage
    (IntPtr hWnd,
    uint Msg,
    uint wParam,
    uint lParam);

const uint WM_SYSCOMMAND = 0x112;
const uint SC_SCREENSAVE = 0xF140;
const uint HWND_BROADCAST = 0xFFFF;

static void Main()
{
    SendMessage(
    new IntPtr((int)HWND_BROADCAST),
    WM_SYSCOMMAND,
    SC_SCREENSAVE,
    0);
}
' VB.NET Code

Declare Auto Function SendMessage Lib "user32.dll" _
    (ByVal hWnd As IntPtr, _
    ByVal Msg As UInt32, _
    ByVal wParam As UInt32, _
    ByVal lParam As UInt32) As Int32

Const WM_SYSCOMMAND As UInt32 = &amp;h212
Const SC_SCREENSAVE As UInt32 = &amp;HF140
Const HWND_BROADCAST As UInt32 = &amp;HFFFF

Sub Main()
    SendMessage( _
        New IntPtr(CInt(HWND_BROADCAST)), _
        WM_SYSCOMMAND, _
        SC_SCREENSAVE, _
        0)
End Sub

Code explanation

First, we created our PInvoke method. This method is decorated by the DllImportAttribute attribute specifying the library which the method resides in. Also PInvoke methods must be declared as “static” and “extern”.

Because LRESULT defined as a signed 32-bit integer, it is marshaled as System.Int32 in .NET. Also, because of System.IntPtr is the best type for marshaling any Win32 raw handle, we have used it for the first argument. UINT, WPARAM, AND LPARAM are all defined as an unsigned 32-bit integer, so we have marshaled them as System.UInt32. HWND_BROADCAST represents the handle for all top-level windows, so we have sent them the order to turn on the screen saver.

PInvoke stands for Platform Invocation, it is the process of creating a wrapper for the .NET to interact with unmanaged functions.

Marshaling is the process of creating a bridge between .NET types and unmanaged types.

You can use PostMessage() in place of SendMessage() if you want to send the message asynchronously and don’t want to wait for a response.

Read more about PInvoking and Marshaling in other API lessons.