Professional Documents
Culture Documents
If you are a C++ or a Java programmer you would find lot of things similar when you take a first look at C# code. However, apart from the initial similarity you will find C# a lot easier than C++ and Java. It offers simplicity of Visual Basic, power of C++ and platform independence of Java, all bundled into one language. The highlighting features of C# are as follows: a. b. c. d. e. Full support for object-oriented programming In-built support for automatic generation of XML documentation. Automatic cleanup of dynamically created memory. Access to .Net class library as well as Windows API. Can be used to create a ASP.Net dynamic web pages.
Most of these features are available on VB.Net as well as VC++.Net. However, since C# is designed from the start to work with .Net, it uses .Net features with ease and efficiency that would be found wanting in VB.Net and VC++.Net. C# has been developed by a team led by Anders Hejlsberg who was also the leader of the J++ team. Hence you will find the design and syntax of C# much similar to Java. However, as of now Java has one strong advantage over C#-platform independence. The same Java code can be executed on any platform that has a Java Runtime (JVM) implementation. Since JVM's are already in existence for most major platforms Java is truly portable today. Same is not true about C#-at least not as of now. In contrast, C# has two advantages over Java. These are as under: a. C# supports operator overloading. If required C# programs can use pointers by enclosing them within 'unsafe' blocks. b. C# can interoperate with code written in other .Net languages. Without much ado lets get on with C# programming. Here we go The First C# Program All that you need to program in C# is Microsoft VisualStudio.Net Beta 2, .Net SDK Beta 2. (These you can either download from msdn.microsoft.com or you can get it along with your MSDN subscription.) You need to install it on a machine running under Windows 98, Windows 2000 or Windows XP. namespace Simple { using System ; class Class1 { static void Main ( string[ ] args ) { Console.WriteLine ( "Hello C#" ) ; } } } Before we understand how the program works, let us first see the steps involved in creating it.
Compiled by rmshankar@yahoo.com
c. From the New Project dialog box select project type as Visual C# Projects. d. Select Console Application from the list of Templates. e. Select a location (directory/folder) where this project should get saved. Give name to the project as Simple. Click on OK button. f. A Class1.cs file would get created. This file would contain skeleton program. The VisualStudio.Net environment automatically creates this program. It contains a class called Class1 containing the function Main( ) . g. Add the following line to the skeleton code. Console.WriteLine ( "Hello C#" ) ; h. To compile and execute the program use Ctrl + F5. On execution the message "Hello C#" would be displayed on the screen. Now a few useful tips about the program a. C# is a pure object oriented language. It doesn't allow global variables or functions. All variables and functions should be defined inside a class. b. All C# programs start from Main( ). Since Main( ) cannot be global it is enclosed in a class called Class1. void before the word Main specifies that Main( ) does not return anything. The static modifier used with Main( ) indicates that it can be called without creating an object of the class Class1. c. string is a data type used to store strings. string[ ] represents an array of strings. Thus args is an array of strings. It stores the command line parameters, if specified by the user while executing the program. d. To display anything on the screen we need to call the WriteLine( ) function. To this function we can pass strings, integers, floats, etc. Since the WriteLine( ) function belongs to the Console class we have to call it using Console.WriteLine( ). A function within the class can be accessed using the '.' Operator. Console class is used to perform input from keyboard and output to screen. e. In C#, namespaces provide a way to group classes. Console class belongs to the System namespace. Hence to be able to use the Console class we need to import it from the System namespace. This has been done through the using System statement. The way the Console class has been enclosed within the System namespace, likewise
Compiled by rmshankar@yahoo.com
f.
Let us now write another program that would show how to receive input from the keyboard. Here it is namespace Simple { using System ; class Class1 { static void Main ( string[ ] args ) { string s ; s = Console.ReadLine( ) ; Console.WriteLine ( s ) ; } } } To receive input from the keyboard we have used the ReadLine( ) function. This function returns a string. This function is also a static member function of the Console class, hence we have called it using Console.ReadLine( ). Note that C# does not have its own class library. It uses the class library provided by the .Net Framework. The .Net Framework provides the class library in the form of .Net Base Classes. Thus Console is a .Net base class. This class can be used by any other .Net-aware language. Command-line Arguments Instead of receiving input from keyboard we may want to supply input to it in the form of command-line arguments. Following program shows how to receive these arguments and print them out. using System; namespace cmdline { class Class1 { static void Main ( string[ ] args ) { foreach ( string str in args ) { Console.WriteLine ( str ) ; } } } }
Compiled by rmshankar@yahoo.com
Let us now understand the objective of creating two classes for file operations. The static functions of the File class can be called to perform various file operations without creating an object. This avoids the overhead of instantiating objects. As against this, to call the member functions of the FileInfo class it is necessary to create an object. This is because FileInfo class contains non-static member functions. So if we wish to carry out a single operation on the file we can use the File class, avoiding the object creation overheads thereby. On the other hand if we wish to carry out multiple operations on the file (with the preservation of state of the object) we can use the FileInfo class. When we create a FileInfo object all the relevant information like size, attributes, authentication permissions are read in through the constructor. This information is then shared by other functions while carrying out multiple operations. If we use the File class for carrying our multiple operations then this information will have to be read in each time we perform a new operation. Also, at times we are required to pass the file information to another application. In such a case it is necessary to create a FileInfo object and then pass its state to other application (this process is known as marshalling). Marshalling of object is possible only if the class in derived from the MarshalByRefObject class. Since the object of the File class cannot be created it has not been inherited from MarshalByRefObject class. Reading And Writing To A Text File
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
We have taken the first few toddling steps in C#. Imbibe the matter presented here. We would take a peek below the hood of C# and explore its internal working next time.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Each menu item is governed by a control variable of the type MenuItem. We can change the names of these variables through the 'Properties' window. For the program that follows we have used the names as filemenu that will hold the other menu items, newmenu, openmenu, savemenu, generatemenu and exitmenu. Let us now decide what should happen when these menu items are selected. When we select the 'Generate' menu item, shapes like rectangle, ellipse and line should get generated at random and in random colors. On selecting the 'Save' menu item these shapes should be saved in a file. We must be able to load this file and display the shapes again. This would be achieved through the 'Open' menu item. When we click the 'New' menu item the earlier shapes should vanish and we must get a new form to draw new shapes. While saving the shapes we should not save the image of the shape. Instead we should save the relevant information of the shape using which we should be able to regenerate the shape again when the file is loaded. This means we must write the object onto the disk while saving it and load it back while opening the file. This process of writing the state of an object is called serialization and reading it back is called deserialization. To make all these activities to happen we need to add handlers for these menu items. The Windows Forms programming model is event based. When we click on a menu item it raises an event. In order to handle an event, our application should register an event-handling method. For adding these handlers click on the menu item for which we wish to add the handler. Then go to the 'Properties' window and select the 'Events' tab (shown by a yellow lightening icon). From the list of events select 'Click'. As a result an event handler called say, openmenu_Click( ) would get added to our code. On similar lines rest of the handlers can be added. All these handlers will get added to the Form1 class, which is the default class name. Before we add code to these menu handlers let us insert four new classes. The first amongst these is an abstract class called shapes. In this class we will store the color of the shape in variables r, g, b, representing red, green and blue components of the color. The other three classes that we would add are line, rectangle and ellipse. These classes are derived from the shapes class. In these classes we will store the coordinates of the shapes. Each of these three classes would have a constructor to initialize the data members. Each class would have a function draw( ) which would contain the logic to draw the respective shape. This function would be declared as abstract in the base class shapes. To make all the classes capable of carrying
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
st.Close ( ) ; } } private void generatemenu_Click ( object sender, System.EventArgs e ) { Size sz = ClientSize ; Random rd = new Random( ) ; for ( int i = 0 ; i < 10 ; i++ ) { int shapeno = rd.Next ( 3 ) ; int x1 = rd.Next ( sz.Width ) ; int y1 = rd.Next ( sz.Height ) ; int x2 = rd.Next ( sz.Height - y1 ) ; int y2 = rd.Next ( sz.Width - x1 ) ; switch ( shapeno ) { case 0: s.Add ( new line ( x1, y1, x2, y2 ) ) ; break ; case 1: s.Add ( new rectangle ( x1, y1, x2, y2 ) ) ; break ; case 2: s.Add ( new ellipse ( x1, y1, x2, y2 ) ) ; break ; } } Invalidate( ) ; } private void exitmenu_Click ( object sender, System.EventArgs e ) { Dispose( ) ; } private void Form1_Paint ( object sender, System.Windows.Forms.PaintEventArgs e ) { Graphics g = e.Graphics ; foreach ( shapes ss in s ) ss.draw ( g ) ; } private void newmenu_Click ( object sender, System.EventArgs e ) { s.Clear( ) ; Invalidate( ) ; } } }
Compiled by rmshankar@yahoo.com
If we wish to save the file we can click on 'Save' menu item. When we do so savemenu_Click( ) gets called. We have created an object of the SaveFileDialog class and used a "*.dat" filter for it. When we type in a file name and click Ok, a FileInfo object gets created with the selected name. The Open( ) function returns a Stream object associated with the file. We have collected it in a Stream reference. We have used the BinaryFormatter object to serialize the objects. The BinaryFormatter serializes and deserializes an object, in binary format. We have added a BinaryFormatter object b to our class. The Serialize( ) method of this class serializes the object to the given stream. After serializing all the elements of the array we have closed the stream using the Close( ) method. When we click 'Open' menu item an OpenFileDialog is popped with the appropriate filter. Here also we have created a FileInfo object and collected the corresponding Stream of the specified file. Next we have used a while loop to deserialize the objects until the end of stream is reached. The Deserialize( ) method deserializes the specified stream into an object. We have collected
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The earliest form of reuse was in the form of Static Libraries. These libraries contained object code of functions. During linking the object code of the library functions (usually stored in .Lib file(s)) was linked with the object code of the program calling those functions to form an executable file. The linking phase used to precede execution. This way the library functions could be reused by different applications calling them. This however led to wastage of storage space as the object code from the function library used to get replicated into every application using it. This is shown in Figure 1.
Figure 1 In multitasking environments if two applications are running in memory each calling the same library function then two copies of the same function would be running in two different processes. This led to wastage of precious memory space. Also if a bug was found in the library functions the library as well as the client program using it had to be re-compiled and re-distributed. A recipe for disaster for sure! To avoid the wastage of memory and disk space Microsoft suggested the concept of Dynamically Linked Libraries (DLLs). Functions from these libraries never became part of an application trying to call them. Instead they used to get linked with the applications calling them at run-time. Moreover, multiple applications calling them used to share the same copy of the library function present in memory. A developer could simply place the DLL in Windows directory, Windows\System directory or in the same directory as the EXE file using that DLL and then rely on the operating system to do the linking at run-time. This to begin with was a welcome change from the static libraries of the past. However, as programmer's started building DLLs they realized that the concept though apparently promising is infested with several problems listed below: Name mangling - To permit function overloading C++ compilers mangle (decorate) the name of each function called/defined in the program. Since the C++ language doesn't lay down any rules about how name mangling should be done, each compiler writer adopted his own strategy to
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Figure 2 The metadata include the types (classes, methods and properties) exported from the assembly and a manifest. A manifest is a data structure. It serves the same purpose as the type library and associated registry entries do for a COM component. Manifest contains more information than a type library. The details of the manifest structure would be discussed in the next article. Assemblies can be loaded using the side-by-side technique. This means a different version of the same assembly can be used inside a single process. Assemblies support Zero-impact installations. Installations can be as easy as copying the files that belong to an assembly. An assembly may represent one file or might be spread across several files. Shared and Private Assemblies There are two types of assemblies available: private assemblies and shared assemblies. A private assembly is used by only one application while a shared assembly is shared amongst different applications. By default when we compile a C# program, the assembly produced will be a private assembly. This assembly (DLL/EXE) should be placed in the same folder as the calling application. With a private assembly it's not necessary to think about naming conflicts with other classes or versioning problems because each application has its own copy of the assembly.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Since our assembly is a private assembly (and not a shared one) it would not be listed in this window. So click on 'Browse' and select the fontassembly.dll from the fontassembly\bin\Debug directory. As a result the DLL would get copied into the fontclient\bin\Debug subfolder of the client. Now we can refer to this class in the client code. On executing the client you would get the window shown below. Click on the form anywhere using the left mouse button and a string "Hello" would appear there.
With the first assembly under your belt, you are ready to get into the more complicated stuff like shared assemblies, versioning, application domains, etc. But that would have to wait till the next article.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Web-Centric View What is needed today is to change the framework from device centric to Internet/Intranet/Webcentric. Under this framework software will be available as a set of distributed services with the devices (PC, PDA, Mobile, etc.) acting as mere points of delivery of services. These services are known as Web Services. Like components they are programmable and reusable. They are available anywhere via the Internet. Programs built using this model will run across multiple websites extracting information from each of them and combining and delivering it in a customized form to any device anywhere in the world. The potential of Web Services is unlimited. For example, a software company may provide a Web Service to calculate income tax. Any company that wants to calculate income tax can subscribe to this Web Service. The customer company need not deploy the income tax calculator. It simply needs to access the Web Service. The company offering the service can dynamically update it to accommodate new taxation rates. The subscribers won't have to do anything to get the new updates. In future a collection of such Web Services may replace packaged software. Other Web Services that can be developed include weather information; stock quotes, shipping status, news items, etc. I think you get the picture now. How will businesses and their customers benefit from Web services? As Web services break down the distinctions between the Internet, standalone applications and computing devices of every kind, they enable businesses to collaborate to offer and unprecedented range of integrated and customized solutions--solutions that enable their customers to act on information any time, any place and on any device. The following figure captures the essence of the .Net vision. To meet the challenge of next generation of internet-based computing Microsoft has come up with the .Net platform. This platform simplifies the process of building these solutions and provides a framework for integration and interoperability. This platform is based on open standards like (XML and SOAP) so that it can work across all programming languages and operating systems. It helps you to combine the power of PCs and smart devices with the richness of Internet. To make Web services a reality Microsoft has addressed the problem at three levels. It has provided a framework to help build the web services, development tools and languages to make this development easy and a server infrastructure to deploy and operate the web services. Let us take a brief look at each of these. Development Tools and Technologies A productive set of tools is critical to carry out successful development on a new platform like .Net. Visual Studio.net provides a complete solution for building, deploying, and running Web services. It helps you to maximize the performance, realiability, and security of your Web services. Visual Studio.Net helps developers quickly build Web services and applications that scale easily, using the language of their choice. This multi-language development tool has been built especially for .Net. You can use programming languages like Visual Basic, C++ and the new language C# for your development work under .Net. Visual Basic was not object oriented, hence it has been spruced up and christened into VB.Net. Visual C++ has been extended to build Web services. You can continue to use it build traditional desktop Windows application s too. A brand new language called C# (pronounced as C sharp) has also been introduced. This language combines RAD (Rapid Application Development) feature of Visual Basic, OO of Visual C++ and portability and platform independence of Java. In addition to these languages provided by Microsoft, there will be over 20 languages provided by partners, including Perl, Python, COBOL, and Eiffel from which developers can choose. For server side programming instead of using nonOO scripting languages like VB SCript we can use C#, VB.Net or C++. Access to databases has also been improved by providing ADO.Net.
Compiled by rmshankar@yahoo.com
Framework The .Net framework is a high productivity, standards-based, multi-language application execution environment that handles essential plumbing chores and eases deployment. It provides an application execution environment that manages memory, addresses versioning issues and improves the reliability, scalability, and security of your application. The .Net framework consists of several parts, including the Common Language Runtime and a rich set of class libraries. Microsoft has also provided a set of core Web services that releases developers from the burden of building everything themselves. By integrating with these core services to perform routine tasks, developers can concentrate on building high-value, business-critical Web services. Microsoft Passport is the first such service which provides authentication services. Microsoft and many other companies plan to develop more core services for users and enterprises. Server Infrastructure Web services should be built on a infrastructure that offers developers the benefits of modular architecture, economical and linear scaling, security, reliability, manageability, and high availability. The .Net Enterprise Servers and the Windows 2000 Server family make up the Microsoft .Net server infrastructure for deploying, managing, and orchestrating Web services. Designed with mission-critical performance in mind, they provide enterprises with the agility they need to integrate their systems, applications, and partners through Web services, and the flexibility to adapt to changing business requirements. The .NET Enterprises Servers are: Application Center 2000 to deploy and manage highly available and scalable Web applications BizTalk Server 2000 to build XML-based business process across applications and organizations Commerce Server 2000 for quickly building scalable e-commerce solutions Content Management Server 2001 to manage content for dynamic e-business Web sites Exchange 2000 Server to enable messaging and collaboration Host Integration Server 2000 for bridging data and application on legacy systems Internet Security and Acceleration Server 2000 for secure, fast Internet connectivity Mobile Information 2001 Server to enable application support by mobile devices like cell phones SharePoint Portal Server 2001 to find, share and publish business Information SQL Server 2000 to store, retrieve and analyze structured XML data.
Compiled by rmshankar@yahoo.com
OS Usage In the older days of DOS programming calling the ROM-BIOS or DOS routines was a messy affair. These functions did not have names hence to call these functions it was necessary to pick up these addresses from Interrupt Vector Table (IVT). Moreover to communicate with these functions it was necessary to setup the CPU registers. And if you managed to master this you were required to content with the hardware dependencies. That is the process of a simple operation like drawing a line varied from one type of display adapter to another. To minimize these difficulties several libraries came into existence. They were useful but were language dependent. With Windows things improved to the extent that the Application Programming Interface (API) functions could be called like any other library function. Moreover with the introduction of device independence the programmer was not bothered to worry about the device on which the programmer would finally run. It was Windows Graphical Device Interface (GDI) that adjusted the drawing according to the capability of the device. Also, the same API functions could be called easily through different languages. However the Windows API functions typically needed several parameters to be passed during the call as shown in figure 2.1. Also, API being merely a library of functions could not support the object-oriented programming paradigm. To
Compiled by rmshankar@yahoo.com
Little Reuse In procedural languages like C reuse was limited to calling the same library functions from different programs. These functions however were not extensible. They were required to be use on a "as is, where is" basis. Also structured programming languages did not model the real world very well. For example, if a C program is used to create a window then there were no language elements that could be identified with the window or its elements like toolbar, menu, status bar, etc. In the procedural programming paradigm the whole emphasis was on dividing a job into several smaller jobs and then implementing these jobs through the individual functions. Importance was given to the operations rather the data on which these operations are performed. While dealing with complex systems this was found to be an unrealistic programming model. World is object-oriented and programmer being the part of the world should also deal with a system that he is trying to program in the form of objects and their inter-relationship. Objectoriented languages embrace these concepts and hence have become immensely popular amongst programmers. C++ and Java are good examples of these. These languages promoted reuse by letting you inherit features of one class into another and then providing additional features in the new class. This was possible even if the source code of the first class was not available. This reuse was a big step forward. However the reuse was restricted within the language. Thus, a Java class was not of much use to a C++ programmer and vice-versa. To promote language independent reuse Microsoft came up with a bold new technology called Component Object Model (COM). COM was a binary specification and components built as per this specification could be used by not only the conventional languages like C or C++ but also by scripting languages like VBScript and JavaScript. To accommodate these wide range of languages a lot of plumbing code was required to be built. Also, COM didn't support crosslanguage inheritance or cross-language debugging. Instead of adopting a philosophy of letting all kinds of languages to use COM components and requiring a lot of plumbing code to be written in
Compiled by rmshankar@yahoo.com
Messy Runtime DOS was a single tasking operating system, which could run only one program at a time in memory. With the dramatic increase in the computing power it was unrealistic to expect that a user will like to use the entire power to run only one program. Windows could utilize this computing power by letting users run several programs at a time by creating a powerful runtime. However this runtime had the following problems: Poor error handling - Windows returned error codes which is not the object oriented way of handling errors. It has now become a common norm that errors should be handled through exceptions and nit through error codes. Costly Inter Procedure Calls (IPC) - When multiple processes are running in memory Windows runtime ensures that no process barges into the memory of the other. However there is often a need to communicate between processes. This calls for marshalling (conversion of parameters being passed to a function into a byte stream) and unmarshalling (conversion of byte stream into data types). There is a severe overhead in this as lot of copying of parameters takes place. If this is to be avoided then the second process can be made as a DLL and then made to run in the same address space as the first. This has a disadvantage that if the DLL fires the process in whose address space it is running also fires. .Net overcomes this limitation by using a concept called Application Domains.
Compiled by rmshankar@yahoo.com
Deployment Nightmare DLLs are created with a motive to share them between different applications. Hence while installing them instead of placing them in any particular application's directory they are installed either in Windows directory or in Windows\System directory. Thus whichever application wants to use a DLL file it can load it from one of these directories. This, on the face appears to be pretty straightforward. But when a new version of the DLL is released it should not be copied on top of the earlier version. Otherwise the clients that were using the earlier DLL might break. Thus the DLLs have to have different names if the two versions are to coexist. These versioning problems are popularly known as DLL hell.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Article: Thinking in C#
C# (pronounced as 'C Sharp') is a new object-oriented language designed at Microsoft by Anders Hejlsberg. This language would help programmers create secure, robust, portable, distributed object-oriented applications for the internet. But that is hardly a definition that would impress a programmer. What he would be most interested in knowing is how this language is going to make a difference to his daily work and how is it different than existing popular languages like C++, Visual Basic and Java. The answer is simple-it combines the power of C++ with productivity of Visual Basic and elegance of Java. That's a tall promise. We need to examine this claim with a thick lens. Power of C++ - C# brings with it object-oriented paradigm of C++. It implements the same through encapsulation, inheritance and polymorphism. Productivity of Visual Basic - Promotes Rapid Application Development through simpler GUI programming with easy drag & drop support. Properties & Events are part of the language itself. Elegance of Java - No pointers (unless explicitly mentioned), fixed-size primary data types, Unicode characters, Type-safety, No multiple-inheritance, Garbage collection, Platform independence.
The C# language is disarmingly simple. C# is the first language that has been designed from ground up with Internet in mind. Using C# we can create a whole gamut of applications including Windows-based applications (WinForms), server-side applications (Dynamic Web Pages, Web Services), client-side applications (Web Forms & Web Controls), enterprise applications (ADO.NET), mobile applications, components (Assemblies), etc. The First C# Program Best way to learn a new language would be by writing programs and then comparing them feature by feature with popular existing languages like C++, Visual Basic and Java. So let us begin with the first program that displays a message "Hello C#". Here is the program namespace Simple { using System ; class Class1 { static void Main ( string[ ] args ) { Console.WriteLine ( "Hello C#" ) ; } } } On execution, this program prints a message "Hello C#" on the screen. To create this program we would use the Visual Studio.NET environment in the steps mentioned below: a. Start Microsoft Visual Studio.NET 7.0 from Start | Program | Microsoft Visual Studio.NET 7.0 menu option. b. Create a new C# project from File | New | Project menu option. A New Project dialog as shown in the following figure would appear.
Compiled by rmshankar@yahoo.com
c. From the New Project dialog box select project type as Visual C# Projects. d. Select Console Application from the list of Templates. e. Select a location where this project should get saved. Give name to the project - Simple. Click on OK button. f. A Class1.cs file would get created. g. Type the program in Class1.cs file h. To execute the program, programmers using Visual Studio.NET should use Ctrl + F5. Those who do not have Visual Studio.NET should go to DOS prompt and execute the command C>csc Class1.cs. Here csc stands for C Sharp Compiler. The output of this command would be an EXE file. To execute the .EXE file just type its name on the command prompt. (From now onwards we would build applications using Visual Studio.NET.) Here we have used console application from several templates. As we go along we would use other templates also. The program execution starts from the Main( ) function. Since C# is a pure object-oriented language it does not allow us to create global variables and functions. Instead, all variables and functions should be defined inside a class. Hence it is necessary to define the Main( ) function in some class, say Class1. Except for the line marked out in bold in the above program the rest of the code shown in the program is generated by the Wizard. A class is a blue-print from which specific objects can be created. A class is similar to a data type and an object is similar to a variable. The way we can create several variables from an int type, likewise we can create several objects from a class like Class1. The class, like structure in C, allows us to create our own (user-defined) data types by combining intrinsic or other user-defined data types. Unlike structures in C a class can hold data as well as functions. Thus a class indicates what kind of data an object of its type can hold and what operations (like addition, subtraction, display, etc.) can be performed on this data. In short, the class specifies what data and what functions will be included in objects of that class. We would learn more about this in the Chapter "Classes and Objects".
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Range
-128 to 127 0 to 255 -32768 to 32767 0 to 65536 -2147483648 to 2147483647 0 to 4294967295 -9223372036854775808 to long signed 8 bytes 9223372036854775807 ulong unsigned 8 bytes 0 to 18446744073709551615 Any whole number value can be an integer value. The data types in this group cannot hold fractional values. Floating Points Data Signed/Unsigned Size Range Type float signed 4 bytes 1.5 x 10 -45 to 3.4 x 10 38 double signed 8 bytes 5.0 x 10 -324 to 1.7 x 10308 The data types in this group can hold Floating-point numbers representing decimal values with a fractional component. Character Data Signed/Unsigned Size Range Type char unsigned 2 bytes The data type in this group can hold a character with a 16-bit Unicode value. Unicode defines fully international character set that can represent all of the characters found in all human languages. It is the unification of dozens of character sets such as Latin, Greek, Arabic, Cyrillic, Hebrew, Katakana, Hangul and many more. For this purpose it requires 16 bits to represent each character. Boolean Data Signed/Unsigned Size Range Type Bool NA 1 byte true or false This type can hold logical values. It can have only one of the two possible values, true or false. Decimal Data Signed/Unsigned Size Range Type 16 decimal signed 1.0 x 10 -28 to 7.9 x 10 28 bytes This data type is a dedicated type for financial calculations. It represents higher precision floating-point numbers. It allows us to specify currency amounts. C# imposes some rules while using these data types. These rules are explained below with the help of code snippets: Rule 1: Before using any variable it must be initialized with a value.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Article: Registry
The registry is used to store information about Windows setup, user preferences, and installed software and devices. All the COM components place their CLSIDS, ProgIDs, paths of the DLLs, versions in the registry. This helps the clients to load the component from any directory. The registry is a hierarchical structure whose top-level nodes represent the registry hives. To view or modify the registry we execute the utility regedit through Start | Run Dialog. The number of hives in the registry is fixed. There are seven of them. We cannot see all the hives. HKEY_CLASSES_ROOT - Contains details of the types of files present on the system and information about applications that are able to open those files. It also consists of registration information for all COM components. HKEY_CURRENT_USER - Contains details of user preferences for the user currently logged on to the machine. HKEY_LOCAL_MACHINE - Contains details of all software and hardware installed on the machine. HKEY_USERS - Contains details of user preferences for all users. HKEY_CURRENT_CONFIG - Contains details of configuration of hardware devices on the machine. HKEY_DYN_DATA - Contains information about volatile data. HKEY_PERFORMANCE_DATA - Contains information concerning the performance of running applications.
Each root key consists of data as well as keys. The data is present as values. The value is divided into 3 parts: name, type and data. The key may have a default value, which is unnamed. The type of value may be formatted as one of the three data types namely, REG_SZ, REG_DWORD, REG_BINARY. REG_SZ corresponds to a string. REG_DWORD corresponds to a uint. REG_BINARY corresponds to an array of bytes.
The .NET Framework offers two classes in the Microsoft.Win32 namespace: A RegistryKey class and a Registry class. Microsoft.Win32 namespace contains classes related to those that handle events raised by the operating system and those that manipulate the system registry. These classes are not included in the System namespace because they are specific to Windows operating system. The RegistryKey class represents a Registry key. This class has methods to browse, to create new keys and to read or modify the values in the keys. The Registry class contains only seven public static fields, which expose the actual keys to the programmer. These fields are read-only fields and cannot be modified. These fields expose the instances of the root RegistryKeys found in the registry. The seven fields are CurrentUser, LocalMachine, ClassesRoot, Users, PerformanceData, CurrentConfig, and DynData . This class is never instantiated and it only provides us with instances of top-level registry key instances. Creating a Test Version Application.
Compiled by rmshankar@yahoo.com
In the following program we plan to write an application that keeps a count on the number of times the application has executed as well as the amount of time the program spent in execution. If the application crosses a specified limit, it becomes unavailable. Many softwares, especially the ones that we download freely from the Net have an expiry period. When we run such softwares a dialog is popped up which informs us that we can use the software only for a specific number of days. And this count keeps reducing every day. In our program we have kept a limit on number of days as well as time. The Logic used is as follows: When we run our application for the first time, we add a registry entry in the HKEY_CURRENT_USER | Control Panel. Hence we have added a key for our application along with two values, one for maintaining the number of executions and another for maintaining the count on time. Next time when we open the application it checks these values and accordingly allows or disallows the program to execute. The limitation that we have kept in the program is that it should work for a maximum of 5 hrs or can execute only 50 times. To keep a count on time, we have added a timer control in our application. This is done by dragging in the control from the toolbox. We have changed its name from timer1 to mytimer. Every time we start the application a 'staring form' is displayed which indicates the time expired, time remaining, number of times the application was executed, and remaining number of times it can be executed.
Here we have added 9 labels, 4 for displaying the static text and four for displaying the time expired, time left, executions completed, and executions remaining. We have named them as texp, tleft, execom, and exerem respectively. The last label is used to display a message besides the start button. The start button indicates that the actual application will start, the earlier form is just a starting indication, and it does not start the real application. When we click the start
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
If demo does not contain a null it means that the application is not running for the first time and the key and its values already exist. In this case we have retrieved the values using the GetValue( ) method. While retrieving the value we have to type cast it back in whichever data type we have used amongst a string, an int or a byte array. Here we have used an int. Next we have set all the text fields of the labels to the appropriate values by calculating the time in hours and minutes from the extracted key values. If the extracted minutes happened to be more that 300 (5 hours) or the number of executions happened to be more that 50, we have disabled the start button and flashed an appropriate message. We have kept a count on time with the help of the timer. The timer starts when we click the Start button: private void start_Click ( object sender, System.EventArgs e ) { numexe++ ; demo.SetValue( "executions", ( object ) numexe ) ; mytimer.Start ( ) ; MessageBox.Show ( "Write Your Application Logic Here" ) ; } When we press 'Start' the number of executions is increased and the new value is set. We have added the Tick( ) handler with a time interval of 1000 milliseconds. This means after every 1000 milliseconds (1 second) this event will be fired. We can change this value in the 'Properties' window of the timer control. This is the place where we can write the logic of our actual application. private void mytimer_Tick ( object sender, System.EventArgs e ) { if ( ++timercounts >= 60 ) { min++ ; texp.Text = min / 60 + "hours " + min % 60 + "minutes" ; int m = 300 - min ; tleft.Text = m / 60 + "hours " + m % 60 + "minutes" ; demo.SetValue ( "Minutes", ( object ) min ) ; timercounts = 0 ; } if ( min >= 300 ) { mytimer.Stop ( ) ; Dispose ( ) ; } } Here we have first checked if timercounts is greater than 60 (1 min). If it is, we have increased min by one and we have written the new value in the registry as well as in the text filed of the labels accordingly. Next we have checked the min field. If it happens to be greater than 300 (5 hours), the timer should stop and the program should terminate. To do so, we have called the Dispose( ) method. In this method we have disposed all the objects we created. protected override void Dispose( bool disposing ) { top.Close ( ) ; r.Close ( ) ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
DirectX Components DirectX Graphics This component includes various functions that are used for handling graphics. This component is further divided into DirectDraw (2D Graphics) and Direct3D (internally uses DirectDraw). The DirectX Graphics component also includes Direct3DX utility library which helps in simplifying complex mathematical operations useful to Direct3D. DirectInput This component supports variety of input devices like keyboard, mouse, joystick, etc. It also provides force-feedback effect in input devices like motor mounted joystick by generating push or resistance. Force-feedback technology helps make the gaming environment more realistic. For example, if we are flying an aircraft in a game and if the aircraft crashes then due to forcefeedback we would feel the jerkiness of the explosion. (push effect) . Or if we are driving a car with the help of a force-feedback joystick, the more we push the joystick the more the car accelerates. If the car collides with another car/obstacle then the joystick will try to resist our action of pushing to simulate an obstacle. DirectInput removes delay in receiving input data by bypassing the Windows messaging architecture. DirectX Audio This component consists of DirectSound and DirectMusic. DirectSound is used to generate sounds like car doors slamming, horns honking and birds chirping thereby making games more realistic. It also removes delay in generating sound effects. DirectMusic is used to compose music at runtime. DirectPlay This component facilitates multi-player gaming on the network or Internet. It provides functionality
Compiled by rmshankar@yahoo.com
Public and private keys are always created in pairs. The public key is made available to everybody and the private key is kept safe and secure. How it works on Assemblies? First a public-private key pair is generated at random for the assembly using the sn utility. How to generate the keys using the sn utility is discussed later. We then provide these keys to the compiler. The compiler takes a cryptographic hash of the names and contents of the files in the assembly. This hash is taken using a very simple algorithm. This cryptographic hash is then encrypted using the private key for the assembly by the compiler, and placed in the manifest. The compiler also creates the strong name and writes it in the manifest. As said earlier a strong name consists of a combination of a file name, a public key, a version number and culture. So along with the strong name the public key also gets written in the manifest. The strong name does not contain the private key. This ensures that the private key is not written in the manifest
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Using the Shared Assembly We will use the same client we made last time for using 'fontassembly.dll'. To do so first we have to be sure of two things: We must delete the private 'fontassembly.dll' version we created last time from the directory of the client and secondly we must remove its reference by right clicking on fontassembly under 'References' in the 'Solution Explorer' window and selecting 'Remove'. To use the shared assembly we will have to again add the reference of the shared assembly in the same way as for the private assembly. But this time the assembly does not get copied into the local directory because the CopyLocal property of the reference is automatically set to False by the compiler. This can be seen in the 'Properties' Window of the assembly. On compiling the client we get the same results. We can now use the same DLL in any client we want and every time the assembly installed in the Global cache will be used. Structure of an Assembly So now lets look at how the assembly looks like. The assembly is made up of metadata , IL code and resources. The Metadata consists of type metadata and assembly metadata. Assembly Metadata describes the assembly and is called the Manifest. A manifest contain: a. The identity of the assembly, consisting of its name, version and culture.
Compiled by rmshankar@yahoo.com
The tool shows the Manifest, Namespace, Class and Method in the assembly. It can also show Interfaces, Value types, Static methods, Fields, Static Fields, Events and Properties if present.
Article: C# - Versioning
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Figure 1 Here, Click is a reference to an event of the type System.EventHandler and is already defined in the System.Windows.Form class. Realize that System.EventHandler is a delegate used to wrap an event handler. A delegate that dispatches an event is called an 'event delegate'. The event handler Form1_Click( ) is wrapped inside the Click event. This method is written in the Form1 class and it accepts two references. One of them is of object type and contains reference of the event raiser (Form1 here) and the other is of type EventArgs. Here we have not written any statement to explicitly raise the event Click( ). Whenever the user clicks on the form the .NET runtime raises this event for us. .NET runtime then informs the base class, Form about this event. The Form class would call the event handler using the statement like Click ( reference of sender, reference of EventArgs ) ; Here, Click represents (is a delegate for) Form1_Click( ) event handler. And so, this statement would call the Form1_Click( ) handler.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Here a, a1, a2 are references to an int array. Thus we are not declaring an array. Instead, we are declaring a reference to it. This merely sets aside space for reference to an array. Once we have declared an array reference, we can construct an array through the statement:
Compiled by rmshankar@yahoo.com
To initialize an array we need to write the following statement: int[ ] arr1 = new int[ ] { 3, 5, 7, 9, 1 } ; Or int[ ] arr1 = { 3, 5, 7, 9, 1 } ; Here the array gets allocated on the heap and all its elements store a value. By default, all the elements of this array are initialized with a value 0. We can also create an array of objects. This is explained with an example, sample[ ] s = new sample [ 5 ] ; Here s is a reference to an array of references. The array gets created on the heap. Each element of the array in itself is a reference to the sample object. Hence, each reference would hold address of an object and not its value. By default, all the elements are initialized with a null reference. The in-memory view of the array is shown below:
Compiled by rmshankar@yahoo.com
To assign the array element with the addresses of the objects we need to write the following statements: s [ 0 ] = new sample ( 1 ) ; s [ 1 ] = new sample ( 2 ) ; s [ 2 ] = new sample ( 3 ) ; s [ 3 ] = new sample ( 4 ) ; s [ 4 ] = new sample ( 5 ) ; Or sample s[ ] = { new sample ( 1 ), new sample ( 2 ), new sample ( 3 ), new sample ( 4 ), new sample ( 5 ), } Like C and C++, C# also uses a zero-based scheme to access array elements. This means that the first element in the array is considered to be at 0th position. Multidimensional Arrays In C# multidimensional arrays are of two types - Rectangular and Jagged. C# has a different syntax for both. Rectangular Arrays In rectangular arrays every row of the array is of the same length. This means if we have a two-
Compiled by rmshankar@yahoo.com
To print the elements of the rectangular array we need to write the following code: foreach ( int i in arr1 ) Console.Write ( i + " " ) ; The foreach loop allows us to iterate through each item in an array. The foreach loop always travels through all elements of one row before moving to the next row. Using foreach we can never travel through a 2-D array column by column. Jagged Array A jagged array is an array of several 1D arrays each of different length. We cannot create the jagged array in the same way as we created the rectangular array. Suppose we are required to create a jagged array containing 2 rows where first row contains four integers and the second row contains 2 integers. We may try to define this array as follows: int [ , ] arr1 = new int [ , ] { { 3, 5, 7, 1 }, { 11, 13 } } ; Or int [ , ] arr1 = { { 3, 5, 7, 1 }, { 11, 13 } } ; Both these definitions are wrong, because the number of elements in each row is different and the complier never keeps track of how many elements are present in each row. Hence later on it would not be feasible for it to access the correct element when we use an array access expression, like arr [ 1, 2 ]. The correct way to initialize the jagged array is as follows: int[ ] [ ] arr1 = new int [ 2 ] [ ] ; arr1 [ 0 ] = new int [ 3 ] { 3 , 5, 7, 1 } ; arr1 [ 1 ] = new int [ 2 ] { 11, 13 } ; The in-memory view of this jagged array is as follows:
Compiled by rmshankar@yahoo.com
The way to create a 3D jagged array is as follows: int[ ] [ ] [ ] arr = new int [ 2 ] [ ] [ ] ; arr [ 0 ] = new int [ 3 ] [ ] ; arr [ 0 ] [ 0 ] = new int [ 3 ] ; arr [ 0 ] [ 1 ] = new int [ 4 ] ; arr [ 0 ] [ 2 ] = new int [ 5] ; Here the 3D array consists of two 2D arrays. The first 2D array would consist of three 1D arrays, and finally all the three 1D arrays have different number of elements. From the above discussion it is clear that in a rectangular array all indices are within one set of brackets. for a jagged array each element is within its own bracket. For a 2D rectangular array we have to write int [ , ] whereas, for a 2-D jagged array we have to write int[ ][ ].
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
When we use an assignment operation between two reference variables, the reference to the first object gets copied into the other reference variable. But this is not the case with strings. In spite of being a reference type an assignment operation on two string variables results in creation of a new object. The value of the right-hand side string object gets copied into the new object and the reference to this new object gets assigned to the reference variable on the left-hand side of the assignment operator. This is shown in the following example. using System; namespace sample { class Class1 { static void Main ( string[ ] args ) { string s1 = "Good Morning" ; string s2 ; s2 = s1 ; s1 = "Wake Up" ; Console.WriteLine ( s1 ) ; Console.WriteLine ( s2 ) ; } } } The output of the program would be, Wake up Good Morning In this program we have created two string references - s1 and s2. We have initialized s1 with a reference to an object containing "Good Morning" and kept s2 uninitialized. Then we have assigned s1 to s2. Normally both being references only the reference should have assigned to s1. But this does not happen. Instead a new object gets created that holds the same value contained in the object referred by s1. Like System.Array, System.String class too defines various methods to perform routine operations on strings. The following programs illustrate use of the System.String methods. using System ; namespace sample { class Class1 {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
if ( func3( ) == -1 ) // handle the error else // do normal things There are three problems with this approach: (a) Every time we call a function we must check its return value through a pair of if and else. Easier said than done! Surrounding every function call with a pair of if and else results in increase in code size. Also, too many if - elses make the listing lose its readability. (b) This approach cannot be used to report errors in the constructor of a class, as the constructor cannot return a value. (c) It becomes difficult to monitor the return values in case of deeply nested function calls. Especially so, if the functions belong to a third-party library. C# uses a more systematic approach to tackle exceptions. The .NET CLR checks for the runtime errors and raises exceptions to inform the program that an error has occurred. It also handles these exceptions if the program has not handled it. In C# the exceptions are in the form of objects of exception classes. All exception classes are derived from the System.Exception class. An exception object cannot be "thrown" or "caught" unless their classes are inherited from the System.Exception class. When we say an exception is thrown, it means that the CLR creates an object of the class on heap and passes its reference to the program. There are several standard exceptions provided by the .NET framework. We can also create user-defined exceptions. The exception thrown by the code written in one .NET compliant language can be caught in another .NET compliant language. We can handle exceptions in C# using the following: a. The try block followed by one or more catch blocks. b. The try-catch blocks followed by finally block. Let us understand each of them. The try-catch Blocks The try block contains code expected to raise an exception. The code in the try block executes until a statement which raises an exception is encountered. When an exception is encountered, the program flow shifts to the catch block. The catch block handles the exception by executing the code written in it. For example, using System; namespace Sample { class Class1 { static void Main ( string [ ] args ) { int a, b = 0 ; try {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Article: C# - Multithreading - I
Every application running under Windows constitutes a process. Each process can contain one or more threads of execution. A thread constitutes a part of execution through a program's code and a set of resource (like stack, register state, etc.) assigned by the operating system. When we execute a Win32 application it starts as a single thread but can spawn several additional threads. There is a scheduler program in the operating system kernel that divides the CPU time among active threads. As a result, all the threads appear to run simultaneously. Threads are popularly used for performing tasks in the background while processing user input in the foreground. However, usage of threads is not restricted to running tasks in the background. They can also be used for creating windows or other foreground processing. Though writing multithreaded programs is difficult, if used properly threads can dramatically improve an application's performance. Threads are basically asynchronous by nature. It takes time for the programmers to get used to this behavior. Let us now create an application where we can put multithreading to work. The application should display the list of files present in 'C' drive in the form shown in Figure 1.
Compiled by rmshankar@yahoo.com
Figure 1 The listing should begin when we click on the 'Start' button and it should stop when we click on the 'Stop' button. When we click on the 'Start' button, an event handler should get called. Another event handler should get called when we click on the 'Stop' button. If we do not run the event handler or the 'Start' button in a separate thread we would not be able to click the 'Stop' button unless control returns from the 'Start' button's event handler. A clear cut case where multithreading would make sense. Let us now proceed with creating the program. Create a form shown in Figure 1 Insert three buttons and a label in the form. The label would display file names. On clicking the 'Start' button an event handler would get called that would start a new thread to display the files on the disk in the label. After starting the thread the event handler would end. The process of displaying the files would continue and there would be no restriction on us to click the 'Stop' button. This is because the event handler written for the 'Start' button in the main thread would end and the main thread would be ready to receive other events. At the same time the new thread would be getting time slots for processing. To build such an application create a 'Windows application' and insert three buttons: 'Start', 'Stop' and 'Close' having names as start, stop and close respectively in the form. Also add a Label control having name file to the form. Add the event handlers for all the three buttons. Firstly we would see the start_Click( ) handler. This handler is given below: private void start_Click ( object sender, System.EventArgs e ) { string path = @"c:\" ; search s = new search ( file, path ) ; ThreadStart ts = new ThreadStart ( s.searchfiles ) ; t = new Thread ( ts ) ; t.Start( ) ; } Here, we have first created an object of the user-defined search class. We would see this class later. We have passed the reference of the label and the directory path to the constructor. Next, we have created a new thread. To start another thread we have created an object of the Thread class first. This object's reference is stored in t. The reference t (of type Thread) should be added as a data member of the form class. While creating a thread, we must specify which function should get executed when the thread gets started. We have specified that the searchfiles( ) method of the search class should get executed. For this, we have to wrap its address in a delegate and pass it to the constructor of the Thread class. We have used a predefined .NET delegate class called ThreadStart and created a delegate object ts. The delegate ts is passed to the constructor of the Thread class. So whenever the thread is started, the method wrapped inside ts would start executing. To start a thread we have called Start( ) method of the Thread
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Figure 2 The FileSystemInfo class can hold the reference of any file system object, be it a file or a directory. After storing the reference of the array in f, we have iterated through the array using the foreach loop and checked whether each file system object is a file or a directory. This is done by comparing the Attribute property of the FileSystemInfo object with the Directory member of the FileAttribute enumeration. If the object turns out to be a directory, we have created a new DirectoryInfo object, stored its reference in dir and recursively called the searchfiles( ) method. If the file system object turns out to be a file, we have displayed its name in the label present in the form. To interrupt the process of displaying the files before all the files are displayed we have to click on the 'Stop' button. It is possible for us to click on the 'Stop' button because the execution of the searchfiles( ) method is taking place in a different thread. On clicking the 'Stop' button, the handler stop_Click( ) gets called. The code for the handler is shown below. private void stop_Click ( object sender, System.EventArgs e ) { t.Abort( ) ; } The Abort( ) method of the Thread class terminates a thread. If we wish to terminate the application, we have to click on the 'Close' button; the handler for the 'Close' button gets called that disposes the form. The handler is shown below. private void close_Click ( object sender, System.EventArgs e ) { Dispose( ) ; }
Article: C# - Multithreading - II
Continued from last week... Synchronization Software development is a team effort. Unless team members cooperate with one another, synchronize their work with the rest of the team, the team can't go far. Similarly if in a program
Compiled by rmshankar@yahoo.com
In such cases we must make sure that if one thread is handling the list, the other should not work with it. This is achieved using synchronization.
Synchronization provides a lock on the object that is going to be shared amongst threads and makes a thread wait until the other thread finishes the job with the resource or object. Hence we can say that synchronization 'locks' the object or shared resource and prevents another thread from using it. C# provides us with a lock keyword to lock the shared object or resource. Whatever is written inside the parenthesis following the lock keyword gets locked for the current thread and no other thread is permitted to access that resource or object. To understand these concepts more thoroughly consider the following program. In this program the form consists of three buttons: 'Add', 'Sort' and 'Close' having names add, sort and close respectively and a list box control having the name list. The design of the form is shown in following figure.
Compiled by rmshankar@yahoo.com
Clicking the 'Add' button would start a thread to add a new name to the list, whereas, clicking the 'Sort' button would start another thread that would sort the list. The list box control would always display the names stored in an ArrayList object whose reference is added as a data member of the form class. We have initialized the array list object in the constructor of the form class with names contained in a file. The code to do so is shown in the following snippet: public Form1( ) { InitializeComponent( ) ; arr = new ArrayList( ) ; FileInfo f = new FileInfo ( "data.txt" ) ; StreamReader r = f.OpenText( ) ; string s ; while ( ( s = r.ReadLine( ) ) != null ) { arr.Add ( s ) ; list.Items.Add ( s ) ; } r.Close( ) ; } Here in the constructor we have initialized the array list object arr with names present in the 'data.txt' file. This file should be present in the 'synchronize' project folder. The methods that the threads would start are written inside a class called mythread. The declaration of the mythread class is given below. class mythread { ListBox list ; ArrayList arr ; string name ;
Compiled by rmshankar@yahoo.com
public mythread ( ListBox l, ArrayList a ) { list = l ; arr = a ; } public mythread ( ListBox l, ArrayList a, string n ) { list = l ; arr = a ; name = n ; } public void add( ) { lock ( arr ) { arr.Add ( name ) ; list.Items.Clear( ) ; foreach ( string i in arr ) list.Items.Add ( i ) ; } } public void sort( ) { lock ( arr ) { arr.Sort( ) ; list.Items.Clear( ) ; foreach ( string i in arr ) list.Items.Add ( i ) ; } } } In this program we cannot pass parameters to the sort( ) and add( ) methods because they are wrapped by the ThreadStart delegate. Hence we have added the parameters that we need in the methods as data members of the class and initialized these parameters using constructors. Hence this class contains two constructors. The two-argument constructor is used for initializing parameters for the sort( ) method, whereas, the three-argument constructor is used for initializing parameters for the add( ) method. We have locked the ArrayList object in this program, as it is used by both the threads. In the add( ) method after locking the arr object we have added the new name to the list by using the Add( ) method. Next we have deleted all the items of the list box by calling the Clear( ) method and then displayed all the names again including the new name. In the sort( ) method too we have first locked the object arr and then sorted the array using the Sort( ) method of the ArrayList class. The sorted list is then displayed in the list box. We have called the add( ) and sort( ) methods in the corresponding handlers. The handler for the 'Add' button is shown below. private void add_Click ( object sender, System.EventArgs e ) {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Such a situation calls for alternate execution of both the threads and each thread must wait for the other thread. Both threads would share the same resource. The generate thread would use the resource to fill in shapes and the draw thread would use the resource to read the shapes. Hence the resource must not be used by both the threads at the same time. For such a sophisticated control over resources, we should use a monitor. A Monitor lets us decide when to enter and exit the synchronization. The class that represents a monitor in .NET is System.Threading.Monitor. Let us see how to use this class in our program. In this program we plan to generate shapes like lines, rectangles and ellipses and then draw them on the form. To accomplish this we have used two methods namely generate( ) and draw( ). These two methods would be called from two different threads. We have to make sure that in spite of them being in different threads, they should execute alternately. We have also created a structure called info that would store information about a shape including the shape number, its coordinates and the pen with which the shape would be drawn. The structure declaration is shown in the following snippet: struct info { public int shapeno ; public int x1, y1, x2, y2 ; public Pen p ; }; Next we have defined a class called shapes. The shapes class consists of four data members: They are as follows: info[ ] n ; Random r ; bool flag ; Form1 f ; The array n would be used to store the pointer to an array containing the shapes. The reference r would be used to generate random numbers. The bool data member flag would be used for controlling the alternate execution of the threads. The reference f would hold the address of the form. A one-argument constructor is used to initialize these data members. This is how we need to initialize the data members: public shapes ( Form1 ff ) { n = new info [ 10 ] ; r = new Random( ) ; flag = false ; f = ff ; } We have defined two methods called generate( ) and draw( ) in the shapes class: Along with these methods the shapes class also contains the generatedata( ) and drawdata( ) methods. Let us discuss them one by one. The generate( ) method is given below:
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
A point to note! Instead of using the if statement and making the thread wait until the other thread sends a pulse to it, we may think of using a while loop checking the flag every time. But this is not the correct way. The processor time would be wasted if we go on checking the flag manually. Hence to save processor time, it is always right to use the Wait( ) method and send a pulse to it every time.
Compiled by rmshankar@yahoo.com
Retrieving Information about Assemblies, Modules and Types Here is a simple program that shows how to obtain information about an assembly and modules. It also displays the contained types of the assembly. To execute this program we must declare the namespace System.Reflection in the program. Here we have displayed information of the assembly System.Drawing.dll. static void Main ( string[] args ) { Assembly a = Assembly.LoadFrom ( "C:\\System.Drawing.dll" ) ; AssemblyName n = a.GetName( ) ; Console.WriteLine ( "Name of assembly: {0}", n.Name ) ; Version v = n.Version ; Console.WriteLine ( "Assembly Version: {0}.{1}.{2}.{3}", v.Major, v.Minor, v.Build, v.Revision ) ; Console.WriteLine ( "Modules: " ) ; Module[ ] ma = a.GetModules( ) ; foreach ( Module m in ma ) Console.WriteLine ( m.Name ) ; Console.WriteLine ( "Exported Types: " ) ; Type[ ] t = a.GetExportedTypes( ) ; foreach ( Type type in t ) Console.WriteLine ( type.Name ) ; } To reflect on an assembly System.Reflection namespace contains a class named Assembly. Before calling any methods of the Assembly class we must load the assembly. We have done this by calling the static method of the Assembly class called LoadFrom( ). To the LoadFrom( ) method we need to pass URL of the assembly. Once the assembly is loaded, we can obtain information like assembly name, version, modules in assembly, types exported by the assembly, etc. The GetName( ) method of Assembly class returns reference to an object of the AssemblyName class. Using this object we can get still more information about the assembly. We have used the Version property of the AssemblyName class to get the version of the assembly. The GetModules( ) method of the Assembly class returns an array of Module objects representing modules in the assembly. We have then obtained the module name by using the
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Figure 2
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Figure 1 Figure 1 also displays reference of 'baseform.dll' being added in the 'References' tree in the Solution Explorer. The derived form displays the derived controls being added to the base form. These controls are accompanied by a small icon at the top left corner to distinguish between the derived controls and the new controls. 7. Open the 'Form1.cs' file. Change form name in Application.Run( ) method to Form2 as shown below. Application.Run ( new Form2( ) ) ; This ensures that when we would execute the application, the new form, i.e. Form2, would get displayed. If we enter the text in the textbox and click the button the text would get displayed in a message box. Let us now see how the whole thing works. To begin with the statement Application.Run ( new Form2( ) ) gets executed. Here we are creating an object of the Form2 class which is derived from the baseform.Form1 class. When we create an object of derived class, base class's constructor gets called. So, in our case constructor of the baseform.Form1 class would get called. This class is accessible to us since a reference to the 'baseform.dll' assembly is already being added to our project. The compiler adds a call to the InitializeComponent( ) method in the constructor of every form class. The InitializeComponent( ) method contains the code for creating and customizing the controls. Once this method gets executed and controls get created, the control returns to the constructor of the Form2 class. This constructor again calls the InitializeComponent( ) method. This time the InitializeComponent( ) method of the Form2 class gets called. This is the reason why derived form contains the derived controls (initialized by InitializeComponent( ) method of the baseform.Form1 class) and the new controls (initialized by InitializeComponent( ) method of the Form2 class). We have already added the Click event handler for the 'Click' button. We can override this handler in the Form2 class and add our code in it. Now if we click the button, firstly, event handler of the base class gets executed and then the overridden handler gets executed. This is because, the InitializeComponent( ) method of the baseform.Form1 class gets executed first, wherein, an address of the Click event handler defined in the baseform.Form1 class gets stored in the Click delegate. Next the InitializeComponent( ) method of the Form2 class gets executed. In it,
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Console.WriteLine ( x.i ) ; Console.WriteLine ( y.i ) ; } } } The output of this program would be 9 5. Let us now understand how this program works. The statement, mystruct x = new mystruct( ) ; creates a new structure variable x, which refers directly to the data. We have stored 9 in x. The statement mystruct y ; too creates a structure variable y, which refers directly to the data. The statement y = x assigns the value of x to y. Hence y would now hold 9 in it. Then the statement y.i = 5 assigns the value 5 to y. Now y would hold 5 and x would continue to hold 9 in it. Thus whenever we assign a structure variable to another structure variable the full contents of righthand side structure variable get copied in the left-hand side variable. The difference between mystruct x = new mystruct( ) ; and mystruct y ; is that for x a default zero-argument constructor would get called, whereas, for y no constructor would be called. The default zero-argument constructor sets the data members to their default values. Since no constructor gets called for y its members do not get initialized. In such a case we must take care to initialize the variables before their usage. In both the cases discussed above memory is allocated on the stack. Now let us see a reference type at work. using System ; namespace sample { class myclass { public int i ; } class Class1 { static void Main ( string[ ] args ) { myclass x = new myclass( ) ; x.i = 9 ; myclass y ; y=x; y.i = 5 ; Console.WriteLine ( x.i ) ; Console.WriteLine ( y.i ) ; } } }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The primitive data types being structures, they can call functions defined in those structures. For example to convert an integer to a string we can write the following code: int n = 10 ; string s = n.ToString( ) ; C# supports two more primitive data types: object and string. They are of reference types and are mapped to the System.Object class and System.String class respectively. User-defined structures and classes by default get derived from the System.Object class. Even all .NET classes and structures are derived from the System.Object class. Enumerated data types and arrays too get mapped to the .NET base classes in some way or the other. Even though the structures cannot have virtual functions they can have override methods. This is because structures are derived from the System.Object class. Using the override methods we can override the virtual methods of the System.Object class. Boxing And Unboxing C# provides the flexibility to use value types as reference types (objects) as and when required. Whenever a value type is converted into a reference type it is known as boxing. On the other hand when a reference type is converted into a value type it is known as unboxing. For example, int i = 10 ; object o = i ; // boxing i = ( int ) o ; // unboxing This is a simple example where we have first "boxed" an int into an object (reference type) and then extracted the value back into an int variable. Note that boxing will always be implicit, whereas, unboxing is explicit. This is because while unboxing we extract the value from an object type and hence we are never aware of its actual type i.e. whether it is an int, float, char, etc. So we explicitly have to determine the type we want back. On the other hand while boxing, we need not bother about the type and just box it into the object. This is because all value types are inherited from the object class. Where do we need to use boxing? Boxing generally occurs while passing arguments to a method. If we pass a value type to a method that was expecting a reference type, the compiler boxes the value type into an object or System.Object. Consider the following example: int i = 12 ; myclass c1 = new myclass ( 10 ) ; Console.WriteLine ( "The value is {0} {1}", i, c1 ) ; Here we have passed three arguments to the WriteLine( ) method. This includes a string, an int and a class type. The WriteLine( ) method has been written to accept a string followed by a params array of object class. The declaration of WriteLine( ) is as follows: WriteLine ( string s, params object[ ] o ) ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Working With GDI+ We would see how to draw text and graphics using GDI+ by writing a small program. Create a Windows Application. Windows programmers know that a window receives WM_PAINT message when it is to be painted. We need to handle this message if we want to do any painting in the window. In .NET to do this we can either override the virtual method OnPaint( ) of the Form class or write a handler for the Paint event. The base class implementation of OnPaint( ) invokes the Paint event handler through delegate. Hence we should write our code in the Paint event handler. Add the Paint handler to the form. The Form1_Paint( ) handler would look like this. private void Form1_Paint ( object sender, PaintEventArgs e ) { } The first parameter passed to the Form1_Paint( ) handler contains the reference to the object of a control that sends the event. The second parameter contains more information about the Paint event. We would first see how to display a string on the form. To display the string we would use DrawString( ) method of the Graphics class. private void Form1_Paint ( object sender, PaintEventArgs e ) { Graphics g = e.Graphics ; Font myfont = new Font ( "Times New Roman", 60 ) ; StringFormat f = new StringFormat( ) ; f.Alignment = StringAlignment.Center ; f.LineAlignment = StringAlignment.Center ; g.DrawString ( "Hello!", myfont, Brushes.Blue, ClientRectangle, f ) ; } The Graphics property of the PaintEventArgs class contains reference to the Graphics object. We can use this reference for drawing. In a handler other than Paint event handler we can obtain the Graphics reference using the CreateGraphics( ) method of the Form class. The DrawString( ) method has several overloaded versions. We used one that allows us to display centrally aligned text in desired font and color. The first parameter passed to the DrawString( ) method is the string we wish to display. The second parameter is the font in which text would get displayed. We have created a font by passing the font name and font size to the constructor of the Font class. The text gets filled with the brush color specified as the third parameter. The fourth parameter specifies the surrounding rectangle. We have passed ClientRectangle property of Form class that contains a rectangle representing the client area of the form. To centrally align the text we have used the StringFormat class. The Alignment and LineAlignment properties of this class contain horizontal and vertical alignment of text respectively. The Graphics class contains various methods to draw different shapes. This includes drawing rectangle, line, arc, bezier, curve, pie, etc. We would add the code in Form1_Paint( ) handler that draws rectangles in different pens and brushes. You would be able to draw other shapes on similar lines. The following code draws a rectangle using green colored pen having line thickness of 3. Pen p = new Pen ( Color.Green, 3 ) ; g.DrawRectangle ( p, 20, 20, 150, 100 ) ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Reflection allows us to either read data from assembly or write data to assemblies. The System.Reflection namespace contains classes to read an assembly, whereas, System.Reflection.Emit namespace contains classes to write to the assembly. In this article, we would firstly create an application that lists all the types of selected assembly. Then, on selecting a type its members get displayed. Create a Windows Application and design a form as shown in the following figure.
Compiled by rmshankar@yahoo.com
The variables and events of different controls in the form are given in the following table. Control TextBox Load Button Types ListBox Methods and Constructors ListBox Properties ListBox Events ListBox Variable aname load list listmethods listprop listeve Click SelectedValueChanged Event
Also add the OpenFileDialog control to the form. On clicking the 'Load' button the standard 'Open' dialog box gets displayed. If user selects an assembly and clicks the OK button, its path gets displayed in the text box, the assembly gets loaded in memory and its types get displayed in the list box. To do this, we have added the Click event handler as shown below. private void load_Click ( object sender, System.EventArgs e ) { openFileDialog1.InitialDirectory = @"C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705" ; openFileDialog1.Filter = "Assemblies (*.dll)|*.dll" ; if ( openFileDialog1.ShowDialog( ) == DialogResult.OK ) { list.Items.Clear( ) ; aname.Text = openFileDialog1.FileName ; Assembly a ; try { a = Assembly.LoadFrom ( aname.Text ) ; tarray = a.GetExportedTypes( ) ; } catch ( Exception ex ) {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Also add the OpenFileDialog and ColorDialog controls to the form. Name them as file and color respectively. The 'Choose Bitmap' button allows user to select an image file through the 'Open' file dialog. The 'Choose Color' button lets the user to select a foreground color through the standard 'Color' dialog.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
This application consists of two buttons named Start and Hit, and three textboxes named num1, num2 and num3. The user needs to click on the Start button to start the game. As soon as this button is clicked, random numbers would get displayed on the three textboxes. Now at any instance if the user clicks on the Hit button, the display of numbers stops. If the numbers turn out to be the same the user hits the jackpot. It is impossible to generate and display the random numbers in the three textboxes simultaneously in the main thread. If we attempt to do so, numbers in the second textbox would get generated only after generating and displaying numbers in the first textbox. So here if we want concurrent functionality, we need to generate and display the numbers for the textboxes in three different threads. On clicking the Start button, the three threads get launched as shown in the following code snippet: private void start_Click ( object sender, System.EventArgs e ) { t1 = new Thread ( new ThreadStart ( this.display1 ) ) ; t1.Start( ) ; t2 = new Thread ( new ThreadStart ( this.display2 ) ) ; t2.Start( ) ; t3 = new Thread ( new ThreadStart ( this.display3 ) ) ; t3.Start( ) ; } We have added the references t1, t2 and t3 of the Thread class as data members of the Form1 class. The display1( ) method is given below.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Here we have added a textbox named quantity, a button called purchase and a label called msg. In this application we have simply asked the user number of goods he wants to purchase, i.e. the demand. We have maintained number of goods in stock in a file called log.bin. Whenever the user purchases certain amount of goods, the number in the file is updated. In this application we have also launched another thread which keeps on checking continuously whether the goods are out of stock or not. If the thread finds that the number of goods in the store is zero, it fills the store with hundred goods and hence updates the number in log.bin file. We need to synchronize the two threads so that only one thread works on log.bin at one time. We added the following as data members of the Form1 class. FileInfo f ; FileStream fs ; byte total = 100 ; total denotes the total number of goods in store. We have used a value like 100 that can be represented in one byte. This is because FileStream is used to write an array of bytes in the file and if we take a larger number, we would have to first create an array of bytes representing the large number. For the sake of simplicity here we have used a number that can be represented in one byte. We initialized the reference f, and launched the thread that would keep on checking the stock from time to time after the call to the InitializeComponent( ) method in the constructor as shown below: f = new FileInfo ( "C:\\log.bin" ) ; Thread t = new Thread ( new ThreadStart ( checker ) ) ; t.IsBackground = true ; t.Start( ) ; We have made this thread a background thread because we wish that as soon as the application terminates, the thread should also get terminated. The checker( ) method is given below: public void checker( ) { while ( true ) { lock ( f ) {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The following table shows the controls and their Names. Control Server Text Box Port Text Box Listen As Server Button Connect As Client Button File Name Text Box Open Button Text Box Name Tserver tport bserver bclient fname bopen text
Both the users have to start the same application. Out of the two, one should listen as server and another should connect as client. It is necessary to listen as server before connecting as a client, otherwise the client would get an exception. To be able to listen as server, the user has to enter the port number (any integer value) and click the 'Listen As Server' button. The client must enter both the server name (name of machine on which server application is running) and the same port number and then click the 'Connect As Client' button. The client now can enter the file name with entire path in the 'Enter File Name' text box and click the 'Open' button. As soon as the client clicks the 'Open' button a request to send the specified file is sent to the server and the file contents are received back from the server. Let us now add the handlers and write code in them. First of all we would add the Click event handler for the 'Listen As Server' button. The code of the handler is given below. private void bserver_Click ( object sender, System.EventArgs e ) {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The Quizmaster asks a question by typing it in the 'Post a Question' text box named que. He is also supposed to provide an answer to cross check the answers supplied by the players in the
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The PE file 'a.dll' is said to be stored in a module of the 'mydll.dll' assembly. Had 'mydll.dll' contained resources, they would also get added in the structure with the type metadata and manifest. The 'assembly description' shown in manifest contains the identity of the assembly, consisting of its name, version and culture. An assembly has a four part version number e.g. 1.0.1.1. The parts are <Major> . <Minor> . <Build> . <Revision>. Other contents are the names of all the files in the assembly, information regarding whether all the types defined in the assembly are visible to other assemblies or private to one, a hash of all files in the assembly and details of any security permissions that clients need to have in order to be able to run the assembly. Private and Shared Assemblies We can create two types of assemblies-private assemblies and shared assemblies. A private assembly is used by only one application while a shared assembly is shared amongst different applications. By default when we compile a C# program, the assembly produced will be a private assembly. This assembly (DLL/EXE) should be placed in the same folder as the calling application. With a private assembly it's not necessary to think about naming conflicts with other classes or versioning problems because each application has its own copy of the assembly. In shared assemblies we have to ensure that the assembly is unique, and therefore, have a unique name (called strong name). In this article we would see how to build and use a shared assembly. We plan to write a class library consisting of a function called display( ). We will call this function from a client program, which we will create later. Here is code of the display( ) method which is defined in the mytext class. public class mytext { public void display ( Form fr, string s, Color c, string fname, int size, Point pt ) { Graphics g = fr.CreateGraphics( ) ; Font myfont = new Font ( fname, size) ; SolidBrush mybrush = new SolidBrush ( c ) ; g.DrawString ( s, myfont, mybrush, pt ) ; } }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Along with the strong name, the compiler also generates a cryptographic hash from the names and contents of the files in the assembly. The compiler then encrypts the cryptographic hash for the assembly using the private key (available in mykey.snk). It places the encrypted hash in the manifest of the assembly. This hash would be used by the client to check the authenticity of the assembly. So, in all, two things are written inside the manifest, the strong name and the encrypted hash of the names and contents of the files. The process of writing the encrypted hash value in the manifest is called 'Signing of an assembly'. Now our shared assembly is ready. To make it available to all the clients we would have to install it in the Global Assembly Cache. All the shared assemblies available on a system are stored in the Global Assembly Cache. This store is located in the <drive>:\Windows\Assembly folder. Installing The Shared Assembly To install a shared assembly in the global cache we would have to use the Global Assembly Cache utility tool called gacutil along with the /i option. Here /i stands for install. This is what we must type at the command prompt to install the assembly. C:\CSharp\fontassembly\bin\Debug>gacutil /i fontassembly.dll If the assembly is successfully installed, the following message would appear: Assembly successfully added to the cache Building The Client Let us now build a client that would use the assembly that we created above. To create the client select a 'Windows Application' project and name it as fontclient When we click on the form, some text should be displayed at the position where we click. This can be achieved by calling the display( ) method from 'fontassembly.dll' in the Form1_MouseDown( ) handler. To have access to this method we have added a reference of the mytext class as a data member of the Form1 class. The Form1_MouseDown( ) handler is shown below. private void myform_MouseDown ( object sender, System.Windows.Forms.MouseEventArgs e ) { if ( e.Button == MouseButtons.Left ) { Point pt = new Point ( e.X, e.Y ) ; t.display ( this, "Hello", Color.Red, "Comic Sans MS", 30, pt ) ; } } Here we have first checked whether the left mouse button has been clicked. If so then we have called the display( ) method of the mytext class from the fontassembly assembly. For the mytext class to become available we have added the statement using fontassembly ;. However this is not enough. We also need to add a reference to the library. To do this we should right click on 'References' in the Solution Explorer window and select 'Add References'. On doing so the 'Add References' window would appear. Execute the program and click on the form, a string "Hello" would appear at the point where mouse is clicked.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
After this much is done, we have added code to the constructor of the form class to display a quote and a picture in the form. The constructor is given below: public Form1( ) { InitializeComponent( ) ; Assembly asm = Assembly.GetExecutingAssembly ( ) ; ResourceManager rm = new ResourceManager ( "resclient.quotes", asm ) ; Random r = new Random( ) ; string str ; int i = r.Next ( 4 ) ; str = string.Format ( "img{0}", i ) ; pic.Image = ( Image ) rm.GetObject ( str ) ; i = r.Next ( 4 ) ; str = string.Format ( "quo{0}", i ) ; tip.Text = ( string ) rm.GetObject ( str ) ; } To use the embedded resource, we have used the ResourceManager class defined in the System.Resources namespace. We need to pass the reference of the Assembly class where the resources are embedded to the constructor of the ResourceManager class. In this case the file is embedded in the executing assembly, so we have passed the result of Assembly.GetExecutingAssembly( ) as the second argument. The first argument is the root name of the resource file. The root name is made of the namespace followed by the name of the resource file without extension. We have collected the reference of this ResourceManager object in rm. To extract a resource from the file we have used the GetObject( ) method. We have passed a key to this method. This method returns us the object associated with the key specified. To create the key we have used the Random class's Next( ) method that would return any number between 0 and 4 (0 & 4 inclusive). Next we have set the Image property of pic and Text property of quote to the Image and string objects respectively returned by the GetObject( ) method. The output of this application is shown in the following figure.
Compiled by rmshankar@yahoo.com
Every time we execute this application we get a different picture and quote on the form.
Compiled by rmshankar@yahoo.com
The dark gray colored control is the 'DataGrid' control. The controls, their Names and handlers are given in the following table. Control Name DataGrid dg Write Button wb Clear Button cb Read Button rb TextBox xmltext Handler Click Click Click -
First of all we would look at the Click event handler for the 'Write' button. private void wb_Click ( object sender, System.EventArgs e ) { String constr = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\book.mdb" ; OleDbConnection con = new OleDbConnection ( constr ) ; con.Open( ) ; String comstr = "SELECT Name, Email, Phone FROM addressbook" ; OleDbCommand com = new OleDbCommand ( comstr, con ) ; OleDbDataAdapter adapt = new OleDbDataAdapter ( com ) ; adapt.Fill ( dset, "addressbook" ) ; dg.SetDataBinding ( dset, "addressbook" ) ; dset.WriteXml ( "addressbook.xml" ) ; xmltext.Text = dset.GetXml( ) ; con.Close( ) ; }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Note that we must add the following declarations at the beginning of the program. using System.Data.OleDb ; using System.IO ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
We would now create the client. Create a Windows application and design the form as shown in the following figure.
Note that in order to run the application we must first download and install Microsoft Agent software from the website www.microsoft.com/products/msagent/downloads.htm. Next we need to add them to the toolbox by right clicking on the Toolbox and selecting Customize Toolbox. From the dialog box that would appear we need to select Microsoft Agent Control 2.0 and then click on OK. On doing so the Microsoft Agent control would get added to the toolbox. Next we need to drag the control on the form. On dragging the Microsoft Agent control an object of the type AxAgent class that belongs to the AxAgentObjects namespace gets added as data member of our Form1 class. Following table shows the controls and their properties.
Control TextBox Speak button Peedy Radiobutton Merlin Radiobutton ComboBox Change button Agent Add the following code to the constructor.
String loc = @"C:\WINNT\msagent\chars\" ; agent.Characters.Load ( "Merlin", loc + "merlin.acs" ) ; agent.Characters.Load ( "Peedy", loc + "peedy.acs" ) ; speaker = agent.Characters [ "Peedy" ] ; loadmoods( ) ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
As soon as the user selects some mood from the combo box, the mood_SelectedIndexChanged( ) event handler gets invoked. This handler is given below. void mood_SelectedIndexChanged ( object sender, System.EventArgs e ) { speaker.StopAll ( "Play" ) ; speaker.Play ( mood.Text ) ; speaker.Play ( "RestPose" ) ; } In this handler we have first stopped all the animations presently playing using the StopAll( ) method. Next we have played the selected mood from the combo box using the Play( ) method. To this method we have passed the name of animation to play. After this we have played the Rest Pose animation, which indicates an idle position of the character. If we type something in the textbox and click on the Speak button the speak_Click( ) event handler gets called. Here we have first played the animation selected by the user and then played the text written by the user using the Speak( ) method. Here is the handler. void speak_Click ( object sender, System.EventArgs e ) { speaker.Play ( mood.Text ) ; speaker.Speak ( speechtext.Text, "" ) ; } The jobs that are remaining are adding the user control and writing an event handler for it. Add the user control by right clicking on the Toolbox and selecting Customize Toolbox. From the dialog box that would appear select the .NET Framework Components tab. Click the Browse button. From the Browse dialog select the ClockControl.dll and click Open. The user control would get added to the list of controls. Dismiss the dialog by clicking on OK. It would appear on the Toolbox. Drag and drop it on the form. Name it as c. Set the Alarmtime and Message property of the control through the Properties window. First of all we need to start the timer in the constructor of the Form1 class by calling the start( ) method of the control. Do so as given below. c.start( ) ; We also need to add an event handler to handle the d event of the control. Do so through Properties window. The code in this handler is shown below. void c_d ( object sender, ClockControl.TimeEventArgs e ) { int i ; for ( i = 0 ; i < 5 ; i++ ) speaker.Speak ( e.msg, "" ) ; } The TimeEventArgs object would contain the message to be displayed in the msg data member. In the event handler we have simply made the character speak out the message five times.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Name the radio buttons as reng, rger, rita, and rfre respectively. Name the Display button as bdisplay. Add the Click event handler for the Display button. Here is the handler. void bdisplay_Click (object sender, System.EventArgs e ) { Thread t = Thread.CurrentThread ; if ( rfre.Checked ) t.CurrentUICulture = new CultureInfo ( "fr-FR" ) ; if ( rger.Checked ) t.CurrentUICulture = new CultureInfo ( "de-DE" ) ; if ( rita.Checked ) t.CurrentUICulture = new CultureInfo ( "it-IT" ) ; if ( reng.Checked ) t.CurrentUICulture = new CultureInfo ( "en-US" ) ; greetform g = new greetform( ) ; g.ShowDialog( ) ; } Here, we have only checked which radio button the user has selected and set the UI culture accordingly. After this we have displayed another form. We need to add this form to the project. Add controls to this form as shown below.
Compiled by rmshankar@yahoo.com
The controls and their names are given in the following table. Control Name text box Greet button Label Close button Name tname bgreet lgreet bclose
Add the Click event handlers for the Greet and Close buttons. The bgreet_Click( ) handler is given below. void bgreet_Click ( object sender, System.EventArgs e ) { String s ; DateTime t = DateTime.Now ; }
Following table shows the data to be added to German and Italian resource files.
Compiled by rmshankar@yahoo.com
Now you can run the program. Select a language and display the greetform. The greetform in Italian is shown in the following figure.
But there is a problem in this output. Although resources are appearing in Italian, the greeting message is still in English. This is because, when we localize resources, an entry is made in their properties to extract proper resource from appropriate resource file. Since welcome messages are string literals their properties are not changed. We have to do this job ourselves. We also need to make few changes in the program. Add the following translations in the resource files for German, French and Italian. Name French GoodMorning GoodAfternoon GoodEvening German GoodMorning GoodAfternoon GoodEvening Italian GoodMorning GoodAfternoon GoodEvening Value Bonjour Bonsoir Bonaprsmidi Guten Morgen Guten Tag Guten Abend Boungiorno Bounpomeriggio Buonasera
Compiled by rmshankar@yahoo.com
private void bgreet_Click ( object sender, System.EventArgs e ) { ResourceManager r = new ResourceManager ( "locale_greet.greetform", Assembly.GetExecutingAssembly( ) ) ; String s ; DateTime t = DateTime.Now ; if ( t.Hour <= 12 ) s = r.GetString ( "GoodMorning" ) ; else { if ( t.Hour <= 19 ) s = r.GetString ( "GoodAfternoon" ) ; else s = r.GetString ( "GoodEvening" ) ; } s += " " + tname.Text ; lgreet.Text = s ; } The ResourceManager class provides methods to work with culture specific resources at runtime. The locale_greet.greetform is the root name of the resources (If resource file name is MyResource.en-US.resources then root name is MyResource) that we want to access from the current assembly. We have specified fully qualified name of the resource file. We have used the ResourceManager.GetString( ) method to extract the value of the resource passed to it as parameter. Use the System.Resources and System.Reflection namespace for the ResourceManager and Assembly classes respectively. Now run the program again and confirm that the greetings are displayed in the chosen language. Behind The Scene Let us see what happens behind the scene when we localize the form, select the language and compile the program. When we set the Localizable property to true, information about all the resource strings, properties, embedded pictures, etc. gets stored in the root resource file i.e greetform.resx. The following statement gets added to the InitializeComponent( ) method. ResourceManager resources = new ResourceManager( typeof ( greetform ) ) ; The type greetform provided to the constructor is used to gather all information like assembly name, root name of resource, etc. for finding the resources. Instead of assigning values directly to the properties, methods like GetString( ), GetObject( ) are used to retrieve the strings and pictures from the resource file. Before retrieving the values, the CurrentUICulture property is checked for the current culture. On compilation, for every localized resource separate assembly called satellite assembly gets
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Stack Walk Stack walks are an essential part of the security system. A stack walk operates in the following manner. Every time a method is called a new activation record will be put on the stack. This record contains the parameters passed to the method, if any, the address to return to when this function completes and any local variables. At certain stages during execution, the thread might need to access a system resource, such as the file system. Before allowing this access the protected resource may demand a stack walk to verify that all functions in the call chain have permission to access the system resource. At this stage a stack walk will occur and each activation record is checked to see that callers do indeed have the required permission. Principal In case of role-based security, the code can perform actions based on the data it collects about the user. It is best when used in conjunction with Windows 2000 accounts. The heart of Role based security lies the Principal (identity and role of the user). Role based security is most useful in situations where access to resources is an issue. Consider a bank, where everyone needs to log into a software in order to use it. Access to records will depend on the role of the user trying to access it. A clerk will login with a different role than the manager, hence he will not be allowed access to personal data of various customers whereas the manager might have the powers to modify them if necessary. These situations are very common and hence .NET provides easy ways to implement security on the basis of roles. .NET allows developers to use role based security as attributes freeing the business logic from the responsibility of performing security checks. Let us now put the role-based security model to work in an application. This application retrieves personal information about employees that is stored in a database. User will be allowed to view the database only if he has an administrative login on that computer. Create a Windows application and design the form as shown in following figure
Change the names of the controls as shown in the following table Control Employee ID First Name Last Name City Lookup button Exit button Name empid fname lname city lookup exit
Compiled by rmshankar@yahoo.com
Documents downloaded from www.funducode.com Article: C#- Role Based Security Model - II
Now, add the Click event handler for the Lookup button. Add the code given below in this handler. private void lookup_Click ( object sender, System.EventArgs e ) { SqlDataReader dr = null ; SqlConnection con = new SqlConnection ((@"server=(local)\NetSDK;Trusted_Connection=yes;database=backup" )); SqlCommand com = new SqlCommand ( "Select * from Employees",con ) ; con.Open( ) ; dr = com.ExecuteReader( ) ; while ( dr.Read( ) ) { if ( empid.Text == dr [ "EmployeeID" ].ToString( ) ) { fname.Text = dr [ "FirstName" ].ToString( ) ; lname.Text = dr [ "LastName" ].ToString( ) ; city.Text = dr [ "City" ].ToString( ) ; } } con.Close( ) ; }
Here, we have created three basic objects required to deal with databasedr, com and con of type SqlDataReader, SqlCommand and SqlConnection respectively. We have then used the ExecuteReader( ) method of the command object to execute the command and collected the result in dr. Then we have iterated through the record set till we find the record whose Employee ID matches with the one user has asked for. Once the record is found we have displayed it in the text boxes. Add an event handler for the Load event and write code in it as given below.
private void Form1_Load ( object sender, System.EventArgs e ) { AppDomain.CurrentDomain.SetPrincipalPolicy ( PrincipalPolicy.WindowsPrincipal ) ; WindowsPrincipal p = ( WindowsPrincipal ) Thread.CurrentPrincipal ; lookup.Enabled = p.IsInRole ( WindowsBuiltInRole.Administrator ) ; } In this handler to begin with we have set the principal of the current application domain. The method SetPrincipalPolicy( ) is used for this purpose. To access the current domain we have used the CurrentDomain property of the AppDomain class. It returns a reference to the application domain in which our application is running. We have passed the PrincipalPolicy.WindowsPrincipal to this method. PrincipalPolicy is an enumeration in the System.Security.Principal namespace. PrincipalPolicy enumeration holds three types NoPrincipal, UnauthenticatedPrincipal and WindowsPrincipal. Of these three, the WindowsPrincipal holds the identity of the current user logged on to Windows. In the next statement we have created a reference to an object of type WindowsPrincipal. The
Compiled by rmshankar@yahoo.com
Lastly add the Click event handler for the Exit button and call Dispose( ) method from it to close the form. Note that we must use System.Threading, System.SqlClient and System.Principal namespaces to run the program.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The details of the controls are given in the following table. Control TextBox TextBox TextBox TestBox TextBox TextBox TextBox TextBox TextBox RadioButtonList Button Name uid pass cpass sname address state zip country mail course submit
The controls appearing in red color are called validation controls. Whenever we enter something on the form and submit it to the server it is called a postback. Validation controls provide a method of validating user input without writing any code. Whenever postback is initiated (i.e. we click the Submit Form button) each control checks the control it is validating and changes its IsValid property accordingly. If the property is set to false it means that the user input is wrong. In
Compiled by rmshankar@yahoo.com
The pass textbox would accept a password. Generally a password is something that should not be visible hence we need to change the TextMode property of this textbox to Password. Now whatever the student types in this textbox is substituted by *s. We must now change the properties of validation controls. How to do this would be discussed next week.
Compiled by rmshankar@yahoo.com
We have used the OLEDB .NET Data provider in this case with a disconnected approach and the data source is the online.mdb file stored in the local drive. In this handler we have created the connection string, the command string, the OleDbDataAdapter object and the DataSet object. Next we have filled the DataSet with the table from the database and extracted the Table in a DataTable object referred to by dt. Then we have created a new DataRow object. We have initialized the row fields with the text entered in the corresponding textboxes containing the students information. Next we have added the row to the DataTable object referred to by dt. Then we have created an OleDbCommandBuilder object and updated the database using the Update( ) method. After doing this we have used the static method called Redirect( ) of the Response class to browse to a different page called Confirm.aspx. We can create the Confirm.aspx file by simply adding another Webform (.aspx file) to the project (through Solution Explorer), naming it Confirm.aspx and adding the text to it. Compilation We are now all set to compile the program. We need to do so using Build | Compile menu option. On compiling the HTML tags present in the WebForm1.aspx file and the code in the WebForm1.aspx.cs file called the code-behind file, a new intermediate file would get created. This file contains a class written in C# and is derived from the WebForm1 class that contains code to emit HTML from ASP.NET tags. This class gets compiled to a Registration.dll file. Here we have chosen to deploy our files on the local machine. But if we plan to deploy it on the Web Server, we need to copy the .aspx and .aspx.cs files into the virtual directory. We can also copy the Registration.dll file but this is optional because if the file is not deployed, it gets created and cached in the web server as soon as the first request is made. The process of compilation is shown in the following figure.
Let us now see the WebForm1.aspx file in HTML view. This file contains the ASP.NET tags for our application. The first line of this file is known as the @Page directive. This directive is given below.
Compiled by rmshankar@yahoo.com
<%@ Page Language = "c#" Codebehind = "WebForm1.aspx.cs" Inherits = "Registration.WebForm1"%> This directive defines general attributes and compilation settings for ASPX files (for example, C# or VB). It also specifies the code behind file and the base class from which the intermediate class was derived. Sending A Request Now, if a client wants to send a request for executing the program that we developed, he can do so by starting the browser and mentioning the following URL http://localhost/Registration/WebForm1.aspx This sends a request to the server. On the server, an object of the class present in Registration.dll would get created and an event handler called Page_Load( ) would get called. This handler outputs HTML, which is then rendered on the client browser. Now whenever a student enters information into the registration form and clicks on the Submit Form button, he is presented with the page shown in the following figure.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Name the text box as t, Read button as bread and Exit button as bexit. Add the following code in the constructor of the Form1 class just below the call to InitializeComponent( ) method. FileIOPermission fp ; try { fp = new FileIOPermission( FileIOPermissionAccess.AllAccess, @"C:\" ); fp.Demand( ) ; } catch ( Exception e1 ) { MessageBox.Show ( e1.Message ) ; } Here we create a reference of type FileIOPermission. We have inisialised the reference in the try block. In the constructor we have passed the AllAccess enumerated type to specify that our code needs complete access permissions to the C:\ drive of the machine where our application is to execute. The constructor is followed by a demand for the above permission. It is necessary to place the demand part in a try-catch block because if the permission is denied, the Demand( ) method would raise an exception and our program would be terminated abruptly. Now add a handler for the Read button. Write the code as shown below to it. private void bread_Click ( object sender, EventArgs e ) { StreamReader sr = new StreamReader ( "c:\\hi.txt" ) ; t.Text = sr.ReadLine( ) ; sr.Close( ) ; } We have created a stream reader object to read the c:\hi.txt file. Next we have read a line from that file and displayed it in the text box t. Now add a handler for the Exit button and call Dispose( ) method from it. Calling Dispose( ) would terminate the application if the Exit button is clicked. Finally add the following declarations at the beginning of the program.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
This can be done programmatically by modifying the <authorization> section of the web.config file. Make the following changes to the authentication section <configuration> <system.web> ::: <authorization> <deny users="?" /> </authorization> ::: </system.web> </configuration>
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
We would now write a program that splits a given input string using the specified delimiter. Suppose we have collected e-mail addresses separated by semicolon ( ; ). Then we can split the string into single address as shown in the following code. String instr = "rucha_200@hotmail.com;malviya@yahoo.com;rdeshpande@hotmail.com" ; Regex ex = new Regex ( ";" ) ; string [ ] str = ex.Split ( instr ) ; foreach ( string s in str ) Console.WriteLine ( s ) ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Figure 1 As soon as we click the Print button, the Printing dialog indicating the number of page that is getting printed gets displayed. The salary slip that gets printed is shown in Figure 2.
Figure 2
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Click the View Page button. It will take you to the login page as shown below.
Compiled by rmshankar@yahoo.com
Let us now understand the current business scenario. We would take an example of an airlines company. The customers of the airlines company may access the company through personal computers, PDAs or simple phones. The airlines company may communicate with partners such as a food company or the bank. Partners and clients would still be there but the way they would interact would be different. The airlines company would have a web server to which clients would send requests for ASP or HTML pages. The request would be in form of HTTP request. The Web Server would communicate with the business logic in the application server and use the data bases to store the data. The Web Server would respond by sending HTML back to the clients. The food company and bank organization would have application servers running business logic in the form of components. They would also have data base servers for secured and efficient data storage. If airlines company is to access the business logic exposed by application servers of food company and bank it would do so through Remote Procedure Calls. Also the food company and bank may also be interacting with each other.
Different client organizations would use various software and programming model. Even the Operating Systems installed on the client devices would be different. The client would like to interact with the Web Server using these devices. The Web Server of the Airline company may either have IIS, JWS or Apache server running appropriate sever side scripts. The food company may have COM+ model on their Application servers with business logic implemented as COM components and MS-SQL database. The bank organization may have J2EE model with business logic implemented as EJB components running on their Application Servers and data base in Oracle. In a distributed computing architecture the clients form the Presentation layer and the DCOM components, EJB components, CORBA components and DCOM components form the Business layer. The clients has to cross the firewalls to access components. Firewalls ensure that communication is done through a specified port and data format. The external applications,
Compiled by rmshankar@yahoo.com
The conflict between these models occur mainly due to the Wire Protocol and Data Standard. This was different for each of the infrastructure. CORBA uses IIOP (Inter Internet Object Protocol), DCOM uses RPC (Remote Procedure Calls) and EJB uses RMI (Remote Method Invocation) / IIOP. All these protocols are non-standard protocols and hence are not followed by all companies. These existing Distributed Computing solutions suffer from various problems. For example, DCOM is a proprietary protocol. It does not support interoperability and it has firewall problems because DCOM transfers data in binary format and it uses many ports to call remote functions. CORBA uses IIOP protocol, which is non-internet friendly. EJB requires very costly infrastructure. Moreover all these object models require their client to use the same libraries as that used on server. This makes a very tight coupling between client and the component. If component is changed and written using new object model the client will also have to change. To address these needs, XML Web services came into existence and were introduced as part of ASP.NET, which is part of the .NET Framework. Web services are based on open Industry standards, such as HTTP, XML, and SOAP. Using these open standards, Web services deliver application functionality across the Web to any type of client, on any platform. XML Web services are based on open Web standards that are broadly supported and are used for communication and data formats. XML Web services provide the ability to expose application logic as URI-addressable resources, available to any client in a platform-independent way. Web services are self-describing. Any clients incorporating open Web standards for communication and data formatting (HTTP and XML) can query dynamically for Web service information and retrieve an XML document describing the location and interfaces supported by a particular XML Web service. These open standards make Web services indifferent to the operating system, object model, and programming language used. Web services are accessible to disparate systems, supporting application interoperability to an unprecedented level thanks to the ubiquity of HTTP and XML. Instead of communicating in binary formats between applications, Web services use XMLencoded messages. Because XML-based messaging is used for the data interchange, a high level of abstraction exists between a Web service implementation and the client. This frees the client from needing to know anything about a Web service except for its location, method
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Here, HelloWorld is a Web service. The attribute [WebMethod] enables the method from being called by the clients through network.We would add our web methods and create a Winform client next time.
Compiled by rmshankar@yahoo.com
Note that the 'Address' bar contains the URL 'http://localhost/webservice/Service1.asmx'. The '.asmx' file acts as an entry point to the Web service. The statement written in the 'Service1.asmx' file is given below: <%@ WebService Language="c#" Codebehind="Service1.asmx.cs" Class="webservice.temperature" %> Here, WebService is an ASP.NET tag, which states that the code written in the specified class is to be exposed as a web Service. The Codebehind tag specifies the name of source file in which Web service is defined. We can omit this tag and write the Web service code in '.asmx' file itself. In fact, defining the Web service in '.asmx' file itself facilitates the deployment of the service. The 'Service1.asmx' file contains fully qualified name of class (webservice.temperature) in which our methods ctof( ) and ftoc( ) are defined. When the '.asmx' file is executed all those methods which are exposed as Web service using the [ WebMethod ] attribute get displayed in the output window. If we click the ctof link a page as shown in the following figure gets displayed.
Compiled by rmshankar@yahoo.com
Name the text box as ttemp, label as ltemp and buttons as cb and fb respectively. We must add a reference to the 'webservice.dll' we are going to use in this application. For this, right click on the project name in the 'Solution Explorer' and select 'Add Web References' from the pop-up menu. The window given below would appear.
Enter the address as 'http:\\localhost\webservice\Service1.asmx'. To use a Web service, which is available in different machine, say User1, add its web reference by specifying the URL as http://User1/webservice/Service1.asmx. Click the arrow present on the right side of the 'Address' text box. A dialog box displaying a page with links to the web methods gets displayed. Click the 'Add Reference' button on the dialog box. On doing this, a folder 'WebReferences\localhost' gets created in the project directory. In the 'Localhost' folder four files namely, 'Reference.cs', 'Reference.map', 'Service1.wsdl' and
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
We have changed the background color of the table, font and font size 'Build Style' option. Select this option from the pop-up menu that appears after right clicking on the form. We have also changed the background colors of the label and button control by changing their respective properties. Change the names of controls as shown in the following table. Control Text box Celsius button Farehnheight button Label Name ttemp cb fb ltemp
The form stands created. Now we would add the reference of the Web Service assembly in our project. For this, right click in the 'Solution Explorer' and select 'Add Web Reference' option from the pop-up menu. On selecting this option, the 'Add Web Reference' window gets displayed. Enter the address as 'http:\\localhost\webservice\Service1.asmx' (Name of the temperature Web Service project is 'webservice'). Click the 'Add Reference' button on the dialog box. On adding the reference a folder 'Web References\localhost' gets created in the project directory containing the four files namely, 'Reference.cs', 'Reference.map', 'Service1.wsdl' and 'Service1.disco'. Rename the namespace 'localhost' to 'currencyservice'. For this, right click the 'Web References\Localhost' in the Solution Explorer and select 'Rename' from the pop-up menu. Also add the reference to the currencyservice namespace at the beginning of the program: using temperatureclient.currencyservice ; Add the Click event handlers for both the buttons. These button handlers are given below: private void cb_Click ( object sender, EventArgs e ) { temperature t = new temperature( ) ; double f = Double.Parse ( ttemp.Text ) ; double d = t.ftoc ( f ) ; ltemp.Text = d.ToString( ) ; } private void fb_Click ( object sender, EventArgs e ) { temperature t = new temperature( ) ; double c = Double.Parse ( ttemp.Text ) ;
Compiled by rmshankar@yahoo.com
Synchronous & Asynchronous Communication Web Services support both synchronous and asynchronous communication between the client and the server that hosts the Web Service. Under synchronous communication, the client sends a request to the server and waits for the response. This prevents the client from performing other operations while waiting for the results. On the other hand, in the asynchronous communication, the client continues processing other tasks as it waits for a response. The client responds to the result of the service request when it becomes available. When a proxy class is created by .NET using the wsdl tool, it generates the synchronous and asynchronous versions of the methods in the class. The asynchronous versions consist of two methods having names as Beginmethodname and Endmethodname. The Begin method is used to initiate the Web Service, while the End method is used to retrieve the results. The handler cb_Click( ) is given below that shows how to make asynchronous call to the ftoc( ) method. private void cb_Click ( object sender, EventArgs e ) { AsyncCallback cb = new AsyncCallback ( ftoccallback ) ; float f = float.Parse ( ttemp.Text ) ; t.Beginftoc ( f, cb, t ) ; // Do some work }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
We have added a textbox called filename to the form and a 'Print' button named print. We have also added the PrintDocument component to our form and renamed it to mypdoc. Add the Click event handler for the 'Print' button. Add the code in it as shown below: private void print_Click ( object sender, System.EventArgs e ) { mypdoc.Print( ) ; } In this handler we have simply called the Print( ) method of the PrintDocument class. Whenever the Print( ) method is called the events are raised. We have not added handlers for the BeginPrint and EndPrint handlers. We have added a handler only for the PrintPage event. If we double click on mypdoc in the component tray of the Windows Form Designer, the mypdoc_PrintPage( ) event handler gets added automatically to the code. This handler is shown below: private void mypdoc_PrintPage ( object sender, System.Drawing.Printing.PrintPageEventArgs e ) { StreamReader reader = new StreamReader ( filename.Text ) ; string str = reader.ReadToEnd( ) ; reader.Close( ) ; Font f = new Font ( "Arial", 10 ) ; e.Graphics.DrawString ( str, f, Brushes.Black, 10, 10 ) ; } PrintPageEventsArgs provides data for the PrintPage event. This data include the Graphics for the printer, the PageSettings for that page, the bounds of the page, and the size of the margins. We have used the Graphics object for printing the text. Here we have created an object referred to by reader of the StreamReader class by passing the file specified in the filename textbox to the constructor of the StreamReader class. To create an object of the StreamReader class we must add using System.IO to our code. Then using this object we have called the ReadToEnd( ) method which reads the stream till the end and returns a string which we collected in str. Next we have created a font object. Then using the DrawString( ) method we printed the string. Printing Graphics From A File Now let us see how to print graphics from a file. To demonstrate this we have created a WinForm application called GraphicsPrint. The UI of this application is same as TextPrint and the print_Click( ) handler is also same. We have made changes only in the mypdoc_PrintPage( ) shown below: private void mypdoc_PrintPage ( object sender, System.Drawing.Printing.PrintPageEventArgs e ) {
Compiled by rmshankar@yahoo.com
In addition to the filename text box and the print button here we have added a multi-line textbox named mytext and a button named open. The idea is that whichever file is displayed in the mytext textbox gets printed even if the words go beyond the margin and pages are more than one. In the open_Click( ) event handler we have used an object of the StreamReader class to read from the specified file. Whatever the StreamReader reads is displayed in the mytext textbox. The handler is shown below: private void open_Click ( object sender, System.EventArgs e ) { StreamReader reader = new StreamReader ( filename.Text ) ; mytext.Text = reader.ReadToEnd( ) ; reader.Close( ) ; } Add the Click event handler for the 'Print' button and add the code in it as shown below:
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Next we have added Click event handlers for all the five buttons. The handler for the browse button is given below. private void browse_Click ( object sender, System.EventArgs e ) { myopendlg.Filter = "Text Files ( *.txt ) | *.txt" ; myopendlg.ShowDialog( ) ; if (myopendlg.FileName != "" ) filename.Text = myopendlg.FileName ; } The 'Browse' button would let the user to select a file for printing. The user would select the file from standard Open File dialog box. We have displayed the dialog box in this handler. The selected file name is displayed in the text box. As soon as the user clicks the 'Open' button the following handler gets called. private void open_Click ( object sender, System.EventArgs e ) { StreamReader reader = new StreamReader ( filename.Text ) ; mytext.Text = reader.ReadToEnd( ) ; reader.Close( ) ; } Here we have read the file contents with the help of an object of the StreamReader class and displayed them on the mytext textbox. Now if the user wants to change the page settings he needs to click the 'Page Settings' button. On doing so the following handler would get called. private void pgsetup_Click ( object sender, System.EventArgs e ) { try { mypgsdlg.PageSettings = ps ; mypgsdlg.ShowDialog( ) ; } catch ( Exception ex ) {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
On clicking the 'Print' button the following handler gets called. private void print_Click ( object sender, System.EventArgs e ) { try { mypdoc.DefaultPageSettings = ps ; str = mytext.Text ; myprintdlg.Document = mypdoc ; if ( myprintdlg.ShowDialog( ) == DialogResult.OK ) mypdoc.Print( ) ; } catch ( Exception ex ) { MessageBox.Show ( ex.Message ) ; } } Here first we have set the DefaultPageSettings property of the PrintDocument class to ps. Next we have collected the text of mytext textbox, which is to be printed in str. The document to be printed is then set to the Document property of the PrintDialog class. Next we displayed the PrintDialog box using the ShowDialog( ) method and if the result happens to be DialogResult.OK, i.e if the user clicks OK, we have called the Print( ) method of the PrintDocument class. On calling the Print( ) method the following handlers get invoked. private void mypdoc_BeginPrint ( object sender, System.Drawing.Printing.PrintEventArgs e ) { f = new Font ( "Arial", 12 ) ; b = new SolidBrush ( Color.Black ) ; strformat.Trimming = StringTrimming.Word ; } private void mypdoc_PrintPage ( object sender, System.Drawing.Printing.PrintPageEventArgs e ) {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
To create a custom control, select 'Windows Control Library' template. Name the project as ClockCtrl. By default a class called UserControl1 gets created, derived from the UserControl class. Change the base class of the control class from UserControl to Control. Also change the name of the control class from UserControl1 to Clock. Next, set the Size property of the control to 120, 120 and BackColor property to Light Blue. To keep track of the time we must add a Timer control. Do so and name it as mytimer. Set the interval time of the timer to 1000 milliseconds (equivalent to one second) and add a handler mytimer_Tick( ) to handle the Tick event that would get generated every second. We would draw the hands and background of control in mytimer_Tick( ) event handler because we need to redraw the control every second. This is the reason why we did not do the painting in the Paint event handler. Let us now see what we have done for drawing the control. On occurrence of every tick we have drawn the clock UI on a bitmap and displayed the bitmap on the control. To draw on the bitmap we first need to obtain the graphics context of the bitmap. We have done this in the constructor of the Clock class. To collect the graphics context we have added a reference g of type Graphics as a data member of the control. We have also added a reference mybmp of type Bitmap to this class. Let us now take a look at the constructor. public Clock( ) { InitializeComponent( ) ; Size sz = this.Size ; mybmp = new Bitmap ( sz.Width, sz.Height ) ; g = Graphics.FromImage ( mybmp ) ; Color bkclr = this.BackColor ; g.Clear ( bkclr ) ; p = new Pen ( Color.Black ) ; b = new SolidBrush ( Color.Purple ) ; }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
To add the control to our form we need to drag it on the form. After adding it to the form, we have changed its name to myclock and set its Locked property to True to lock its size. To start the ticking, we have called the start( ) method of the control in the constructor of the form as shown below: public Form1( ) { InitializeComponent( ) ; myclock.start( ) ; } This starts the timer and the control starts displaying the time.
Compiled by rmshankar@yahoo.com
The idea is to modify the clock control to an alarm clock control. We plan to add two properties AlarmTime and Message to the control. These properties can be set or retrieved programmatically as well as through the Properties Window. The user can set the AlarmTime property to some specific time and as soon as the specified time is reached a message gets displayed. The user can specify the message to be displayed through the Message property. The form data members-altime (of type DateTime) and almessage (of type string)-are controlled by these properties. We have added an event called alarm that would be fired as soon as specified AlarmTime is reached. The AlarmTime and Message properties are given below: [ Category ( "User Defined" ) , Description ( "Controls the Alarm Time" ) ] public DateTime AlarmTime { get { return altime ; } set { altime = value ; } } [ Category ( "User Defined" ), Description ( "Controls the Alarm Message" ) ] public string message { get { return almessage ; } set { almessage = value ; } } Notice the two attributes that we applied to the properties. The Category attribute specifies the category under which the property would get displayed in the Properties window. This would be visible whenever we drag the control on the form and open the Properties window. The Description attribute accepts a String that would get displayed in a small part of the window present at the end of the Properties window. This string describes the property. The Properties window of the control is shown in the following figure.
Compiled by rmshankar@yahoo.com
To add the event we have first added a delegate called NotifyAlarm to the control that accepts two parameters-an object and a TimeEventArgs object. public delegate void NotifyAlarm ( object sender, TimeEventArgs e ) ; TimeEventArgs is a user-defined class. In this class we have added a data member named msg of type String and a one-argument constructor accepting a string that would be stored in msg. The class is shown below: public class TimeEventArgs : EventArgs { public string msg ; public TimeEventArgs ( string s ) { msg = s ; } } Next we added the event as data member of the class as shown below: public event NotifyAlarm alarm ; For the alarm to ring at the specified time, with every minute we must check whether the specified alarm time is equal to the time displayed in our control. We have done the checking in the Tick event handler. The modified Tick event handler is given below. private void mytimer_Tick ( object sender, System.EventArgs e ) { g.TranslateTransform ( 60, 60 ) ; for ( int i = 0 ; i <= 12 ; i++ ) { g.FillRectangle ( b, -2, -45, 4, 5 ) ; g.RotateTransform ( 30 ) ; } g.ResetTransform( ) ;
Compiled by rmshankar@yahoo.com
//seconds p.Width = 1 ; p.EndCap = LineCap.Flat ; p.Color = Color.Red ; g.TranslateTransform ( 60, 60 ) ; g.RotateTransform ( s ) ; g.DrawLine ( p, 0, 0, 0, -40 ) ; g.ResetTransform( ) ; //minutes p.Width = 3 ; p.EndCap = LineCap.Triangle ; p.Color = Color.Blue ; g.TranslateTransform ( 60, 60 ) ; g.RotateTransform ( m ) ; g.DrawLine ( p, 0, 0, 0, -30 ) ; g.ResetTransform( ) ; //hours p.Width = 4 ; g.TranslateTransform ( 60, 60 ) ; g.RotateTransform ( h ) ; g.DrawLine ( p, 0, 0, 0, -20 ) ; g.ResetTransform( ) ; s += 6 ; if (s == 360 ) s=0; sec = sec + 1 ; if (sec == 60) { sec = 0 ; m += 6 ; if (m == 360) m=0; min = min + 1 ; if ( altime.Hour == hr && altime.Minute == min ) { TimeEventArgs t = new TimeEventArgs ( almessage ) ; alarm ( this, t ) ; } h += 0.5f ; if ( h == 360 ) h=0; if ( min == 60 ) { min = 0 ; hr += 1 ; } }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
To select the file click on the 'Browse' button, locate the file and select it. On clicking 'OK', a file with the same name i.e. 'AtlServer.dll' would get created in the 'Debug' sub-directory of our project and would contain the wrapper class called CMath. We can now call the methods of the class as shown in the following code.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Now let us create a non-.NET project that would use this component. We have created our project in VC++. To create this project, click on 'Visual C++ Projects' and select 'Win32 Project'. Name the project as NetClient. On clicking 'OK' the window shown in the following figure would appear. In the 'Application Settings' tab select the 'Console Application' option and click on the 'Finish' button.
We need to add the following code to our project. # include "stdafx.h" # include "iostream.h" # import "C:\dotnet\c#\com-interop\NetServer\bin\Debug\NetServer.tlb" using namespace NetServer ; int _tmain ( int argc, _TCHAR* argv [ ] ) { CoInitialize ( NULL ) ; IMathPtr p ; HRESULT hr = p.CreateInstance ( "NetServer.Math" ) ; if ( FAILED ( hr ) ) { cout << "CreateInstance Failed" << endl ; return 0 ;
Compiled by rmshankar@yahoo.com
The controls and their names are shown in the following table Book Name Textbox Author Textbox Image Textbox Browse button Insert Button book author file browse insert
Using the Browse button the user would select the image file of the book cover. On clicking the Insert button the book information would get stored in the database. First of all to add entries in the table we need to open the connection to the data source. For this
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
. Change the names of controls as shown in the following table. Book Name Label Author Label Picture Box Next Button bookl authorl img next
On clicking on the Next button the information of the next book stored in the database would get displayed. Add the following data members to the Form1 class. string constr ; SqlConnection con ; string cmdstr ; SqlCommand com ; SqlDataReader r ; Initialize them in constructor after the call to the InitializeComponent( ) method as shown below: constr = "server=kicitsqlserver;database=books;uid=sa;pwd = kicit" ; con = new SqlConnection ( constr ) ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
int *x, *y ; in C/C++. Once we've declared the pointers, we can use them as normal pointer variables using the 'address of' (&) and the 'value at address' (*) operators. For the most part, C# relies on references of instances of classes, and the language has been designed in such a way that pointers are not required as often as they are in C/C++. The checked and unchecked operators The checked and unchecked operators can be used to control overflow checking for arithmetic operations and conversions of integer types. If a statement is marked as checked, the CLR enforces overflow checking and throws an exception if an overflow occurs. On the other hand if it is marked unchecked, and overflow occurs, the overflowing bits (higher) are discarded and exception is not thrown. For example, consider the following snippet:
Compiled by rmshankar@yahoo.com
Article C# - Serialization
Serialization is the process of writing objects on a persistent storage media such as a file on the disk. Complementary to serialization is Deserialization using which we can restore objects. Let us see an example where we have used serialization and deserialization to store and retrieve objects of a class to/from a file. Let us discuss the application first. We would create a WindowsApplication and add two menus File and Generate to the form. The File menu would have two menu items. Open and Save. On clicking Generate ten shapes would get generated randomly. We can save them in a file. To save the shapes drawn we would use serialization. While saving the shapes, we should not save the images of the shapes. Instead we should save the relevant information of the shapes using which we should be able to regenerate them again when the file is loaded. This means that we must write the object containing the information about the shape (coordinates of the shape and the color) in the file while saving it and load it back while opening the file. This is done using serialization and deserialization. To be able to represent the shapes we would create three classes-line, rectangle and ellipse. To generate the shapes we would call the draw( ) method of these classes. To be able to call the draw( ) methods of the line, rectangle and ellipse classes using the same call, we would use virtual mechanism. We would declare a class called shapes having an abstract method draw( ). The above mentioned three classes would be derived from the shapes class. These classes would override the draw( ) method. To save the objects on a disk we would create an ArrayList and store the objects of the shapes class in it in the order in which they are drawn. We can then write this array list to the disk. The names of menu items are given in the following table. Menu Open Save Generate Name open save generate
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
MessageBox.Show ( t.Text ) ; (d) Now since our form stands ready we can build it into a class library so that we can export the form. Note that we cannot import a form from an exe file. To build the project in a class library, right click the solution name in Solution Explorer and select Properties. The 'baseform Property Pages' would get displayed. Select the Output Type as Class Library as shown in the following figure.
Now build the project to create 'baseform.dll'. This assembly contains the baseform.Form1 class that we can inherit. Creating Derived Form
Compiled by rmshankar@yahoo.com
(d) The 'Inheritance Picker' dialog would get displayed. This dialog allows us to select an assembly that contains the form we want to inherit. For this, click the 'Browse' button. A dialog would appear from where we can select the 'baseform.dll' file and click the 'Open' button. (e) Clicking the 'Open' button dismisses the dialog and displays the forms exported by the assembly (an assembly can export any number of forms) in 'Specify the component to inherit from' list control. (f) Select the form name from the 'Specify the component to inherit from' list control and click the 'OK' button. As soon as we click the 'OK' button, a new form derived from the 'baseform' gets displayed in the design editor. The file 'Form2.cs' also gets displayed in the Solution Explorer as shown in the following figure.
Compiled by rmshankar@yahoo.com
The figure also displays reference of 'baseform.dll' being added in the 'References' tree in the Solution Explorer. The derived form displays the derived controls being added to the base form. These controls are accompanied by a small icon at the top left corner to distinguish between the derived controls and the new controls. (g) Open the 'Form1.cs' file. Change form name in Application.Run( ) method to Form2 as shown below.
Application.Run ( new Form2( ) ) ; This ensures that when we would execute the application, the new form, i.e. Form2, would get displayed. If we enter the text in the textbox and click the button the text would get displayed in a message box. Let us now see how the whole thing works. To begin with the statement Application.Run ( new Form2( ) ) gets executed. Here we are creating an object of the Form2 class which is derived from the baseform.Form1 class. When we create an object of derived class, base class's constructor gets called. So, in our case constructor of the baseform.Form1 class would get called. This class is accessible to us since a reference to the 'baseform.dll' assembly is already being added to our project. The compiler adds a call to the InitializeComponent( ) method in the constructor of every form class. The InitializeComponent( ) method contains the code for creating and customizing the controls. Once this method gets executed and controls get created, the control returns to the constructor of the Form2 class. This constructor again calls the InitializeComponent( ) method. This time the InitializeComponent( ) method of the Form2 class gets called. This is the reason why derived form contains the derived controls (initialized by InitializeComponent( ) method of the baseform.Form1 class) and the new controls (initialized by InitializeComponent( ) method of the Form2 class). We have already added the Click event handler for the 'Click' button. We can override this handler in the Form2 class and add our code in it. Now if we click the button, firstly, event handler of the base class gets executed and then the overridden handler gets executed. This is because, the InitializeComponent( ) method of the baseform.Form1 class gets executed first, wherein, an address of the Click event handler defined in the baseform.Form1 class gets stored in the Click delegate. Next the InitializeComponent( ) method of the Form2 class gets executed. In it, the address of the Click event handler defined in the Form2 class gets added to the Click delegate.
Compiled by rmshankar@yahoo.com
Documents downloaded from www.funducode.com Article C# - Getting Management Information using WMI
As the enterprise systems, applications, and networks became larger and more complex, the challenge in front of the managers to manage them also increased. In order to solve these problems, Microsoft developed WMI, a scalable management infrastructure and shipped it with Windows 2000. When we implement WMI on Windows platforms, the technology enables the Common Information Model (CIM) designed by the Distributed Management Task Force (DMTF) to represent systems, applications, networks, and other managed components. The CIM Specification describes the modeling language, naming, and mapping techniques used to collect and transfer information from data source and other management models. The CIM schema provides the actual model descriptions and information framework. It defines a set of classes with properties and associations, making it possible to organize information about the managed environment. The key features of WMI are discussed below: (a) Uniform Scripting API: WMI uses the CIM object model to create the managed objects. So, scripts only need to use a single API of WMI to access information for numerous disparate sources. (b) Remote Accessibility: Objects managed within WMI can be used by the applications and scripts running on the local machine as well as on the remote machine. (c) Discovery: Applications and scripts are able to discover what information is available about a system by enumerating the classes that are available. (d) WMI Queries: WMI allows SQL queries to be executed on its objects. (e) Powerful Event Publication: Events can be requested for any change in the managed objects in the system, regardless of whether they support an internal event capability. If you have used WMI in the past, you might be daunted by its complexities as it exposes COM interfaces. You would be happier to know that .NET provided easy to use namespaces and classes that encapsulate the WMI API. We would start with a simple program that displays information of the drive entered by the user. Create a Windows Forms application and design the form as shown below:
Compiled by rmshankar@yahoo.com
We have added few labels and read only text boxes to the form. Give suitable Names to the text boxes. The user would enter the drive name, for example, C: in the text box names as 'Enter Drive Name'. To get the information of the specified drive the user would click the 'GetInfo' button. Add the Click event handler for the button. This handler is given below:
private void binfo_Click ( object sender, System.EventArgs e ) { ManagementClass mc = new ManagementClass ( "Win32_LogicalDisk" ) ; ManagementObjectCollection disks = mc.GetInstances( ) ; foreach ( ManagementObject disk in disks ) { if ( disk [ "Name" ].ToString( ) == tdrive.Text ) { text1.Text = disk [ "DeviceID" ].ToString( ) ; text2.Text = disk [ "DriveType" ].ToString( ) ; text3.Text = disk [ "FileSystem" ].ToString( ) ; text4.Text = disk [ "FreeSpace" ].ToString( ) ; text5.Text = disk [ "MediaType" ].ToString( ) ; text6.Text = disk [ "Size" ].ToString( ) ; text7.Text = disk [ "VolumeName" ].ToString( ) ; text8.Text = disk [ "VolumeSerialNumber" ].ToString( ) ; } } }
Here, we have firstly declared a reference mc to the ManagementClass object. To the constructor of this class we have passed the name of the management class
Compiled by rmshankar@yahoo.com
What we saw in this article is only a tip of the iceberg. In the coming few article we would study the WMI architecture and use more WMI classes to explore the management information.
Compiled by rmshankar@yahoo.com
Let's first study the architecture of WMI. Following figure describes the three-layer model of WMI comprising of providers, the CIM Object Manager (CIMOM), and consumers of WMI information (applications).
The first tier in the WMI architecture is the provider. A provider is a mediator between the system to be managed (for example, operating system, service, application, device driver, and so on) and the CIM object manager. The job of a provider is to extract management information from the underlying data source using whatever interfaces that software presents for management. The management information and interfaces are then mapped by the provider into the object classes that WMI presents to WMI consumers. Moving forward, new and updated managed systems will use providers as a direct way to expose management APIs without significant intermediate conversions. Next is CIMOM, the CIM Object Manager has its own storage repository. It acts as a broker for object requests. CIMOM and its repository are represented on the system by the system service called WinMgmt. Providers plug into CIMOM via a published set of COM interfaces. CIMOM keeps track of what classes are available and what provider is responsible for supplying instances of those classes. When an application requests for management information to CIMOM, it evaluates the request, identifies which provider has the information, and upon getting it returns the data to the consumer. Finally, there are consumers of WMI data. These are the applications requesting for the management information. These consumers, as previously noted, only need to know about the classes of the objects about which they wish to get information. Thus an application or script can call one WMI API function and get a wealth of information about the computer, operating system, applications, devices and even information available via other management protocols like SNMP and DMI. A WMI class exposes properties, methods, events and associations. An application can make use of them for obtaining the management information. Properties supply descriptive information about a particular object of a class. For example, the object of Win32_Process class has a property called Caption that contains the name of the process. The WMI classes provide methods, that an application can call using the object of that class. The WMI object can throw
Compiled by rmshankar@yahoo.com
ManagementClass mc = new ManagementClass ( @"root\cimv2:Win32_Process" ) ; ManagementObjectCollection mobjects = mc.GetInstances( ) ; foreach ( ManagementObject mo in mobjects ) m_list.Items.Add ( mo [ "Caption" ].ToString( ) ) ; Here, firstly we have created a reference to the ManagementClass object passing to it the WMI class name. 'root\cimv2' is the default namespace for System.Management API. Most of the system instrumentation classes reside here. We have retrieved the managed objects by calling the GetInstances( ) method of the ManagementClass class. This method would return the instances of the Win32_Process class, which is the class that represents a Windows process. The instances are returned in a collection, each instance would represent one process. We have then run a foreach loop to access the objects in the collection. We have obtained the name of the process by using the Caption property of the Win32_Process class. Note that we can access the property of this class because an object of ManagementObject class represents the instance of the Win32_Process class. Declare the System.Management namespace at the beginning of the program and add the reference to the 'System.Management.dll' to the project. Now run the program and click the 'Browse' button. All the processes would get listed as shown in the following snap shot.
Compiled by rmshankar@yahoo.com
Change the names of controls as shown in the following table. Control ListView Machine Name TextBox Username TextBox Password TextBox Refresh Button Terminate Process Button Name m_plist m_mname m_uname m_password m_brefresh m_bterminate
When the application is executed, it would display the list of processes and their information of local machine. To view the processes of remote machine, the user should enter the machine name, username and password and click the Refresh button. To terminate the process, the user should select the process from list view control and click the Terminate Process button. Let us first add code to the constructor of the Form1 class after the call to InitializeComponent( ) method to display processes of the current machine.
ManagementClass mc = new ManagementClass ( @"root\cimv2:Win32_Process" ) ; ManagementObjectCollection mobjects = mc.GetInstances( ) ; addprocesses ( mobjects ) ; The object collection returned by the GetInstances( ) method is passed to a user-defined function addprocesses( ). We have separated code to add the processes in a function, because we need to execute the same code again when user clicks the Refresh button. The addprocesses( ) function is given below:
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
We can now enter the machine name, user name and password and click the Refresh button to view the processes of that machine. We would see the Refresh button handler next time.
Compiled by rmshankar@yahoo.com
private void m1_DrawItem ( object sender, DrawItemEventArgs e ) { e.Graphics.FillRectangle ( SystemBrushes.Control, e.Bounds ) ; e.Graphics.DrawIcon ( new Icon ( "C:\\icon1.ico" ), e.Bounds.Left + 3, e.Bounds.Top + 3 ) ; Brush br = new SolidBrush ( Color.Blue ) ; e.Graphics.DrawString ( "Red", new Font ( "Courier New", 9 ), br, ( float )( e.Bounds.Left + 35 ), ( float ) ( e.Bounds.Top + 2 ) ) ; } The DrawItemEventArgs class contains all the information needed for the user to paint the specified item, including the item index, the Rectangle and the Graphics on which the drawing should be done. In this handler, firstly, we have filled the bounds of the menu item with the standard control color. This is necessary to display the bounding rectangle around the icon. Otherwise the icons will get mixed up. Next, we have drawn the icon on the menu item using the DrawIcon( ) method. We have left the suitable number of pixels from left and top of the icon. Next to the icon we have displayed the string mentioning the color name. While drawing the string, we must leave the space where icon has been drawn. We must also keep suitable distance from icon. Thats why we have left 35 pixels from left side of the menu item bounds. The MeasureItem and DrawItem event handlers for the other two menu items are same. Only the icon files are different. Add the Click event handlers for the menu items and set the BackColor property of the form to respective color. Creating one menu item having three owner drawn menu items is quite manageable, although it is resulting into repetition of code. We can avoid this by inheriting a class from the MenuItem class and handling the event handlers in it. Create our own iconmenuitem class derived from the MenuItem class. This class is given below.
class iconmenuitem : MenuItem { Icon m_icon ; string mtext ; public iconmenuitem( ) { } public iconmenuitem ( string menutext, EventHandler eh, Shortcut sh, Icon ico ) : base ( menutext, eh, sh ) { this.OwnerDraw = true ; this.DrawItem += new DrawItemEventHandler ( drawitem ) ; this.MeasureItem += new MeasureItemEventHandler ( measureitem ) ;
Compiled by rmshankar@yahoo.com
m1 = new ownerdrawn.iconmenuitem( ) ; Now create the menu items m2 and m3 using the iconmenuitem class as shown below. Add this code to the constructor of the Form1 class after the call to the InitializeComponent( ) method.
Icon i1 = new Icon ( "C:\\icon1.ico" ) ; m2 = new iconmenuitem ( "Red", new EventHandler ( m2_click ), new Shortcut( ), i1 ) ; Icon i2 = new Icon ( "C:\\icon2.ico" ) ; m3 = new iconmenuitem ( "Green", new EventHandler ( m3_click ), new Shortcut( ), i2 ) ; m1.MenuItems.AddRange ( new System.Windows.Forms.MenuItem[ ] { m2, m3 } ) ; Add m1, m2 and m3 as data members of type iconmenuitem to the Form1 class. The Click event handler for the m2 menu item is given below. In the same way add the event handler for the m3 menu item.
Compiled by rmshankar@yahoo.com
We would display different images for XML elements and nodes in the tree control. For this, create four bitmap files. Add these files to the Images collection of the ImageList control. The first two images would be used for elements and nodes, whereas, next two images would be used as selected images for elements and nodes The user should enter an XML file name in the text box and click the Load button. This would
Compiled by rmshankar@yahoo.com
private void bload_Click ( object sender, System.EventArgs e ) { try { XmlDocument doc = new XmlDocument( ) ; doc.Load ( txtfile.Text ) ; xmltree.Nodes.Clear( ) ; additem ( doc.DocumentElement, null ) ; } catch ( Exception e1 ) { MessageBox.Show ( e1.Message ) ; } } Here, we have loaded the document in memory by calling the Load( ) method of the XmlDocument class. It may happen that the user would first load one document and then another. In such case, we must delete the nodes of first document before adding new nodes to it. We have done so by calling the Clear( ) method of the TreeNodeCollection class. We have accessed the collection using the Nodes property of the TreeView class. To add the new item, we have called the user-defined additem( ) method. We have passed two parameters to itthe node of the XML document loaded in memory as first parameter and node of the tree control as second parameter. The root node in the document is represented by the DocumentElement property. We have passed null as the tree controls node because there are no nodes in the tree control yet. We have written the code in try-catch block because the Load( ) method throws an exception if it fails instead of returning an error value. Lets write the additem( ) method.
public void additem ( XmlNode xnode, TreeNode tnode ) { TreeNode child = addnode ( xnode, tnode ) ; if ( xnode.Attributes != null ) { string text ; foreach ( XmlAttribute attr in xnode.Attributes ) { text = attr.Name + " = " + attr.Value ; child.Nodes.Add ( new TreeNode ( text ) ) ; } } if ( xnode.HasChildNodes ) { foreach ( XmlNode node in xnode.ChildNodes ) additem ( node, child ) ; } }
Compiled by rmshankar@yahoo.com
public TreeNode addnode ( XmlNode xnode, TreeNode tnode ) { string txt ; TreeNode child = new TreeNode( ) ; TreeNodeCollection tnodes ; if ( tnode == null ) tnodes = xmltree.Nodes ; else tnodes = tnode.Nodes ; switch ( xnode.NodeType ) { case XmlNodeType.Element: child = new TreeNode ( xnode.Name ) ; child.ImageIndex = 0 ; child.SelectedImageIndex = 2 ; tnodes.Add ( child ) ; break ; case XmlNodeType.Text: txt = xnode.Value ; if ( txt.Length > 128 ) txt = txt.Substring ( 0, 128 ) + "..." ; child = new TreeNode ( txt ) ; child.ImageIndex = 1 ; child.SelectedImageIndex = 3 ; tnodes.Add ( child ) ; break ; } return child ; } Let us now see the addnode( ) method. Here, firstly we have declared child as a reference of type TreeNode and tnodes of type TreeNodeCollection. The TreeNodeCollection object represents a collection of tree node objects. If the tree control is empty we must add the XML node as the root node of the control. Otherwise we must add the XML node as a child of tnode. We have achieved this by applying if condition on tnode.
Compiled by rmshankar@yahoo.com
private void xmltree_AfterSelect ( object sender, TreeViewEventArgs e) { lblpath.Text = xmltree.SelectedNode.FullPath ; } We have obtained currently selected tree node using the SelectedNode property. The FullPath property of the TreeNode class returns the path of the node with respect to the root node.
Compiled by rmshankar@yahoo.com
Let us first discuss the types of projects shown in the dialog box and see the usage of each. Later we have illustrated how to deploy different types of applications using these projects. Setup Project A setup project builds a Windows Installer file or an MSI file with the .msi extension. This file is used to install the specified files and resources on the target machine automatically. The .msi file contains the application, any dependent files, information about the application such as registry entries, and instructions for installation. When the .msi file is distributed and run on another computer, you can be assured that everything necessary for installation is included; if for any reason the installation fails (for example, the target computer does not have the required operating system version), the installation will be rolled back and the computer returned to its preinstallation state. CAB Project A CAB project creates a cabinet file with the .cab extension. It is much like a Zip file, compressing
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The File System Editor has three foldersthe Application Folder, the Users Desktop folder and the Users Programs Menu folder. These folders actually represent the folders on the target machine. For example, whatever you put in Users Desktop will be deployed on the desktop of the target machine. From the three folders in the file system editor, files from Application Folder would be deployed in the Program Files folder; typically it is C:\Program Files\Company Name\Application Name of the target machine. Users Desktop folder contains files and folders that would appear on the desktop of the target machine on a per-user basis. Typically the path is C:\Documents and Settings \username\Desktop. Users Programs Menu folder contains users program groups that would usually get deployed in C:\Documents and Settings \username\Start Menu\Programs. Now we need to add the Windows application EXE file into this project. For this we must right click on the Application Folder. A menu is popped. We must select Add | File and on doing so an Add Files dialog is popped. Now we need to browse for windowsapp1.exe file so that it gets added to the Application Folder. We can add the EXE to Users Desktop and Users Programs Menu as well but while doing so we must keep in mind that these two folders are on per-user basis. This means that only the user who installs the application would be able to access the file on his desktop and not the other users. This completes the basic steps needed to build an installer. We can now build this project and an installer called winsetup.msi would get created in the debug folder. Now all we need to do is to distribute this installer and on running the installer on the target machine the application would get installed there. On running the installer we get a series of screens depicting different stages of installation. Note that if our application needs more files than just the windowsapp1.exe then we can copy them to any of the above-mentioned folders. There is much more to a Setup Project than what we discussed above. We saw the simplest form and there are several more features that we need to explore. All the deployment capabilities discussed below are not mandatory and we can customize our installation process according to the needs of our application. Adding Shortcuts We can add shortcuts to our application in any of the 3 folders. For this we need to right click on
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Msiexec.exe /a Setup1.msi This will start the installer of our application and dialog boxes specified for the Administrative Install will be displayed. The default set of predefined dialog boxes is displayed in the User Interface Editor; we can rearrange or delete these if we wish. The default set of dialog boxes varies according to the type of deployment project. Predefined dialog boxes are divided into three categories: Start Dialog Boxes Start dialog boxes are displayed before the installation begins. Commonly they are used to gather customer information or to allow the user to change the installation directory. Progress Dialog Boxes A progress dialog box is displayed to provide feedback on the progress of an installation. End Dialog Boxes End dialog boxes are displayed once the installation has finished successfully. Common uses are notifying the user that the installation is complete or to allow the user to launch the application. We can remove dialog boxes from the default set as per our wish or reposition them using the right click | Move Up/Move Down options. Note that all combinations are not possible here. For example, we cannot remove the Progress dialog box and place it in the Start dialog boxes category after the Welcome dialog box. Now in addition to these dialog boxes we can add and configure our own custom dialog boxes that would get displayed during the installation. To do so we need to right click on the desired category and select Add Dialog. On doing so the Add Dialog Box gets displayed. Here we are presented with several ready-made dialog boxes that we may want to get displayed during installation. Following table indicates the use of these dialog boxes. Dialog Box RadioButtons (2 buttons) RadioButtons (3 buttons) RadioButtons (4 buttons) Checkboxes A, B, or C Purpose Gives the user a choice between two options through two radio buttons. Gives the user a choice between three options through three radio buttons. Gives the user a choice between four options through four radio buttons. Gives the user a choice to add 1, 2, 3 or 4 checkboxes in the same dialog.
Compiled by rmshankar@yahoo.com
Out of the several dialog boxes listed in this table we would discuss only the ones that are likely to be used more commonly. These include the Checkbox dialog box, Read Me Dialog box and the Splash dialog box. The Checkbox Dialog Box Suppose during installation we plan to ask the user whether he wants to add the Disclaimer.txt file along with windowsapp1.exe or not. To control this we plan to add the Checkbox dialog box. If the user checks the Checkbox, the text file gets installed. To add this custom dialog box we have followed the same steps discussed above and added the Checkboxes (A) Dialog. This dialog box would get added as the last dialog box of the Start dialog boxes category. So we can move it up by two positions. Next we have changed some properties of the Checkboxes (A) dialog box. These are shown in the following table. Property BannerText BodyText Checkbox1Label Checkbox1Value Checkbox1Visible Checkbox2Visible Checkbox3Visible Checkbox4Visible Changed to... Disclaimer Do you want to install the Disclaimer text file? Install Disclaimer Unchecked True False False False
Note that we have changed the visible property of the remaining checkboxes to false because we need just one checkbox. Now we need to add a folder in the Application Folder named Disclaimer. For this we must right click on the Application Folder and select Add | Folder. This would add a new folder we have renamed it to Disclaimer. Next we added a text file called Disclaimer.txt to this folder. Hence the Application Folder would contain the windowsapp1.exe along with the Disclaimer folder holding the Disclaimer.txt file. Then comes the most important step of setting the Condition property of the Disclaimer.txt file so that it would only get installed when the checkbox is checked. To do this we need to open the Properties Window of the Disclaimer.txt and set its Condition property to CHECKBOXA1=1. On building the winsetup.msi project, and double clicking it we are presented with this dialog box in the second step of the installation process. The Disclaimer dialog box is shown in the following figure.
Compiled by rmshankar@yahoo.com
The Read Me Dialog box This dialog box displays the Read Me file during installation procedure and installs it along with the application. To demonstrate this we must add the Read Me dialog box in the Start dialog boxes category. Next we need to associate a Rich Text File (rtf) with this dialog box. For this we have to create a ReadMe.rtf file and add it to the Applications Folder. Next we have to set the ReadmeFile attribute of the Read Me Dialog box to this file. We can browse for this file and since we had added it to the Applications Folder we will find it there. Note that we cannot browse beyond the three folders (Application Folder, Users Program and Users Programs Menu), hence if we wish to make any file available in the project we have to first get it copied in one of these. Now after re-building the project and installing it we are presented with this Read Me dialog box as the 5th step of installation and this file gets copied along with the folder. The Splash Dialog Box We added the Splash dialog box just after the Welcome dialog box. The User Interface Editor after addition of all the dialog boxes is shown in the following figure.
Compiled by rmshankar@yahoo.com
To display a splash screen in the Splash dialog box, all we need to do is to set the SplashBitmap property of the dialog to a .bmp file. To make the file available we must first add it to the Application Folder. On re-building this project and running the installer we are presented with the Splash dialog box. In the next part we would see how to add launch conditions to the setup project.
Compiled by rmshankar@yahoo.com
Create a WinForm application and put the controls on the form as shown in Figure 1.
Figure 1 We have added three list boxes to list the files/folders being created, changed or deleted. The Watch Folder button allows user to select a folder to watch. The path of the selected folder gets displayed on the label placed next to the Watch Folder button. The Clear button allows to delete the items listed in the list box having input focus. In addition to these controls, add the FolderBrowserDialog control from the Windows Forms tab and FileSystemWatcher component from the Components tab of the ToolBox. The controls, their names and event handlers are given in the following table. Controls Created list box Changed list box Deleted list box Clear button FileSystemWatcher Name listcreate listdelete butclear watcher Handler butwatch_Click butclear_Click -
listchange -
FolderBrowserDialog browser
Add handlers for the Created, Deleted and Changed events. Also Set the IncludeSubdirectories property of the FileSystemWatcher component to true.
Compiled by rmshankar@yahoo.com
When the application is run, the user has to first select a folder to watch. He can do so by clicking the Watch Folder button. We have displayed the Browse For Folder standard dialog box in which user can select the folder. The dialog is displayed by calling the ShowDialog( ) method as shown below.
private void butwatch_Click ( object sender, System.EventArgs e ) { if ( browser.ShowDialog( ) == DialogResult.OK ) { watcher.Path = browser.SelectedPath ; label1.Text = browser.SelectedPath ; } } We have specified the folder to watch by setting the Path property of the FileSystemWatcher class to the path of selected folder. The path of selected folder is retrieved from the SelectedPath property of the FolderBrowserDialog class. We have displayed the path on the label. The handlers added for the FileSystemWatcher events are given below.
private void watcher_Changed ( object sender, System.IO.FileSystemEventArgs e ) { listchange.Items.Add ( e.FullPath ) ; } private void watcher_Created ( object sender, System.IO.FileSystemEventArgs e ) { listcreate.Items.Add ( e.FullPath ) ; } private void watcher_Deleted ( object sender, System.IO.FileSystemEventArgs e ) { listdelete.Items.Add ( e.FullPath ) ; } In these handlers we have only added the full path of the file/folder being changed, created or deleted in the respective list boxes. To clear a list box, the user has to select an item in that list box and click the Clear button. The handler for the Clear button is given below.
private void butclear_Click ( object sender, System.EventArgs e ) { if ( listcreate.SelectedIndex != -1 ) listcreate.Items.Clear( ) ; else { if ( listchange.SelectedIndex != -1 ) listchange.Items.Clear( ) ; else if ( listdelete.SelectedIndex != -1 )
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Now we need to specify the launch condition. To do so we must set the Condition property of the Condition1 entity to FILEEXISTS1. Note that in the Properties window of Search For File1 the Property property is set to FILEEXISTS1. We can also specify a message through the Properties window that would be displayed if the condition evaluates to false (i.e. if file is not found) at installation time. Changing Icons We can change icons for our application using the Properties window. To change the icon for the shortcuts we must select the shortcut file and set the Icon property of the file to any .ico file. Note that we need to first copy this file to the Application Folder to make it available. On the same lines we can change the icon of the setup file that would be displayed in the Add/Remove Programs Window. To do so, we must right click on winsetup in Solution Explorer and select Properties. This would display the Properties window of the whole solution. Here we need to set the AddRemoveProgramsIcon to any desired file. Adding File Associations Suppose our application creates files having the userdefined extension (for example, we can serialize data in a file having the .mine extension) and now we wish that on double clicking such a file it should automatically get opened in our application. To achieve this we must use file associations. File Associations allows the developer to associate user-defined file types with his or her application. Assume that we need to deploy a file called myfile.mine with our application. To deploy it along with the application we first need to copy it in the Applications Folder. After installation whenever the user double clicks on this file it should get opened with windowsapp1.exe. Note that here too we have made an assumption for demonstration purpose that our application is creating files having .mine extension. Actually windowsapp1.exe is too simple and does not do any serialization or file I/O. Now to associate this file with our application we must right click on the project name in the Solution Explorer and select View | File Types. On doing so we are presented with the File Types Editor. Next we need to right click on the node and select Add File type. Now we need to give any
Compiled by rmshankar@yahoo.com
This editor contains four folders, each corresponding with a phase of installationInstall, Commit, Rollback, and Uninstall. Custom actions are run in the same order that they are displayed in the editor. They can be reordered by dragging with the mouse or through the Cut and Paste commands on the Edit menu. All the Custom Actions run at the end of installation. In addition to the custom actions we add, there are 5 pre-defined custom actions included in Visual Studio .NETEvent Log, Message Queue, Performance Counter, Service, and Service Process components. We can also add these predefined Custom Actions in our project. Deploying to Special Folders In addition to the folders mentioned in the previous sectionApplication Folder, Users Desktop, and Users Programs Menuwe can add more folders to the File System Editor through the Add Special Folders menu. If we right click on the left pane of the File System Editor we get a popup menu offering fourteen folders from which we can select the ones that we can add.
Compiled by rmshankar@yahoo.com
The File System Editor has two foldersCommon Files Folder and Module Retargetable Folder falling under File System on Target machine. Files present in a Merge Module are generally sharable files hence Common Files Folder is a good option to deploy the files. Whichever file we copy in this folder gets deployed to the Common Files folder of the target machine. Here too we have an option of adding special folders to the File System Editor by right clicking on the left pane and selecting the desired folder. Files deployed in these folders would get deployed to corresponding folders on the target machine.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Next we need to change two of the properties of the Web Application Folder. First we have to set the AllowDirectoryBrowsing property to True. This property determines whether users can see a hypertext listing of files and subdirectories in a virtual directory. If it is set to True, users can browse for it. Next we have to set the VirtualDirectory property to myweb. Now we need to build websetup and copy the websetup.msi file to the web server. On double clicking the MSI file the project would get installed. To test the project we need to start Internet Explorer and type the http:\\computername\myweb URL. You will see the name of the windowsapp1.exe file in the browser window. On clicking filename the EXE would get executed. For the second scenario we need to follow the same steps as given above, but instead of copying the EXE to the Web Application Folder, we need to copy an MSI (winsetup.msi) project, which includes the EXE to the folder. Then on deploying and installing websetup.msi we would get the window displaying the name of the websetup.msi file. On clicking it we would be presented with a dialog box that gives us options to install or download the MSI. On installing or downloading the MSI we would be able to execute the Windows application. Setup Wizard As told to you earlier the Setup Wizard helps us to start the deployment projects. The wizard guides us through the steps of creating setup program that contains all information required for installation. The steps in the Setup Wizard are self-explanatory. As soon as we select Setup Wizard, give the project a name (say wizsetup) and press OK, we are presented with a Welcome dialog. On clicking Next we are presented with the Step 2 window of the wizard. It asks us type of project we intend to make. Suppose we select the first option and click Next, we get the third dialog box. Here the Wizard asks us to add the files we wish to deploy. We can add the files by clicking on the Add button and browsing for the desired files. On clicking the Next button the Wizard presents us with the summary of the project. We had selected the first option and hence on clicking the Finish button the Wizard takes us to the File System Editor of the project. We can now build the project as we would build any deployment project.
Compiled by rmshankar@yahoo.com
We will bind the controls to the data source of a hospital management system. The list box will display patient IDs. On selecting the ID, patients name, his address and doctors name will get displayed in text boxes. The patients photograph will get displayed in the picture box. The controls, their names and handlers are given in the following table. Control ListBox Name TextBox Address TextBox Picture Box Name list name address photo
private SqlDataAdapter m_da ; private DataSet m_ds ; private BindingManagerBase m_bman ; We will first fill the dataset with the data we wish to bind with the control. For this, add the following statements to the constructor of the Form1 class.
m_da = new SqlDataAdapter ( "SELECT * FROM PatientInfo", "SERVER=localhost;database=hospital;uid=sa;" ) ; m_ds = new DataSet( ) ; m_da.Fill ( m_ds, "PatientInfo" ) ; We have read the hospital database and filled the dataset with the PatientInfo table. Fill the list box with patient IDs using the following statements.
Compiled by rmshankar@yahoo.com
Binding bname = new Binding ( "Text", m_ds, "PatientInfo.PatientName" ) ; name.DataBindings.Add ( bname ) ; Here, we have created a new data binding using the Binding class. We have passed three parameters to its constructor. The first parameter is the binding property. Second parameter is the data source and third specifies the table.column in the data source. So, we are binding the Text property with the PatientName column of PatientInfo table. We have added this data binding to the collection of data bindings of the Name text box using the Add( ) method. The property does not always evaluate to the required data type. The Binding class enables us to format the values for display through the Format event. We will see how to use this event while binding data to the Image property of the Picture Box control. Also bind the rest of the controls as shown below.
Binding baddress = new Binding("Text", m_ds, "PatientInfo.PatientAddress") ; address.DataBindings.Add ( baddress ) ; Binding bdname = new Binding ( "Text", m_ds, "PatientInfo.DoctorName" ) ; dname.DataBindings.Add ( bdname ) ; Binding bphoto = new Binding ( "Image", m_ds, "PatientInfo.Photograph" ) ; bphoto.Format += new ConvertEventHandler ( convertpicture ) ; photo.DataBindings.Add ( bphoto ) ; Add these statements in the constructor after the call to the InitializeComponent( ) method. Note that we have added a handler to the Format event. We need to add this handler because the required type is Image, whereas, the contents of the Photograph field resolve to Byte[ ]. The Format event is raised when the data is transferred from data source to control and when the data is transferred from control to data source. The event handler convertpicture transforms an array of bytes into a Bitmap object that can be safely assigned to the Image property of a PictureBox control. The handler is given below.
void convertpicture ( Object sender, ConvertEventArgs e ) { Byte[] b = ( Byte[] ) e.Value ; MemoryStream ms = new MemoryStream( ) ;
Compiled by rmshankar@yahoo.com
m_bman = BindingContext [ m_ds, "PatientInfo" ] ; This line selects all the bindings that involve the m_ds data source and PatientInfo data member from the forms binding context. As said earlier, we would select the patients ID from the list box. The record containing this ID will be displayed in the controls. For this purpose, we need to change the position in the binding context using the Position property. Add the handler for the SelectedIndexChanged event and change the position as shown below.
private void list_SelectedIndexChanged ( object sender, EventArgs e ) { m_bman.Position = list.SelectedIndex ; } When the application is executed, the data at zeroeth position would get displayed in the controls. For this, set the selected index to 0 in the constructor after collection the binding manager base object.
list.SelectedIndex = 0 ;
Compiled by rmshankar@yahoo.com
Communication between application domains is encapsulated in the AppDomain class. Lets create a simple application called firstdomain that uses the AppDomain class.
static void Main ( string[ ] args ) { AppDomain a = AppDomain.CurrentDomain ; Console.WriteLine ( a.FriendlyName ) ; } The AppDomain class is used to create and terminate application domains and load and unload assemblies. The CurrentDomain property holds reference to the current domain. The FriendlyName property gets the friendly name of this application domain. The friendly name of the default application domain is the name of the application loaded in the application domain. This program just extracts the name of the exe running in the current domain. Now write another program named seconddomain.
Compiled by rmshankar@yahoo.com
public interface IStack { void push ( int item ) ; int pop( ) ; } Design the Stack class and use it in the StackDemo project as shown below.
public class Stack : MarshalByRefObject, IStack { int [ ] arr = new int [ 10 ] ; int top ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
using stacklib ; using System.Runtime.Remoting ; static void Main ( string[ ] args ) { AppDomain a ; a = AppDomain.CreateDomain ( "mydomain" ) ; ObjectHandle o ; o = a.CreateInstance ( "stackdemo, "stackdemo.Stack" ) ; IStack s = ( IStack ) o.Unwrap( ) ; s.push ( 10 ) ; s.push ( 5 ) ; s.push ( 3 ) ; Console.WriteLine ( s.pop( ) ) ; Console.WriteLine ( s.pop( ) ) ; Console.WriteLine ( s.pop( ) ) ; AppDomain.Unload ( a ) ; } First of all we would have to copy the stackdemo.exe in the bin folder of the current project. Here we have first created a reference of AppDomain class called a and created a new application domain. Then we have used the CreateInstance( ) method to create an instance of a class that is passed as the second parameter to this method. The assembly in which the class is present is passed as the first parameter. The object of the specified class would get created in the domain mydomain. This method returns the object of type ObjectHandle. This returned object is nothing but a wrapper around the object of the class Stack. To extract the actual object, we must unwrap it using the Unwrap( ) method. Here the reference that we need to create to store the reference of the unwrapped object must be of type Stack. Realize that we cannot create a reference of the Stack class in this EXE. Hence we have created a reference s of its base class IStack and stored the reference of the Stack object in it. The IStack reference can be created here because we can easily add a reference of the DLL, containing the definition of IStack, in the EXE. This is the reason why we created another DLL for the IStack interface. Now using this reference we have called methods from the application domain. Next we have unloaded the application domain using the Unload( ) method.
Compiled by rmshankar@yahoo.com
private.SqlCommand sqlSelectCommand1; private SqlCommand sqlInsertCommand1; private SqlConnection sqlConnection1; private SqlDataAdapter sqlDataAdapter1; The command string for SELECT and INSERT statements as well as the connection string also get created. Now right-click on the SqlDataAdapter1 component and select Generate DataSet from the popup menu. The Generate DataSet dialog box appears. Change the DataSet name to ds1 and click OK. This adds a DataSet reference to the component tray. Add the Load event handler and write the following statement in it.
sqlDataAdapter1.Fill ( ds1 ) ; The InitializeComponent( ) method contains the code to connect to the data source. Check whether the connection string is constructed properly and then run the program. You will see the datagrid control filled with data as shown in the following figure.
The control in our form shows records of the bank database. For the field having datatype bit (or boolean) DataGrid control displays a checkbox. Records having value 1 (or true) in that field appear checked. Let us now start the customization work. Firstly, we would arrange the order in which columns should appear. By default DataGrid shows the columns in order specified in the SQL query. If we want to change this order we can change the query. However, what if the order of columns is dependent on an action taken by the user? This can be managed by using the DataGridTableStyle class. Dont confuse this class with the table (datasource) displayed in the DataGrid control. The DataGridTableStyle class represents the grid drawn in the control.
Compiled by rmshankar@yahoo.com
DataGridTableStyle ts = new DataGridTableStyle( ) ; ts.MappingName = "account" ; DataGridBoolColumn bcol = new DataGridBoolColumn( ) ; bcol.MappingName = "ATM" ; bcol.Width = 30 ; bcol.AllowNull = false ; ts.GridColumnStyles.Add ( bcol ) ; DataGridTextBoxColumn column = new DataGridTextBoxColumn( ) ; column.MappingName = "accno" ; column.HeaderText = "Account No." ; column.Width = 80 ; ts.GridColumnStyles.Add ( column ) ; column = new DataGridTextBoxColumn( ) ; column.MappingName = "name" ; column.HeaderText = "Name" ; column.Width = 110 ; ts.GridColumnStyles.Add ( column ) ; column = new DataGridTextBoxColumn( ) ; column.MappingName = "bal" ; column.HeaderText = "Balance" ; column.Width = 110 ; ts.GridColumnStyles.Add ( column ) ; dataGrid1.TableStyles.Add ( ts ) ;
Compiled by rmshankar@yahoo.com
class formatcolumn : DataGridTextBoxColumn { public event formateventhandler format ; protected override void Paint ( Graphics g, Rectangle bounds, CurrencyManager source, int row, Brush backbrush, Brush forebrush, Boolean alignToRight ) { int col = DataGridTableStyle.GridColumnStyles.IndexOf ( this ) ; formateventargs e = new formateventargs ( row, col ) ; format ( this, e ) ; backbrush = e.Backbrush ; forebrush = e.Forebrush ; base.Paint ( g, bounds, source, row, backbrush, forebrush, alignToRight ) ; } } The class declares the event named format of type formateventhandler. Declare the formateventhandler delegate outside the classes as shown below:
public delegate void formateventhandler( object sender, formateventargs e ) ; This delegate specifies that the handler of the format event would accept two parameters, first the reference of type object and second reference of type formateventargs. We cannot pass a reference to the predefined EventArgs class because we have to pass the row and column to the format event handler. We would see the formateventargs class later.
Compiled by rmshankar@yahoo.com
In the formatcolumn class we have overridden the Paint event handler. To this handler, the brushes along with the current row are passed. We have obtained the current column using the IndexOf( ) method. After this, we have fired the format event. The format event handler would initialize the brushes with the desired colors. We have obtained these colors from the formateventargs class by calling its properties Backbrush and Forebrush. We have then called the base classs Paint handler for doing the painting job. The formateventargs class contains the constructor and few properties. This class is given below.
public class formateventargs : EventArgs { private Brush backbrush, forebrush ; private int r, c ; public formateventargs ( int row, int col ) { Row = row ; Col = col ; } public int Row { get { return r ; } set { r = value ; } } public int Col { get { return c ; } set { c = value ; } } public Brush Backbrush { get { return backbrush ; } set { backbrush = value ; }
Compiled by rmshankar@yahoo.com
private void column_formathandler ( object sender, formateventargs e ) { if ( e.Row == dataGrid1.CurrentRowIndex ) { e.Backbrush = Brushes.Aqua ; e.Forebrush = Brushes.Red ; } else { e.Backbrush = new SolidBrush ( dataGrid1.BackColor ) ; e.Forebrush = new SolidBrush ( dataGrid1.ForeColor ) ; } } This handler would get called for every cell of the grid. So, we have checked whether the cell that is getting painted belongs to the currently selected row. Now modify the Load event handler as shown below. Here, instead of DataGridTextBoxColumn, we have created reference of type formatcolumn class. We have also added the format event to each column added to the control.
private void Form1_Load ( object sender, System.EventArgs e ) { sqlDataAdapter1.Fill ( ds1 ) ; DataGridTableStyle ts = new DataGridTableStyle( ) ; ts.MappingName = "account" ; DataGridBoolColumn bcol = new DataGridBoolColumn( ) ; bcol.MappingName = "ATM" ; bcol.HeaderText = "" ; bcol.Width = 30 ; bcol.AllowNull = false ; ts.GridColumnStyles.Add ( bcol ) ;
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Rotation: On rotating an object, the object moves about one of the axes. Scaling: On scaling an object, its size gets increased or decreased but the shape does not change. Shearing: On shearing an object, it moves in some direction but its base remains fixed. Transformations are always applied using matrices. It is a two-step process. The steps involved are: (a) Creating a transformation matrix and coordinate matrix. (b) Multiplying the coordinate matrix with transformation matrix. Translation Transformation Let us understand this form of transformation with the help of an example.
We plan to translate a triangle shown in this figure by three units in x direction and two units in y direction. For doing this we need to change all the three coordinates of the triangle. The new coordinates can be obtained by multiplying the transformation matrix with the coordinate matrix. In the transformation matrix the elements 3 and 2 are the units by which we wish to translate the shape in the x and y directions respectively. The coordinate matrix has three elements. The first element consists of the x coordinate of the vertex, which is to be transformed. The second element consists of y coordinate of the vertex and the last element consists of the z coordinate of the vertex. Hence the first and the second elements of the coordinate matrix would be 2, 2 respectively and as a triangle does not have any z order, the last element of the coordinate matrix would contain 1. After the multiplication is performed the coordinates (2, 2) would get transformed into (5, 4) respectively. Rotation Transformation
Compiled by rmshankar@yahoo.com
Suppose we want to rotate the triangle shown in the above figure by 90 degrees. To do so, we need to replace the transformation matrix angle A by 90 degrees. The coordinate matrix would contain the coordinates of the triangle to be transformed. The figure shows the transformation of only one of the coordinates of the triangle i.e. (2, 4). As the triangle does not have any z order the third element of the coordinate matrix would be 1. The resultant matrix shows that the coordinate (2, 4) has changed to (-4, 2). Similarly we need to transform other two coordinates of the triangle. Scaling Transformation Following figure shows the transformation matrix for scaling.
Suppose the triangle is to be scaled by two units in x direction and two units in y direction. Hence sx and sy in the transformation matrix would be two units each. The coordinate matrix would contain the particular coordinate of the triangle to be transformed, which in our case happens to be (4, 1). On multiplying the coordinate matrix with the transformation matrix we get the resultant matrix which shows that the coordinate (4, 1) has been transformed into (8, 2). The effect of
Compiled by rmshankar@yahoo.com
Suppose the triangle is to be sheared two units in x direction only. Hence sx in the transformation matrix would be 2 whereas sy would be 0. The coordinate matrix would contain the particular coordinate of the triangle to be transformed, which in our case happens to be (1, 4). On multiplying the coordinate matrix with the transformation matrix we get the resultant matrix, which shows that the coordinate (1, 4) has been transformed into (9, 4). On performing similar shearing operation on all other coordinates we would get the resultant triangle as shown in the figure. We would see how to perform all these transformations programmatically in the next article.
private void Form1_Paint ( object sender, PaintEventArgs e ) { Graphics g = e.Graphics ; Image myimg = Image.FromFile ( "C:\\palace.jpg" ) ; Matrix mymat = new Matrix( ) ; mymat.Scale ( -1, 1 ) ; mymat.Translate ( -350, 0 ) ; g.Transform = mymat ; g.DrawImage ( myimg, 50, 50 ) ; g.ResetTransform( ) ; } This code creates a mirror image. Here we have used a Static method FromFile( ) of the Image class, which returns a reference to the image, which we have collected in myimg. Next in order to create a transformation matrix we have first created an object of the Matrix class. Since the
Compiled by rmshankar@yahoo.com
private void Form1_Paint ( object sender, PaintEventArgs e ) { Graphics g = e.Graphics ; Matrix mymat = new Matrix( ) ; mymat.Shear ( -1.4f, 0f ) ; mymat.Scale ( 1, 0.5f ) ; mymat.Translate ( 236, 170 ) ; g.Transform = mymat ; Font myfont = new Font ( "Times New Roman", 100 ) ; SolidBrush mybrush = new SolidBrush ( Color.Gray ) ; g.DrawString ( "K", myfont, mybrush, 50, 50 ) ; g.DrawString ( "I", myfont, mybrush, 150, 50 ) ; g.DrawString ( "C", myfont, mybrush, 200, 50 ) ; g.DrawString ( "I", myfont, mybrush, 300, 50 ) ; g.DrawString ( "T", myfont, mybrush, 350, 50 ) ; g.ResetTransform( ) ; mybrush.Color = Color.DarkMagenta ; g.DrawString ( "K", myfont, mybrush, 50, 50 ) ; mybrush.Color = Color.FromArgb ( 150, 0, 255, 255 ) ; g.DrawString ( "I", myfont, mybrush, 150, 50 ) ; LinearGradientBrush lgb = new LinearGradientBrush ( new Point ( 200, 50 ), new Point ( 350, 200 ),Color.Brown, Color.Yellow ) ; g.DrawString ( "C", myfont, lgb, 200, 50 ) ; HatchBrush hb = new HatchBrush ( HatchStyle.DiagonalCross, Color.Blue, Color.Red ) ; g.DrawString ( "I", myfont, hb, 300, 50 ) ; Image myimg = Image.FromFile ( @"C:\test.bmp" ) ;
Compiled by rmshankar@yahoo.com
To create a transformation matrix we have firstly created an object of the Matrix class. This object represents an identity matrix of size 3 x 3. We intend to perform shearing, scaling and translation transformations. For this we have called the methods Shear( ), Scale( ) and Translate( ) using the mymat object. These methods manipulate the object by doing matrix multiplication as discussed earlier. At the end of these calls, mymat object represents the transformation matrix. Next, we have set the Transform property of the Graphics class object g to mymat object. Now whenever a shape would be drawn, the corresponding shapes coordinate matrix would get multiplied with the transformation matrix stored in mymat. Next we have selected a SolidBrush of gray color and used the DrawString( ) method of the Graphics class to display the string. We have called ResetTransfrom( ) method that resets the world transformation matrix of this Graphics object to the identity matrix. The identity matrix represents a transformation with no scaling, rotation, or translation. To display K we have used a solid brush of dark magenta color. To display I we have used a transparent brush. A brush can be made transparent by using the FromArgb( ) method and passing an alpha component as its first parameter. The alpha component specifies how opaque or transparent a color should be. The alpha value ranges from 0 (fully transparent) to 255 (fully opaque). The default value is 255 and hence if we do not pass any value the color created is always opaque. In our program we have passed 150 as the first parameter to the FromArgb( ) method. This results in a semi-transparent color. The string I gets drawn with semi-transparent blue color. Next we have displayed C using a linear gradient brush. Here the y coordinate of the second point passed to the constructor of the LinearGradientBrush class does not match with the y coordinate of the first point and hence the gradient fill is not horizontal. The I is displayed using a hatch brush and lastly to display T, we have used a texture brush. To the constructor of the TextureBrush class a reference to an image, which is to be filled, is passed. We have used the Static method FromFile( ) of the Image class to load the image. If you run the program, you will see the string KICIT written as shown below.
Compiled by rmshankar@yahoo.com
Here, we have loaded the world.gif file containing the map image. The Point objects are initialized with the proper values. Add the Paint event handler wherein we would draw the image on the form. We would also draw the lines using the Point objects initialized just now. private void Form1_Paint ( object sender, PaintEventArgs e ) { Graphics g = e.Graphics ; g.DrawImage ( img, 0, 0, img.Width, img.Height ) ; Pen p = new Pen ( Brushes.Red ) ; g.DrawLine ( p, hstart, hend ) ; g.DrawLine ( p, vstart, vend ) ; }
Run the program, you would see the output as shown in the following figure.
Compiled by rmshankar@yahoo.com
The lines should move as the mouse moves. We have already written the code to draw new lines and erase previous ones in the Form1_MouseMove( ) handler. Update that code as shown below. private void Form1_MouseMove ( object sender, MouseEventArgs e ) { Graphics g = CreateGraphics( ) ; hend.Y = hstart.Y = e.Y ; vend.X = vstart.X = e.X ; g.DrawImage ( img, 0, 0, img.Width, img.Height ) ; Pen p = new Pen ( Brushes.Red ) ; g.DrawLine ( p, hstart, hend ) ; g.DrawLine ( p, vstart, vend ) ; }
Here, we have updated the coordinates stored in the Point objects according to the mouse position and drawn lines at new position. We must keep checking the mouse position. If the mouse is placed over a city that is present in our city database, we must display the label carrying day, time and city. In our program the application data is the name of the city, its coordinates and the time at that place with respect to the Indian Standard Time. To keep things simple we have stored this data in an array of objects. The objects are of type location. location is a user-defined class. We would first declare this class. class location { public int hours, minutes ; public string city ; public int x, y ; public location ( int h, int m, String c, int xx, int yy ) { hours = h ; minutes = m ; city = c ; x = xx ; y = yy ; } }
The location class contains data members to hold hours, minutes, city name and x-y coordinates of the city on the map. The data members are initialized through constructor. Populate the array in the Form1 class as shown below. This is only a part of the array. location[ ] loc = {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
l.Left = dpt.X ; l.Top = dpt.Y ; l.Size = new Size ( 150, 20 ) ; l.Text = str ; l.Visible = true ; If The mouse is positioned at some obscure place in the world whose entry is not present in the array the search( ) method returns a value -1. In such a case the label is hidden by setting the Visible property to false. Lets now look at the two helper functions search( ) and calculate( ). They are given below.
int search ( Point p ) { Rectangle r = new Rectangle ( p.X , p.Y , 5, 5 ) ; Point pt ; for ( int i = 0 ; i < loc.Length ; i++ ) { pt = new Point ( loc [ i ].x, loc [ i ].y ) ; if ( r.Contains ( pt ) ) return i ; } return -1 ; } To this method we have passed the current mouse position. We have run a for loop to see whether coordinates of any city fall within the specified area. If they do, we have returned the index of the element. This index is then passed to the calculate( ) method.
string calculate ( int i ) { int m_hour = loc [ i ].hours ; int m_minute = loc [ i ].minutes ; DateTime t = DateTime.Now ; t = t.AddHours ( m_hour ) ; t = t.AddMinutes ( m_minute ) ; string week_day = t.DayOfWeek.ToString( ) ; string str = week_day + " " + t.Hour + ":" + t.Minute + " " + loc [ i ].city ; return str ; }
Compiled by rmshankar@yahoo.com
We have placed several labels and text boxes along with two buttons. The textboxes are respectively given names as txtto, txtfrom, txtcc, txtbcc, txtsubject, txtattach and txtbody. The buttons are named as butsend and butattach respectively. Declare a reference msg to the MailMessage class as data member of the Form1 class and initialize it in the constructor as shown below. msg = new MailMessage( ) ; Add the Click event handler for both the buttons. These handlers are given below.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
We have added three list boxes to list the files/folders being created, changed or deleted. The Watch Folder button allows user to select a folder to watch. The path of the selected folder gets displayed on the label placed next to the Watch Folder button. The Clear button allows to delete the items listed in the list box having input focus.
Compiled by rmshankar@yahoo.com
Add handlers for the Created, Deleted and Changed events. Also Set the IncludeSubdirectories property of the FileSystemWatcher component to true. When the application is run, the user has to first select a folder to watch. He can do so by clicking the Watch Folder button. We have displayed the Browse For Folder standard dialog box in which user can select the folder. The dialog is displayed by calling the ShowDialog( ) method as shown below. private void butwatch_Click ( object sender, System.EventArgs e ) { if ( browser.ShowDialog( ) == DialogResult.OK ) { watcher.Path = browser.SelectedPath ; label1.Text = browser.SelectedPath ; } } We have specified the folder to watch by setting the Path property of the FileSystemWatcher class to the path of selected folder. The path of selected folder is retrieved from the SelectedPath property of the FolderBrowserDialog class. We have displayed the path on the label. The handlers added for the FileSystemWatcher events are given below. private void watcher_Changed ( object sender,System.IO.FileSystemEventArgs e ) { listchange.Items.Add ( e.FullPath ) ; } private void watcher_Created ( object sender,System.IO.FileSystemEventArgs e ) { listcreate.Items.Add ( e.FullPath ) ; } private void watcher_Deleted ( object sender, System.IO.FileSystemEventArgs e ) { listdelete.Items.Add ( e.FullPath ) ; }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
The blue horizontal bar is a label control. We have changed its BackColor, ForeColor and Font properties. The control placed at the left hand side is the ListBox control. The control placed on the right hand side is the ListView control. The program is to list the currently running processes in the list box. If a process is selected its information is displayed in the list view control. Here, our aim is to show how to use the Splitter control. Our stress is not on browsing and retrieving information of processes. When we place the Splitter control on a container, it divides the entire container in two partsleft and right (or top and bottom if placed horizontally). But, we dont want to show the vertical bar of the Splitter control on the label. We want that the effect of splitter should be felt only on the remaining part of the form. For this, we have placed a Panel on the form so as to cover the remaining part of the form. This is shown in the following snap shot.
Now, place the ListBox and change its Dock property to Left. Name the control as list. Drag the Splitter control on the form. It will get docked to the left side indicating that it has to resize the control placed on the left. Run the program and place the cursor on the splitter bar. When the cursor changes, drag it to left or right. You would see the list box resizing. We want to place a ListView control as well as button on the right side of the splitter. If user moves the splitter, both the controls should be relocated properly. For this, we have again placed a Panel covering the right side of the form and placed the ListView and Button controls on it. Name the Panel control as panel, ListView control as listview and Button control as kill. Clicking this button would kill the process selected from the list box. Again note that our aim is to show you how to relocate the multiple controls if Splitter control is moved, not to kill the process. Lastly, add the Process component from the Components tab on ToolBox and name it process. The designing part is over, lets move on to the coding part. Firstly, add the Load event handler. The handler is shown below. private void Form1_Load ( object sender, System.EventArgs e ) {
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Consider your left hand with the palm up as shown in the above figure. Then the thumb would represent the z-direction, which is traveling away from the body. In the left handed coordinate system we can position 3D objects in one of the three different types of space coordinates. Model Space: Suppose we are drawing different 3D entities like a cube, a sphere, a pyramid etc. Each such object can be called a model. In the model space each such model has a different origin. World Space: In the world space there is a fixed origin. The world transformation matrix changes coordinates from model space, where vertices are defined relative to a model's local origin to world space where vertices are defined relative to an origin common to all the objects in a scene. In essence, the world transformation places a model into the world and hence its name.
Camera Space (View Space): This view of the world places the viewer (user) at the origin and faces him or her in the direction of the positive z-axis. The view matrix is used to transform vertices from the world space to the Camera space. Above figure and following two figures depicts these three spaces.
Compiled by rmshankar@yahoo.com
Let us now take an example and combine these three spaces together. If we want to spin two cubes the first thing that we need to do is create the tow cubes using the model coordinates. In the above figure for depicting the model space the two cubes have their own coordinate separate coordinate systems. We have placed both the cubes at origin in their respective coordinate systems. Then using the world transformation matrix we place the cubes into the world space. The origin of the model space and world space may be same or different. (In the above example the origin of the model space and the camera space are the same). Then we have translated the cube 2 in the world space using transformations because had we done that the two cubes would have got overlapped. Note that the camera is placed at (-200,100) in the world space. In the world space to rotate scale and translate the cube various transformation matrices are used. Next to look at the cube we have to indicate the position of the eye/camera in the world space. When we do so the origin of the world space is mapped to the eye position (Camera space origin). Due to this the camera or the eye is placed at the origin and the two cubes are reoriented with respect to the camera. Now if we display the cubes on the screen they would hardly appear like real cubes. To make the cubes appear more realistic we need to make some more effort. There are two facts involved when a human eye sees an object (a) A human eye sees what falls in the conical volume as shown in following figure.
Compiled by rmshankar@yahoo.com
(b) That part of the object that is nearer to the eye appears bigger than the part that is farther away from it. This way of looking at an object is known as perspective projection. Let us now see how Direct3D uses these facts to generate realistic shapes. Instead of using a cone Direct3D uses a close approximation of it a pyramid to represent the viewing volume. In principle we can see an object which is present on any distance, even at infinity. But in reality we can see an object present only upto a particular distance. Hence instead of a pyramid of infinite length we need to use a frustrum of a pyramid to represent a viewing volume. This is shown in the following figure.
A front and back clipping plane intersects the pyramid. The volume within the pyramid between the front and back clipping planes is the viewing frustum. Objects are visible only when they are in this volume. The viewing frustum is defined by fov (field of view) and by the distances of the front and back clipping planes, specified in z-coordinates. Once the viewing volume is specified we need to create a projection matrix which would apply the perspective projection to the coordinates of the cube. These modified coordinates are then used to render the shape on the screen (2D-plane). While actually rendering shapes using Direct3D it relieves us of the burden of forming the projection matrix. we need to only specify fov and the distances of the front and back plane from the eye. The entire process is illustrated in following figure.
Compiled by rmshankar@yahoo.com
Transformations There are three basic transformations that can be applied to any 3D objects. These are translation, rotation and scaling. These transformations are discussed below. The Translation transformation involves movement of the object in the x, y, or z direction. When we move the object in these directions the coordinates of the object at the new position would be different from the original coordinates. We can calculate the new coordinates using simple equations. However, from the point of view of programming convenience if we store the coordinates in one matrix and the distance by which the object is being translated ( in x, y, and z direction ) in another and carry out simple matrix multiplication then the resultant matrix would contain the new set of coordinates. Similar matrix operations can be performed on Rotation and Scaling operations. 1) Translation If x, y, and z are the coordinates of a point which is to be translated by a distance Tx, Ty and Tz, then the matrix multiplication that would be carried out is as under: Here x', y' and z' are the new coordinates of the point.
Compiled by rmshankar@yahoo.com
3) Scaling The scaling transformation involves increasing or decreasing the size of an object. The following transformation scales the point (x, y, z) by values Sx, Sy and Sz in the x, y, and z directions to a new point (x', y', z').
Other than programming convenience using matrices for performing transformations offers one more advantage. We can combine the effects of two or more transformation matrices by multiplying the matrices representing these transformations. This means that, to rotate a object and then translate it to some location, we don't need to apply two multiplication's. Instead, we can multiply the rotation and translation matrices to produce a composite matrix that contains effects of rotation and translation. This resultant matrix is then multiplied with the coordinate matrix to yield new coordinates. Direct3D provides us methods to set up all the matrices for translation, rotation and scaling as well as it provides a method that provides a matrix that represents the cumulative effects of all the
Compiled by rmshankar@yahoo.com
Two triangles are used to create each face of the cube. A cube has a total six faces i.e. 12 such triangles are used to compose the complete cube. This is shown in following figure.
Compiled by rmshankar@yahoo.com
The new Modifier... We can use the new modifier for a method in the derived class that has the same signature (prototype declaration) as the base class method. Using the new modifier we can declare that a method is not an override of the base class method, but it is the new method that belongs to this class. Declaring the method as new hides the base class implementation of the method. The new modifier can be applied on non-virtual as well as virtual methods but not on abstract methods.
How do I read/write binary data from/to a file? Ans: To read binary data from a file we can use the BinaryReader class. To write binary data to a file we can use the BinaryWriter class. The Write( ) method of the BinaryWriter class writes data of type int, long, float, etc. to the file. Similarly, Read( ) method reads the data from file. Binary I/O is useful while reading or writing records.
How to perform custom validation? Ans: While creating ASP.NET application we often require to validate the input data. We can use various validation controls provided by the .NET for this purpose. There are controls to check whether fields are empty, to compare two values and to validate a value using regular expression. But what if we want that user should enter only numeric value in a text box? There is no built-in validation control for this purpose. In such a situation we can use CustomValidator control. To this control, we need to specify a function that is used for validating the value of the control. Whether value is right or wrong can be specified using the IsValid property of the control.
Binding Data With Controls... We often need to populate controls like combo box, list box, etc. using a data source. Instead of reading data from the data source and then adding it to items' collection of these controls, we can directly bind data sets to these controls so that the controls get populated with the data from specified dataset. Following code snippet shows how to bind data to a combo box named myCombobox. string ConnectionStr = System.Configuration.ConfigurationSettings.AppSettings [ "DbConnect" ] ; SqlConnection Connection = new SqlConnection ( ConnectionStr ) ; SqlDataAdapter DAdapter = new SqlDataAdapter ( "select Id from mytable", Connection ) ; DataSet ds = new DataSet( ) ; DAdapter.Fill ( ds, "mytable" ) ;
Compiled by rmshankar@yahoo.com
COM Interoperability... COM components and .NET components are not compatible since they have different internal architectures. However, there are tools available in the .NET SDK for generating COM proxies for .NET components and .NET proxies for COM components. Using these proxies we can use COM components in .NET projects and vice versa. For using COM components in .NET application we can create the wrapper class either by using the 'TlbImp.exe' tool provided in the .NET SDK or by adding the COM reference through the Solution Explorer. To use a .NET component in a non-.NET project we have to first register the component using the RegAsm tool as well as create a corresponding COM type library file ('.tlb' file). To create a COM type library file we need to use the TlbExp tool.
Using Pointers In .NET... Pointers can be used in C#, but only in the blocks of code that we have specifically marked for pointer use. The keyword to do so is unsafe. We can mark individual methods, classes, structures, blocks of code or even local variables as unsafe. For example we can write: unsfae float myfunction( ) { // Can use pointers } unsfae class myclass { unsafe int *x ; } unsafe { // unsafe block }
Creating A Splash Screen... .NET by default does not expose any feature similar to the VC++ SplashScreen, but it can easily be replicated using a simple trick. The trick is to add a form to the application, strip it off all the borders and title bar, also disable it to have any presence on the task bar. Once this is done, wrap your Splash screen bitmap on to this form. Add a timer control to the form and set it to the necessary delay. On the timer_click event, dispose the form. Your authentic splash screen is ready. Now make sure that this form is displayed every time your application starts. Best way to do this is to show the splash screen in the Load event of the application window.
Compiled by rmshankar@yahoo.com
Documents downloaded from www.funducode.com Structure Of Manifest... The assembly metadata that describes the assembly is called the Manifest. A manifest contains: (a) The identity of the assembly, consisting of its name, version and culture. (b) Names of all the files in the assembly. (c) Whether all the types defined in the assembly are visible to other assemblies or private to one. (d) A hash of all files in the assembly. (e) Details of any security permissions that clients need to have in order to be able to run the assembly.
The With - End With keywords... The keywords With - End With execute a series of statements written between With and End With making repeated reference to a single object of the structure or class. For example the statements e.name = "Satish" e.age = 25 e.sal = 4500 can be written using With - End With as With e .name = "Satish" .age = 25 .sal = 4500 End With How to invoke two handlers for one event? Ans: For one event we can add two handlers. For example, if we click on a button, by default Click event handler gets called. If we want to call some other handler also, we can do so by writing the handler as sub Funname ( ) Handles ControlName.Click. ----End Sub Painting On Form... Suppose we want to display a string at the center of the form. We would do so in Paint event handler as shown below: private void Form1_Paint ( object sender, System.Windows.Forms.PaintEventArgs e ) { Graphics g = e.Graphics ; Font font = new Font ( "Arial", 20 ) ;
Compiled by rmshankar@yahoo.com
How to run another application from current running application? Ans: To run an application from within a currently running aplication call Start( ) method as shown below: Imports System.Diagnostics Public Class Form1 Private Sub Button1_Click ( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles Button1.Click Process.Start ( "IExplore", "http://www.funducode.com/" ) End Sub End Class How do I write code to get the list of fonts available on machine in a combo-box? Ans: Create a Windows application. Add a combo box on form. Add code to Load event as shown below: Private Sub Form1_Load ( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles MyBase.Load
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Difference Between Server-activated & Client-activated Objects... Serveractivated objects are so called because when the client calls new to create an instance of the remote class, only a proxy gets created in the client. The object does not get created or activated. The object gets created only when a method call is placed through the proxy. So, the server actually decides when the object should get created. Clientactivated objects, on the other hand, are created on the server the moment the client calls new. Thus here the client decides when the object should get created. Another difference between the two is that clientactivated objects can be activated using nonzeroargument constructors but serveractivated objects cannot. This is because for serveractivated objects, the calls to new dont map with the actual creation of the object. On the other hand client activated objects can be instantiated with any constructor as both the proxy and the object are created at the same time.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Integer Types in VB.NET... Integer types in VB.Net are used to represent whole numbers. Depending on the amount of memory required to store an integer the data type in VB.net is categorized as, Byte, Short, Integer and Long. The following table lists the data type and its size. Data Type Byte Short Integer Long Size in Bytes 1 2 4 8
Following statement shows how we can declare an integer variable in VB.NET. Dim x, y As Integer
Compiled by rmshankar@yahoo.com
There are two types of procedures in VB.NET-Functions and Subroutines. The basic difference between the two is that a subroutine does not return a value whereas a function returns a value. Function is a collection of logical statements which perform a specific task and return some value. Hence whenever you want to return something to a calling function use a function and to display something use a subroutine. Thus, for displaying a menu we would use a subroutine and for calculating a factorial of a number and returning it to the calling function we would use a function.
Constructor in VB .NET In VB.NET the constructor name is not same as the name of the class. A keyword New is used to define a constructor. Following code snippet shows how to declare a constructor: Class sample Dim i As Integer Sub New( ) i=5 End Sub End Class Module Module1 Sub Main( ) Dim obj As sample obj = New sample( ) End Sub
Compiled by rmshankar@yahoo.com
Value Types Vs Reference Types In VB.NET variables are either value types or of reference types. The difference between the value type and reference type is that the data of value type gets stored on the stack and that of the reference type gets stored on the heap. The variables of the value types directly contain the data, whereas, reference types contain references (or addresses) of the data. Examples of value types are the primitive data types integer, floating points, structures whereas examples of reference types are arrays and classes
Arrays... We can declare an array as shown below: Dim arr( ) As Integer arr = New Integer ( 5 ) { }
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
How do I write code to navigate to previous and/or next record? Ans: Add code to the handlers that move record pointer to previous and next record respectively, as shown below: Private Sub Previous_Click ( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles Previous.Click Dim str As String 'dr is a private variable of type DataRowCollection added to Form class str = dr ( count ).Item ( 0 ) 'to move to previous record decrement count by 1 count -= 1 ' where count is a variable of type Integer If count < 0 Then count = 0 MsgBox ( "Reached First Record" ) End If End Sub Private Sub Next_Click ( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles Next.Click
Compiled by rmshankar@yahoo.com
Documents downloaded from www.funducode.com 'to move to next record increment count by 1 count += 1 Dim str As String str = dr ( count ).Item ( 0 ) ' where dr is a variable of type DataRowCollection If Count >= dr.Count - 1 Then count = dr.Count - 2 MsgBox ( "Reached Last Record" ) End If End Sub
Virtual Functions in VB.NET In VB .NET the keyword Overridable is used to indicate that a function is virtual. The Overridable keyword in VB.NET is similar to the keyword virtual in C++. Following code snippet shows how we can design a base class that has a virtual function. Class shape Overridable Sub draw( ) Console.WriteLine( " Shape" ) End Sub End Class Any class that inherits the shape class can override the draw( ) method. For this it is necessary that draw( ) method should be preceded with the keyword Overrides in a derived class. This is shown in following code snippet. Class line : Inherits shape Overrides Sub draw( ) Console.WriteLine ( "Line" ) End Sub End Class How do I write pure virtual functions in VB.NET? Ans: In VB.NET the pure virtual functions are written by writing the keyword MustOverride against the name of the method. The keyword MustOverride specifies that the method written in the base class must be overridden in the derived class. Like pure virtual functions a MustOverride method cannot have a body. Consider the following example: MustInherit Class shape MustOverride Sub draw( ) End Class Class circle : Inherits shape Overrides Sub draw( ) Console.WriteLine ( "Circle" ) End Sub
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Private Sub sendmail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mailsend.Click If emailaddr.Text = "" then MessageBox.Show("Enter The Email Address") Return End If
Compiled by rmshankar@yahoo.com
System.Diagnostics.Process.Start("mailto:" & emailaddr) End Sub How do I make use of LinkLabel control in a program? Ans: Follow the steps listed below: 1. Create a Windows Application. 2. Place on it a LinkLabel control named as link. 3. Set the Text property of link as "http://www.funducode.com/". On clicking link an appropriate web page should get opened. To make it work add the LinkClicked event handler and write code to it as given below: Private Sub link_LinkClicked ( ByVal sender As Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs ) Handles link.LinkClicked System.Diagnostics.Process.Start(link.Text ) End Sub How do I write code that sends an e-mail? Ans: Create a Windows Application. Place four Text Boxes labeled as emailaddr, fromaddr, emailmessage and emailsubject used forentering the destination email address, sending email address, writing message and writing subject respectively. Also add a button SendMail named sendmail on the form. On entering the email address in the text box and on writing the message in the emailmessage text box when the SendMail button is clicked the mail should be sent to the proper address. To do so we will use SMTPMail class, and to use it we need to add a reference in our solution. Click on 'View' menu and select 'Solution Explorer'. Right-click on 'references', select 'Add Reference' option. Then select 'System.Web.dll'. Click select and then press OK. As a result, System.Web reference will get added in our solution. Now, we will have to import the namespace System.Web.Mail. For that write the following import statement in the Form1.vb at the top. Imports System.Web.Mail Then, write following code in the Click event handler of the SendMail button. Private Sub sendmail_Click ( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles sendmail.Click If emailaddr.Text = "" Then MessageBox.Show ( "Please enter email address" ) Return End If Dim myMail As New MailMessage( ) myMail.From = fromaddr.Text myMail.To = emailaddr.Text myMail.Subject = emailsubject .Text myMail.BodyFormat = MailFormat.Text
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Private Sub browse_Click ( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles browse.Click opendlg.ShowDialog( ) If opendlg.FileName <> "" Then filepath.Text = opendlg.FileName End If End Sub Here, we have used StreamReader class hence write following line at the top in Form1.Vb file Imports System.IO Now, add following code in the click event handler of open button. Private Sub open_Click ( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles open.Click Dim reader As StreamReader = New StreamReader ( filepath.Text ) filetext.Text = reader.ReadToEnd( ) reader.Close( ) End Sub
How do I write code to display a Splash Screen for an application? Ans: Create a Windows application. Add another form named SplashForm to the application by selection Project | Add | Windows Form menu item. Insert a picture box on the SplashForm. Copy a '.bmp' say 'Splash.bmp' to the project. Set the Image property of the picture box to the file name 'Splash.bmp'. Change the BackColor and BorderStyle property of SplashForm to White and none respectively. Set the TransparencyKey of SplashForm as White. Then write following code in the constructor of Form1. Public Sub New( ) MyBase.New() 'This call is required by the Windows Form Designer. InitializeComponent( ) 'Add any initialization after the InitializeComponent() call Dim f As New SplashForm( ) End Sub Write following code in constructor of SplashForm. Public Sub New( ) MyBase.New( ) 'This call is required by the Windows Form Designer. InitializeComponent( )
Compiled by rmshankar@yahoo.com
Accessing Database Using OLEDB.NET... Create a database called bank and add a table called account with three fields accno, name and balance. Create a console application. In this application we will connect to the database and display the contents of the table account on the console output. To be able to use class OLEDBDataReader write following line at the top in 'Module1.Vb'. Imports System.Data.OleDb Create the connection string and the command strings. Then create OleDbConnection object and OleDbCommand object. Using the command object execute the query. Write code in Sub Main( ) as shown below: Sub Main( ) Dim connectionstr As String = "Provider = Microsoft.Jet.OLEDB.4.0 ;Data Source = c:\bank.mdb" Dim commandstr As String = "SELECT accno, name, balance from account" Dim connection As New OleDbConnection ( connectionstr ) Dim command As New OleDbCommand ( commandstr, connection ) connection.Open( ) Dim r As OleDbDataReader = command.ExecuteReader( ) While r.Read( ) Console.WriteLine ( r(0) & r(1) & r(2) ) End While connection.Close( ) End Sub How do I declare variables as read only in VB.NET? Ans: VB.NET provides a keyword ReadOnly which is used for variables which are to be initialized at the time of building the objects. The following code shows how to declare variables as ReadOnly. Module module1 Class hotel Public ReadOnly name As String Sub New ( ByVal n As String ) name = n End Sub End Class Sub main( ) Dim h As New hotel ( "Tuli" ) End Sub
Compiled by rmshankar@yahoo.com
What does .Net framework consist of? Ans: The .Net framework consist of the following: Class Library which contains Language Independent classes Virtual Machine which is known as Common Language Runtime used to run native code Development Environment comes in the form of Visual Studio.Net which supports VB, VC++ & C# to create Portable Executable files and components
What is Microsoft Intermediate Language (MSIL)? Ans: MSIL is a CPU-independent set of instructions. It is like bytecode in Java. MSIL code under .Net is stored in EXEs or DLLs. EXEs are known as (portable executable) file.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
public class myexception : Exception { public string i ; public myexception ( string x ) : base ( x ) { } } Calling the base class constructor is mandatory here. We can throw this exception anywhere in the program in the following manner: if ( x > 10 ) throw new myexception ( "Value out of Range" ) ; The new modifier Suppose a base class has a virtual function and the virtual function is overridden in the derived class. If we store a reference of derived class in an object of base class and try invoking the function, the function from the derived class is called. If we don't override the virtual function, the function from the base class is called. But along with this, a warning is flashed. To remove this warning and call the function of the base class we have to add the a modifier called new to it. The new modifier is used to explicitly hide a member inherited from a base class. C# destructors and Finalize( ) method In C++ whenever an object gets destroyed the destructor of that class gets called. In C# the destructor does not work in this manner. A C# destructor is nothing but a Finalize( ) method in disguise. The Garbage Collector calls the Object.Finalize( ) method immediately before the object is collected (destroyed). We can not tell when the garbage collector gets called and when the object gets destroyed because C# runtime schedules garbage collections when it feels theyre necessary. It is quite possible that the destructor we wrote never gets called. If we write the destructor and the Finalize( ) method in the same class the compiler flashes error String Comparison In C# we can use == operator to compare two strings, but the comparison done will be case sensitive. Method Compare( ) can be used for both, case sensitive as well as case-insensitive string comparison. If we pass true as the last parameter to the Compare( ) method the comparison becomes case insensitive. Following code snippet illustrates this: string str1 = "hello" ; string str2 = "HELLO" ; bool chk1 = ( str1 == str2 ) ; // output is false int chk2 = ( String.Compare ( str1, str2, true ) ) ; // output is 0, meaning strings are equal Function Overloading Value, Reference, Output and Parameter Array can be used to overload a function. Consider the following program. public class Class1 { public static int Main ( string[] args )
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
To make a connection, we pass the connection string to the OleDbConnection constructor. To the OleDbCommand constructor we pass the connection as well as the command string. The Open( ) method opens a database connection with the property settings specified by the connection string. The OleDbDataReader class reads a stream of rows from database. To create an OleDbDataReader class we have to call the ExecuteReader( ) method belonging to the OleDbCommand class. This method will execute the command and return an OleDbDataReader object. The Read( ) method iterates through the records advancing the OleDbDataReader by one record every time. we have used the ordinal indexer to access individual values of a row referenced by the OleDbDataReader. Using SQL Server .NET Data Provider... using System; using System.Data; using System.Data.SqlClient; class myclass { static void Main ( string[ ] args ) { string str = "server = kicit ; uid = icit ; pwd = ypk ; Database = bank" ; string cmd = "SELECT accno, name, balance from account" ; SqlConnection con = new SqlConnection ( str ) ; SqlCommand com = new SqlCommand ( cmd, con ) ; con.Open( ) ; SqlDataReader r = com.ExecuteReader ( ) ; while ( r.Read ( ) ) Console.WriteLine ( r[0] + " " + r[1] + " " + r[2] ) ; con.Close ( ) ; } } First we need to get connected to the database. To do so, we have to write a connection string. The connection string includes database name, server, database provider, user name, password. This connection string is stored in str. The command string is stored in cmd. cmd contains the query to be executed. To make a connection, we pass the connection string to the SqlConnection constructor. To the SqlCommand constructor we pass the connection as well as the command string. The Open( ) method opens a database connection with the property settings
Compiled by rmshankar@yahoo.com
The tool shows the Manifest, Namespace, Class and Method in the assembly. It can also show Interfaces, Value types, Static methods, Fields, Static Fields, Events and Properties. Structure of an Assembly An assembly is made up of metadata , IL (Intermediate Language) code and resources. The Metadata consists of type metadata and an assembly metadata. Assembly Metadata which is referred to as the Manifest describes assembly. It contains following information. a. An identity, name, version and culture of an assembly. An assembly has a four part version number e.g. 1.0.1.1. which stands for <Major> . <Minor> . <Build> . <Revision> The use of these numbers is dependent on the configuration of our application. A good policy is to change the major or minor numbers if the version is incompatible with the previous versions. The build number is the number of days since Jan-1, 2000, and revision is the number of seconds since midnight local time. b. Names of all files in an assembly. c. Details of all types defined in an assembly.
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
How do I read non-public members from metadata? Ans: We use reflection technology to read metadata. We have various methods at hand like GetMethods( ), GetConstructors( ), GetFields( ), GetProperties( ), etc. that can be used to read the respective members from metadata. If we call these methods without passing any parameters, they return only public members, not the non-public members. To read the nonpublic members we must pass certain flags to them. The following statement shows how to pass the flags to read all the methods. mytype.GetMethods ( BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic ) ; These flags indicate that we intend to read the instance methods, methods that are not inherited from base type and methods that are public as well as non-public. The main design goal of C# was simplicity rather than pure power. We do give up a little processing power, but you get cool stuff like type safety and automatic garbage collection in return. C# can make our code stable and productive overall. C# offers several key benefits for programmers: Simplicity Consistency Modernity Object-orientation Type-safety Scalability Version support Compatibility Flexibility
Let's see what version support does C# provides: In C++, if a derived class contains a non-virtual function with a name abc( ) and the new version of a base class is shipped with a virtual function having the same name abc( ). This would result in an unpredictable result since the derived class version of abc( ) would get called now, which was not expected. Previously, there was nothing a programming language can do to retain the binary compatibility of new version of base class with existing derived class. This is not the case in C#. In C#, a function in derived class doesn't automatically become virtual if there is a virtual function with the same
Compiled by rmshankar@yahoo.com
Let's see what version support does C# provides: In C++, if a derived class contains a non-virtual function with a name abc( ) and the new version of a base class is shipped with a virtual function having the same name abc( ). This would result in an unpredictable result since the derived class version of abc( ) would get called now, which
Compiled by rmshankar@yahoo.com
Thread States... Ans: At times we may want to prevent our thread from getting CPU cycles till: 1. Passage of some time. 2. Some other thread completes some operation. 3. Some other thread terminates. We can achieve the above three scenarios by respectively calling the methods Thread.Sleep( ), Monitor.Wait( ) and Thread.Join( ) methods on our thread. Upon calling one of these three methods, our thread enters the WaitSleepJoin state. Once in this state we can transition out of it in the following three ways: 1. The sleeping time specified by the Sleep( ) method expires. 2. Another thread calls the Thread.Interrupt( ) method before the sleeping time expires. 3. Another thread calls the Monitor.Pulse( ) method or Monitor.PulseAll( ) method. Monitor.Pulse( ) moves the waiting thread into the Running state. Monitor.PulseAll( ) method moves the thread along with all the other waiting threads into the Running state. All the above three ways move the thread from the WaitSleepJoin state to the Running state. When a thread completes its execution, it goes into the Stopped state. The StopRequested state is reached when a thread is being requested to stop. There is no method available that we can invoke to manually force our thread in this state. Whenever an exception is thrown and the thread stops executing abruptly it goes into the Aborted state.
Printing With Different Units... In the Graphics methods we specify coordinates in two-dimensional coordinate system. The system has origin at left-top corner and x and y axes point to right and down respectively. All the methods take coordinates in pixels. The coordinates passed to Graphics methods are world coordinates. When we pass world coordinates to a method, they firstly get translated into page coordinates (logical coordinates) and then into device coordinates (physical coordinates). Ultimately, the shape gets drawn in device coordinates. In both the page and device coordinate system the measure of unit is same i.e. pixels. We can customize the coordinate system by setting a different measure of unit. Suppose we wish to print a line having one-inch length, for this we need to use the PageUnit
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
How do I write code if I want that the following statement should join the two corners of the form irrespective of its size? g.DrawLine ( 0, 0, 100, 100 ) ; Ans: Use the Graphics.ScaleTransform( ) method as shown below: void Form1_Paint ( object sender, PaintEventArgs e ) { Graphics g = e.Graphics ; g.ScaleTransform ( ClientSize.Width / 100.0f, ClientSize.Height / 100.0f ) ; Pen p = new Pen ( Color.Green, 1 / ( ClientSize.Width / 100.0f ) ) ; g.DrawLine ( p, 0, 0, 100, 100 ) ; } Difference Between Custom Control And User-Defined Control.. A custom control is the one which is created by extending an existing control like Label, Textbox, Buttons, etc. For example, we can derive a class from the TextBox class so that the user can enter only digits in it.
Compiled by rmshankar@yahoo.com
A user-defined control is a set of one or more existing controls (WinForm or WebForm controls). The best example of user-defined control is a media player that is a combination of several buttons, slider control and other UI elements. A user-defined control is derived from the Forms UserControl class. If we want to create a control from scratch, we can do so by deriving a class from the Control class. Asynchronous Delegate Invocation Delegates normally work synchronously. That is, they invoke the method passed to them and return only when the method returns. We can also use delegates to make an asynchronous call to the method passed to it. It means that, the delegate would initiate the method and return immediately. To invoke a delegate asynchronously, call the BeginInvoke( ) method, which will queue the method to be run on a thread from a system thread pool. The BeginInvoke( ) method accepts a reference to the method that should get called when the method called by BeginInvoke( ) ends. What is thread pooling? Ans: While programming Windows versions prior to Windows 2000, developers often started a thread to perform a particular task and when the task was complete the thread would die. The starting and closing the thread was costly in performance point of view. So, Microsoft introduced a concept called thread pool in Windows 2000. And now in .NET, thread pool has been implemented in CLR itself. And so, all the managed applications can use thread pool. Now if a managed application starts a thread, it has to ask for a thread in the thread pool. The thread pool initiates the thread just like any other normal thread. But when the task is complete, thread wont get destroyed. It would go to the thread pool in suspended state. If application makes a request for thread, again this thread would wake up and perform the task. This saves lot of overhead. The thread pool takes the responsibility of creating and killing threads, calling a method asynchronously or after a time interval, etc. As we know the code that accesses a common resource when enclosed within Monitor.Enter( ) and Monitor.Exit( ) helps in synchronizing concurrently running threads. What if one thread calls Monitor.Enter( ) twice. Will it go into the wait state since lock has already been acquired? The answer is no. This is because Enter( ) always checks which thread has acquired the resource before making the thread wait. Initially when resource is not acquired, count in the syncblock is set to zeros. When Enter( ) is called for the first time count becomes 1. If Enter( ) is called again and it finds that the same thread has acquired the resource it just increments the count without making the thread wait. This behavior seems logical otherwise the thread would have gone into indefinite wait state expecting from itself to release the resource. The Exit( ) method then decrements the count. When the Exit( ) method finds that the count has reached zero, it releases the lock and makes the waiting thread as the ready thread. What is Stack Walk? Ans: .NET security models walk the stack to check whether a program accessing a code has permission to do so. Stack walks are an essential part of the security system. A stack walk operates in the following manner. Every time a method is called a new activation record will be put on the stack. This record contains the parameters passed to the method, if any, the address to return to when this function completes and any local variables. At certain stages during execution, the thread might need to
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com
Compiled by rmshankar@yahoo.com