Visual Basic Q&A

As a software engineer, I focus on .NET, especially asp.net, C#, WCF and so on, and I am also very interested in Search Engine Optimization.

Entries for January, 2010

How To Load and Unload a User Profile into the Registry with Visual Basic

Symptoms
This article describes how to use the RegLoadKey registry function to load a user profile into the registry and, subsequently, how to use RegUnLoadKey to unload the user profile. Because RegLoadKey requires the SE_RESTORE_NAME privilege to be successful, this article also uses the OpenProcessToken, LookupPrivilegeValue, and AdjustTokenPrivileges functions.
Resolution
In part, the registry consists of files that store information about a user profile. When this file is loaded, it maps to the HKEY_USERS or HKEY_LOCAL_MACHINE key, whichever is specified in the call to RegLoadKey.
To retrieve user profile-specific information, you can load the NtUser.dat file that is located in the profile path of the user profile that you want to load. It may be necessary to load a hive (user profile) when you try to provide profile-specific data. For example, either the ImpersonateLoggedOnUser function or the CreateProcessAsUser function is generally used to run under a different security context and does not load the profile of that user.
The following steps illustrate how to load NtUser.dat and unload it when finished. These methods are not a threat to security because they only succeed if the calling process and the impersonated user have sufficient privileges.
Step-by-Step ExampleWARNING: If you use Registry Editor incorrectly, you may cause serious problems that may require you to reinstall your operating system. Microsoft cannot guarantee that you can solve problems that result from using Registry Editor incorrectly. Use Registry Editor at your own risk.
Create a new Standard EXE project in Visual Basic. Form1 is created by default.Add a TextBox control (Text1) and two CommandButton controls (Command1 and Command2) to Form1.Paste the following code into the General Declarations section of Form1:

Option ExplicitPrivate Type LUIDLowPart As LongHighPart As LongEnd TypePrivate Type LUID_AND_ATTRIBUTESpLuid As LUIDAttributes As LongEnd TypePrivate Type TOKEN_PRIVILEGESPrivilegeCount As LongPrivileges(1) As LUID_AND_ATTRIBUTESEnd TypePrivate Const TOKEN_ADJUST_PRIVLEGES = &H20Private Const TOKEN_QUERY = &H8Private Const SE_PRIVILEGE_ENABLED = &H2Private Const HKEY_USERS = &H80000003Private Const SE_RESTORE_NAME = “SeRestorePrivilege”Private Const SE_BACKUP_NAME = “SeBackupPrivilege”Private Declare Function GetCurrentProcess Lib “kernel32″ () As LongPrivate Declare Function OpenProcessToken Lib “advapi32.dll” _(ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, _TokenHandle As Long) As LongPrivate Declare Function LookupPrivilegeValue Lib “advapi32.dll” Alias _”LookupPrivilegeValueA” (ByVal lpSystemName As String, _ByVal lpName As String, lpLuid As LUID) As LongPrivate Declare Function AdjustTokenPrivileges Lib “advapi32.dll” _(ByVal TokenHandle As Long, ByVal DisableAllPrivileges As Long, _NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, _ByVal PreviousState As Long, ByVal ReturnLength As Long) As LongPrivate Declare Function RegLoadKey Lib “advapi32.dll” Alias “RegLoadKeyA” _(ByVal hKey As Long, ByVal lpSubKey As String, ByVal lpFile As String) _As LongPrivate Declare Function RegUnLoadKey Lib “advapi32.dll” Alias “RegUnLoadKeyA” _(ByVal hKey As Long, ByVal lpSubKey As String) As LongPrivate Retval As LongPrivate strKeyName As StringPrivate MyToken As LongPrivate TP As TOKEN_PRIVILEGESPrivate RestoreLuid As LUIDPrivate BackupLuid As LUIDPrivate Sub Form_Load()strKeyName = “keyLoaded”‘ Path to file on Windows NT: C:\WinNT\Profiles\<Profile Name>\NtUser.Dat’ Path to file on Windows 2000: C:\Documents and Settings\<Profile Name>\NtUser.DatText1.Text = “<Path to File>”Command2.Enabled = FalseRetval = OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVLEGES _Or TOKEN_QUERY, MyToken)If Retval = 0 Then MsgBox “OpenProcess: ” & Err.LastDllErrorRetval = LookupPrivilegeValue(vbNullString, SE_RESTORE_NAME, _RestoreLuid)If Retval = 0 Then MsgBox “LookupPrivileges: ” & Err.LastDllErrorRetval = LookupPrivilegeValue(vbNullString, SE_BACKUP_NAME, BackupLuid)If Retval = 0 Then MsgBox “LookupPrivileges: ” & RetvalTP.PrivilegeCount = 2TP.Privileges(0).pLuid = RestoreLuidTP.Privileges(0).Attributes = SE_PRIVILEGE_ENABLEDTP.Privileges(1).pLuid = BackupLuidTP.Privileges(1).Attributes = SE_PRIVILEGE_ENABLEDRetval = AdjustTokenPrivileges(MyToken, vbFalse, TP, Len(TP), 0&, 0&)If Retval = 0 Then MsgBox “AdjustTokenPrivileges: ” & Err.LastDllErrorEnd SubPrivate Sub Command1_Click()Retval = RegLoadKey(HKEY_USERS, strKeyName, Text1.Text)If Retval <> 0 Then MsgBox “RegLoadKey: ” & RetvalCommand2.Enabled = TrueEnd SubPrivate Sub Command2_Click()Retval = RegUnLoadKey(HKEY_USERS, strKeyName)If Retval <> 0 Then MsgBox “RegUnloadKey: ” & RetvalEnd SubPrivate Sub Form_Unload(Cancel As Integer)Retval = AdjustTokenPrivileges(MyToken, vbTrue, TP, Len(TP), 0&, 0&)If Retval = 0 Then MsgBox “AdjustTokenPrivileges: ” & Err.LastDllErrorEnd Sub Save the project, and then press the F5 key to run it.Type the path to a specific user profile .dat file, for example:
C:\WinNT\Profiles\Administrator\NtUser.dat and then click Command1.Click Start, click Run, type regedit (on Windows NT) or regedt32 (on Windows 2000), and then click OK.Locate the HKEY_USERS subtree. Notice that this subtree includes the new key, KeyLoaded.In the Visual Basic project, click Command2 to remove this key from the registry.

How To Log On to a Terminal Server Session Programmatically from Visual Basic

Symptoms
The Terminal Services ActiveX client control does not expose the ImsTscNonScriptable interface. However, this interface can be used to configure automatic log on for a Terminal Services Session programmatically, which enables the programmer to log a user on to a Terminal Services Session without receiving the Windows Logon prompt. This is demonstrated in the sample in the “More Information” section.
Resolution
To run this program, configure your Terminal Server computer as follows: Log on to the Terminal Server locally as an administrator.On the Start button, click Programs, click Administrative Tools, and then click Terminal Services Configuration.Click on Connections.In the right pane, right-click RDP-Tcp, and then choose Properties.Click on the Logon Settings tab.Deselect Always prompt for password, and then click OK.NOTE: For security reasons, Microsoft recommends that you do not implement this scenario without extreme care and a clear understanding of Microsoft Windows security.
Sample CodeStart a new Standard EXE project. Form1 is created by default.On the Project menu, click to select Components, select Microsoft Terminal Services Control(redist), and then click OK. If this control is not available, see the “References” section of this article for information on how to download and install it.Add one Terminal Services Control to Form1, making sure it is big enough to handle the display of the session.Add three Label controls, three TextBox controls, and one CommandButton control to Form1. Make sure that Lable1 and Text1 are on the same line, and that Label2, Text2, Label3, and Text3 are on the same line.Paste the following code into the General Declarations of Form1:

‘ This code only works when you set the configuration on the Server-side.’ Log on to the Terminal Server as an administrator’ Start\Programs\Administrative Tools\Terminal Services Configuration’ Click on Connections’ On the Right Pane, right-click on RDP-Tcp and choose Properties’ Click on the “Logon Settings” Tab’ Uncheck “Always prompt for password” and click OKOption ExplicitPrivate Obj As IMsTscNonScriptablePrivate Sub Form_Load()Text1.Text = “”Text2.Text = “”Text3.Text = “”Label1.Caption = “Server”Label2.Caption = “UserName”Label3.Caption = “Password”Command1.Caption = “Connect”Text3.PasswordChar = “*”End SubPrivate Sub Command1_Click()Set Obj = MsTscAx1.ObjectMsTscAx1.Server = Text1.TextMsTscAx1.UserName = Text2.TextObj.ClearTextPassword = Text3.TextMsTscAx1.ConnectEnd Sub Save the project, press the F5 key to run it, and note that after you supply your username, password, and server name, you are not prompted for a logon screen at the server. Microsoft recommends that you enlarge the Terminal Server .ocx file so that you are able to manipulate the Shut Down dialog box.

How To Improve String Concatenation Performance

Symptoms
When concatenating large strings on the order of 50kb or larger (for example, building an HTML table from a database), the length of time to complete can become quite long as the string gets larger. This article demonstrates an alternative to normal concatenation that can improve performance for large strings by 20 times or more.
Resolution
When performing repeated concatenations of the type:

For I = 1 To NDest = Dest & SourceNext N the length of time increases proportionally to N-squared. Therefore, 1000 iterations will take about 100 times longer than 100 iterations. This is because Visual Basic does not just add the Source characters to the end of the Dest string; it also performs the following operations:
Allocates temporary memory large enough to hold the result. Copies Dest to the start of the temporary area. Copies Source to the end of the temporary area. De-allocates the old copy of Dest. Allocates memory for Dest large enough to hold the result. Copies the temporary data to Dest. Steps 2 and 6 are very expensive and basically result in the entire concatenated result being copied twice with additional overhead to allocate and de-allocate memory.
This article details a method using the Mid$ statement and pre-allocating memory in larger chunks to eliminate all but step 3 above for most of the concatenation phase.
WARNING: ANY USE BY YOU OF THE CODE PROVIDED IN THIS ARTICLE IS AT YOUR OWN RISK. Microsoft provides this code “as is” without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.
Step-by-Step ExampleType the following code into a module:

Option Explicit’ For 16-bit products, uncomment the next three lines by removing the’ single quotes and add a single quote to comment out the following’ three lines.’Const ConcatStr = “ABC”‘Const ccIncrement = 15000′Declare Function GetTickCount Lib “USER” () As LongConst ConcatStr = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”Const ccIncrement = 50000Private Declare Function GetTickCount Lib “KERNEL32″ () As LongDim ccOffset As LongSub StdConcat(ByVal LoopCount As Long)Dim BigStr As String, I As Long, StartTick As LongStartTick = GetTickCount()For I = 1 To LoopCountBigStr = BigStr & ConcatStrNext IDebug.Print LoopCount; “concatenations took”;Debug.Print GetTickCount() – StartTick; “ticks”End SubSub Test_Concat()Debug.Print “Using standard concatenation”StdConcat 1000StdConcat 2000StdConcat 3000StdConcat 4000StdConcat 5000Debug.PrintDebug.Print “Using pre-allocated storage and pseudo-concatenation”MidConcat 1000MidConcat 2000MidConcat 3000MidConcat 4000MidConcat 5000End SubSub Concat(Dest As String, Source As String)Dim L As LongL = Len(Source)If (ccOffset + L) >= Len(Dest) ThenIf L > ccIncrement ThenDest = Dest & Space$(L)ElseDest = Dest & Space$(ccIncrement)End IfEnd IfMid$(Dest, ccOffset + 1, L) = SourceccOffset = ccOffset + LEnd SubSub MidConcat(ByVal LoopCount As Long)Dim BigStr As String, I As Long, StartTick As LongStartTick = GetTickCount()ccOffset = 0For I = 1 To LoopCountConcat BigStr, ConcatStrNext IBigStr = Left$(BigStr, ccOffset)Debug.Print LoopCount; “pseudo-concatenations took”;Debug.Print GetTickCount() – StartTick; “ticks”End Sub In the Debug/Immediate Window, type Test_Concat, and hit the Enter key.
The results will look similar to:

Using standard concatenation1000 concatenations took 2348 ticks2000 concatenations took 8954 ticks3000 concatenations took 20271 ticks4000 concatenations took 35103 ticks5000 concatenations took 54453 ticksUsing pre-allocated storage and pseudo-concatenation1000 pseudo-concatenations took 82 ticks2000 pseudo-concatenations took 124 ticks3000 pseudo-concatenations took 165 ticks4000 pseudo-concatenations took 247 ticks5000 pseudo-concatenations took 289 ticks
Additional InformationThe code may take a couple of minutes to run. GetTickCount returns the number of milliseconds since Windows was started. Therefore, the output is in milliseconds. Performance improvement ranges from almost 30 times for the 1000-iteration case to almost 200 times for the 5000-iteration case. These times may vary depending on:
The product used. Your system configuration..The size of ccIncrement (larger size favors MidConcat).The number of iterations used (more iterations favors MidConcat).The size of the resultant string (larger size favors MidConcat).

How to load an assembly at runtime that is located in a folder that is not the bin folder of the application

Symptoms
You do not have to put an assembly that an application must use at runtime in the bin folder of the application. You can put the assembly in any folder on the system, and then youcan refer to the assembly at runtime.
Resolution
This step-by-step article describes three methods that you can useto refer to the assemblies that are located in folders that are not the bin folder of the application.
RequirementsThis article assumes that you are familiar with the following topics: General familiarity with Microsoft Visual Basic .NET or Microsoft Visual Basic 2005 or with Microsoft Visual C# .NET or Microsoft Visual C# 2005General familiarity with assemblies in Visual Basic .NET or Visual Basic 2005and in Visual C# .NET or Microsoft Visual C# 2005General familiarity with .config files in Visual Basic .NET or Visual Basic 2005 and in Visual C# .NET or Microsoft Visual C# 2005The following list outlines the recommended hardware, software, network infrastructure, and service packs that you need:The Microsoft .NET FrameworkMicrosoft Visual Studio .NET or Microsoft Visual Studio 2005
Method 1: Install the assembly in the global assembly cache (GAC)The GAC is a computer-wide code cache where the common language runtime is installed. The GAC stores assemblies that you specifically designate to be shared by several applications.
Note You can only install strong-named assemblies in the GAC.
To install an assembly in the GAC, follow these steps: StartVisual Studio .NET or Visual Studio 2005. On the File menu, point to New, and then click Project.
The New Project dialog box appears.Under Project Types, click Visual Basic .NET, or click Visual C# .NET.
Note In Visual Studio 2005, click Visual Basic or click Visual C#.Under Templates, click Class Library. In the Name box, type MyAssembly1.In the Location box,type C:\Myassemblies.
By default, the Class1.vb file is created byVisual Basic .NET or Visual Basic 2005. By default, the Class1.cs file is created byVisual C# .NET or Visual C# 2005. Add the following code tothe Class1 class of the Class1.vb file or of the Class1.cs file.
Visual Basic .NET or Visual Basic 2005 code

Public Function HelloWorld() As StringReturn “From Class Library “End FunctionVisual C# .NET or Visual C# 2005 code

public string HelloWorld(){ return “From Class Library”;}On the File menu,click Save All to save the solution.Install the MyAssembly1 assembly in the GAC.
For more information about how to do this in Visual Basic .NET, click the following article number to view the article in the Microsoft Knowledge Base:
315682?(http://support.microsoft.com/kb/315682/) How to install an assembly in the global assembly cache in Visual Basic. NETFor more information bout how to do this in Visual C# .NET, click the following article number to view the article in the Microsoft Knowledge Base:
815808?(http://support.microsoft.com/kb/815808/) How to install an assembly into the global assembly cache in Visual C# .NETCreate a new client application. To do this,follow these steps:In Visual Studio .NET or Visual Studio 2005, create a new Visual Basic .NET or Visual Basic 2005 Windows application or a new Visual C# .NET or Visual C# 2005 Windows application that is named TestClient1.
By default, the Form1.vb file is created by Visual Basic .NET or Visual Basic 2005. By default,the Form1.cs file is created by Visual C# .NET or Visual C# 2005.In Solution Explorer, right-click Add Reference.
The Add Reference dialog box appears.Click Browse, locateC:\MyAssembly, click the MyAssembly1 assembly, and thenclick Open.
Note In this step, C:\MyAssembly is a placeholder for theactual location of the MyAssembly1 assembly.Add the following code to the Form1_Load event of the Form1.vb file or of the Form1.cs file as follows:
Visual Basic .NET or Visual Basic 2005 code

Dim obj1 As New MyAssembly1.Class1()MessageBox.Show(obj1.HelloWorld())Visual C# .NET or Visual C# 2005 code

MyAssembly1.Class1 obj1=new MyAssembly1.Class1();MessageBox.Show(obj1.HelloWorld());On the Debug menu, click Start to build and to run the application.
Method 2: Use an application configuration (.config) file with the <codeBase> tagsA .config file containsthe following settings:Settings that are specific to an applicationSettings that the common language runtime reads, such as the assembly binding policy settings and the remoting objects settingsSettings that the application readsThe <codeBase> tags specify where the common language runtime can find an assembly. The common language runtime applies the settings of the <codeBase> tags from the .config file.The settings of the <codeBase> tags determine the version and the location of the assembly.
To use a .config file with the <codeBase> tags to refer to the assemblies, follow these steps:Create a new Class Library project that isnamed MyAssembly2 by following steps 1 through6 of the “Method 1: Install the assembly in the global assembly cache (GAC)” section.Make the assembly strong-named.
For additional information about how to do this, click either of the article numbers that are mentioned in step 8 of the “Method 1: Install the assembly in the global assembly cache (GAC)” section.Create a new client application. To do this,follow these steps:In Visual Studio .NET or Visual Studio 2005, create a new Visual Basic .NET or Visual Basic 2005Windows application or a new Visual C# .NET or Visual C# 2005 Windows application that is named TestClient2.
By default,the Form1.vb file iscreated by Visual Basic .NET or Visual Basic 2005. By default,the Form1.cs file is created by Visual C# .NET or Visual C# 2005. In Solution Explorer, right-click Add reference.
The Add Reference dialog box appears.Click Browse, click theMyAssembly2 assembly, and then click Open.Under References, right-click MyAssembly2, and then click Properties.
The Properties window appears.In the Properties window, set the Copy Local property of the assembly to False. Add the following code to the Form1_Load event of the Form1.vb file or of the Form1.cs file as follows:
Visual Basic .NET or Visual Basic 2005 code

Dim obj2 As New MyAssembly2.Class1()MessageBox.Show(obj2.HelloWorld())Visual C# .NET or Visual C# 2005 code

MyAssembly2.Class1 obj2=new MyAssembly2.Class1();MessageBox.Show(obj2.HelloWorld());On the Build menu, click Build Solution.Find the publicKeyToken attribute number of the assembly that you created. To do this,follow these steps: At the Visual Studio .NET or Visual Studio 2005 command prompt, locate the following folder:
C:\MyAssemblies\MyAssembly2\bin\debug
Note To find the publicKeyToken attribute number, locatethe folder that containsyour compiled library assembly. Typically, this is the bin folder in your project folder that is mentioned previously in this step.Type the following command:
SN -T MyAssembly2.dll
Note You must use a capital letter “T” to obtain the correct public key.
The command returns a hexadecimal value that represents the publicKeyToken attributenumber of the assembly.To find the version number of the assembly, follow these steps: In Microsoft Windows Explorer, locate the following folder:
C:\Myassemblies\MyAssembly2\bin\debug Right-click the MyAssembly2.dll file, and then click Properties.
The Properties window appears.In the Properties window, click the Version tab.
Note The assembly version is specified in the Value section.Use the publicKeyToken attribute number and the version number to identify the correct assembly.
Note You must provide the publicKeyToken attribute number, the version number, and the path of the MyAssembly2.dll file that uses the <codeBase> tags to refer to theMyAssembly2.dll file at runtime.Adda .config file to the project. To do this,follow these steps:On the Project menu, click Add New Item.In the Add New Item dialog box, click Application configuration file under Templates. Make sure that the file name is App.config, and then click Open.Add the following code to the file:

<configuration><runtime><assemblyBinding xmlns=”urn:schemas-microsoft-com:asm.v1″><dependentAssembly><assemblyIdentity name=”MyAssembly2″culture=”neutral” publicKeyToken=”307041694a995978″/><codeBase version=”1.0.1524.23149″ href=”FILE://C:/Myassemblies/MyAssembly2.dll”/></dependentAssembly></assemblyBinding></runtime></configuration>Note The TestClient2.exe.config file is locatedin the Debug folder or in the Release folder. Both of these folders are locatedin the bin folder. The solution configuration mode that you select determines the location of the TestClient2.exe.config file.Make the following changes in the <assemblyIdentity> tags: Change the name attribute to the name of your library assembly.Change the publicKeyToken attribute to the public key that you determined in step 4 of this section.Make the following changes in the <codeBase> tags: Change the version attribute to the version number of the assembly that you determined in step 5 of this section.Change the href attribute to the path where the DLL is located.On the Debug menu, click Start to build the project,and thenrun the application.
Method 3: Use the AssemblyResolve eventThe AssemblyResolve event fires whenever the common language runtime tries to bind to an assembly and fails. You can use the AddHandler method to add an event handler to the application that returns the correct assembly whenever the AssemblyResolve event fires.
The AssemblyResolve event handler must return an [Assembly] object, and the common language runtime must bind to this object. Typically, you can use the Assembly.LoadFrom method to load the assembly and then to return the object. To do this, follow these steps: Create a new Class Library project that is named MyAssembly3 by following steps 1 through7 of the “Method 1: Install the assembly in the global assembly cache (GAC)” section.Create a new client application. To do this,follow these steps:In Visual Studio .NET or Visual Studio 2005, create a new Visual Basic .NET or Visual Basic 2005 Windows application or create a new Visual C# .NET or Visual C# 2005 Windows application that is named TestClient3.
By default, the Form1.vb file is created by Visual Basic .NET or Visual Basic 2005. By default, the Form1.cs fileis created by Visual C# .NET or Visual C# 2005.Add a Button control to the Form1.vb file or to the Form1.cs file.Double-click the Button1 control, and then add the following code to the Button1_Click event:
Visual Basic .NET or Visual Basic 2005 code

Dim obj3 As New MyAssembly3.Class1()MessageBox.Show(obj3.HelloWorld())Visual C# .NET or Visual C# 2005 code

MyAssembly3.Class1 obj3=new MyAssembly3.Class1();MessageBox.Show(obj3.HelloWorld()); In Solution Explorer, right-click Add reference.
The Add Reference dialog box appears.Click Browse, click the MyAssembly3 assembly, and then click Open.In the References folder, right-click the MyAssembly3 assembly, and then click Properties.
The Properties window appears.In the Properties window, set the Copy Local property of the assembly to False.Add an event handler to the AssemblyResolve event in the Form1_Load event as follows:
Visual Basic .NET or Visual Basic 2005 code

AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf MyResolveEventHandlerVisual C# .NET or Visual C# 2005 code

AppDomain currentDomain = AppDomain.CurrentDomain;currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);Define the MyResolveEventHandler function as follows:
Visual Basic .NET or Visual Basic 2005 code

Function MyResolveEventHandler(ByVal sender As Object, _ByVal args As ResolveEventArgs) As [Assembly]‘This handler is called only when the common language runtime tries to bind to the assembly and fails.’Retrieve the list of referenced assemblies in an array of AssemblyName.Dim objExecutingAssemblies As [Assembly]objExecutingAssemblies = [Assembly].GetExecutingAssembly()Dim arrReferencedAssmbNames() As AssemblyNamearrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies()’Loop through the array of referenced assembly names.Dim strAssmbName As AssemblyNameFor Each strAssmbName In arrReferencedAssmbNames’Look for the assembly names that have raised the “AssemblyResolve” event.If (strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(“,”)) = args.Name.Substring(0, args.Name.IndexOf(“,”))) Then’Build the path of the assembly from where it has to be loaded.Dim strTempAssmbPath As StringstrTempAssmbPath = “C:\assemblies\” & args.Name.Substring(0, args.Name.IndexOf(“,”)) & “.dll” Dim MyAssembly as [Assembly]‘Load the assembly from the specified path.MyAssembly = [Assembly].LoadFrom(strTempAssmbPath)’Return the loaded assembly.Return MyAssemblyEnd IfNextEnd FunctionVisual C# .NET or Visual C# 2005 code

private Assembly MyResolveEventHandler(object sender,ResolveEventArgs args){ //This handler is called only when the common language runtime tries to bind to the assembly and fails. //Retrieve the list of referenced assemblies in an array of AssemblyName. Assembly MyAssembly,objExecutingAssemblies; string strTempAssmbPath=”"; objExecutingAssemblies=Assembly.GetExecutingAssembly(); AssemblyName [] arrReferencedAssmbNames=objExecutingAssemblies.GetReferencedAssemblies(); //Loop through the array of referenced assembly names. foreach(AssemblyName strAssmbName in arrReferencedAssmbNames) { //Check for the assembly names that have raised the “AssemblyResolve” event. if(strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(“,”))==args.Name.Substring(0, args.Name.IndexOf(“,”))) { //Build the path of the assembly from where it has to be loaded. strTempAssmbPath=”C:\\Myassemblies\\”+args.Name.Substring(0,args.Name.IndexOf(“,”))+”.dll”; break; } } //Load the assembly from the specified path. MyAssembly = Assembly.LoadFrom(strTempAssmbPath); //Return the loaded assembly. return MyAssembly; }On the Debug menu, click Start to run the application.
Note You must import the System.Reflection namespace to run this application.Click Button1 to call the HelloWorld() method of the MyAssembly3 assembly.

How to implement the Dispose method in a derived class in Visual Basic .NET or in Visual Basic 2005

Symptoms
When you author a class that extends a base class, you need to somehow handle the release of allocated resources. To do this, the Dispose method from the base class should be overridden in the derived classes.This article discusses common problems encountered in this scenario, how to properly override the Dispose method, and is meant to clarify some of the subtleties in the following Visual Basic .NET help article:
http://msdn2.microsoft.com/en-us/library/fs2xkftw(vs.71).aspx(http://msdn2.microsoft.com/en-us/library/fs2xkftw(vs.71).aspx) Refer to this Help document for detailed information about error handling and for general examples of the Dispose method.
Resolution
A base class needs to contain an overloaded set of Dispose methods.The first instance of the sample code that follows is a version without parameters, and the second instance accepts a Boolean parameter:

‘Method that is called by Public to ensure TRUE is passed to DisposePublic Overloads Notoverridable Sub Dispose()Dispose( TRUE )’ Take yourself off of the finalization queue.GC.SuppressFinalize(Me)End Sub’Method that does the actual disposal of resourcesProtected Overloads Overridable Sub Dispose(ByVal disposing As Boolean)’Clean Up ResourcesEnd Sub
Dispose() is the method that is called when an object is disposed of in the code in which the object was created. This is a Public method, and therefore it can be used when an instance of the class exists.The Dispose() method then calls the Dispose(Boolean) method and passes a value of TRUE. The Dispose(Boolean) method is responsible for cleaning up the resources of the class.
When a class is derived from a base class, only the Dispose(Boolean) method needs to be overridden. All resource-cleanup for the derived class will be performed in this overridden method, and then the Dispose(Boolean) method for the base class is called. The following is a primitive example of the function overriding the base class:

Protected Overloads Overrides Sub Dispose(disposing As Boolean)’Clean Up ResourcesMyBase.Dispose( disposing )End Sub The derived class does not need a Dispose() method, because that method is inherited from the base class. When Dispose() is called on an instance of the derived class, Dispose() uses the Dispose(Boolean) of the derived class rather than the one in the base class. It is then important that the Dispose(Boolean) method of the derived class calls the Dispose(Boolean) method of the base class. This is done by means of the MyBase.Dispose(disposing) method. The Dispose(Boolean) method for the base class must be called to ensure that the resources of the base class are also disposed of.
Dispose() is meant as an entry point for public access to the disposal of an object and to ensure that TRUE is passed to the Dispose(Boolean) method. FALSE should be passed only when the Dispose(Boolean) method is called by the runtime or Finalize method. When FALSE is passed, only the unmanaged resources will be disposed. When TRUE is passed, both the managed and unmanaged resources are disposed.
The Visual Studio Development Environment inserts the code to override the Dispose() method into a class that inherits a system object (for example, Inherits System.Windows.Forms.TextBox). This is performed from the menus (at the top of the code window, by default) by selecting Overrides and then clicking Dispose(). The code that is inserted looks something like the following:

Public Overloads Overrides Sub Dispose()’Clean Up ResourcesEnd Sub If this is done, no compile errors are raised. However, when the derived class is loaded at runtime, you receive a runtime error message similar to the following:

An unhandled exception of type ‘System.TypeLoadException’ occurred in system.windows.forms.dll.
Additional information: Declaration referenced in a method implementation can not be a final method. Type: ClassLibrary1.UserControl1. Assembly: Dispose.NOTE: The Type value will be different from that in the preceding example. That is merely the name of the class that attempted to use an improperly overridden Dispose() method.
To correct this issue, just overload the Dispose(Boolean) method instead of Dispose(), and make sure that a call is made to the Dispose(Boolean) method of the base class and that TRUE is passed to it.
NOTE: In Visual Basic .NET or in Visual Basic 2005, the Overridable keyword is used like the Virtual keyword in C# and C++.Methods are, by default, NotOverridable.

How to implement impersonation in an ASP.NET application

Symptoms
This article describes different ways to implement impersonation in an ASP.NET application.
Resolution
If you want to impersonate a user on a thread in ASP.NET, you can use one of the following methods, based on your requirments: Impersonate the IIS authenticated account or userImpersonate a specific user for all the requests of an ASP.NET application Impersonate the authenticating user in codeImpersonate a specific user in codeNote You can use the following code to determine what user the thread is executing as:

System.Security.Principal.WindowsIdentity.GetCurrent().Name
Impersonate the IIS Authenticated Account or User To impersonate the Microsoft Internet Information Services (IIS) authenticating user on every request for every page in an ASP.NET application, you must include an <identity> tag in the Web.config file of this application and set the impersonate attribute to true. For example:

<identity impersonate=”true” />
Impersonate a Specific User for All the Requests of an ASP.NET Application To impersonate a specific user for all the requests on all pages of an ASP.NET application, you can specify the userName and password attributes in the <identity> tag of the Web.config file for that application. For example:

<identity impersonate=”true” userName=”accountname” password=”password” /> Note The identity of the process that impersonates a specific user on a thread must have the “Act as part of the operating system” privilege. By default, the Aspnet_wp.exe process runs under a computer account named ASPNET. However, this account does not have the required privileges to impersonate a specific user. You receive an error message if you try to impersonate a specific user. This information applies only to the .NET Framework 1.0. This privilege is not required for the .NET Framework 1.1.
To work around this problem, use one of the following methods: Grant the “Act as part of the operating system” privilege to the ASPNET account (the least privileged account).
Note Although you can use this method to work around the problem, Microsoft does not recommend this method.Change the account that the Aspnet_wp.exe process runs under to the System account in the <processModel> configuration section of the Machine.config file.
Impersonate the Authenticating User in Code To impersonate the authenticating user (User.Identity) only when you run a particular section of code, you can use the code to follow. This method requires that the authenticating user identity is of type WindowsIdentity.
Visual Basic .NET

Dim impersonationContext As System.Security.Principal.WindowsImpersonationContextDim currentWindowsIdentity As System.Security.Principal.WindowsIdentitycurrentWindowsIdentity = CType(User.Identity, System.Security.Principal.WindowsIdentity)impersonationContext = currentWindowsIdentity.Impersonate()’Insert your code that runs under the security context of the authenticating user here.impersonationContext.Undo() Visual C# .NET

System.Security.Principal.WindowsImpersonationContext impersonationContext;impersonationContext =((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();//Insert your code that runs under the security context of the authenticating user here.impersonationContext.Undo(); Visual J# .NET

System.Security.Principal.WindowsImpersonationContext impersonationContext;impersonationContext =((System.Security.Principal.WindowsIdentity)get_User().get_Identity()).Impersonate();//Insert your code that runs under the security context of the authenticating user here.impersonationContext.Undo();
Impersonate a Specific User in Code To impersonate a specific user only when you run a particular section of code, use the following code:
Visual Basic .NET

<%@ Page Language=”VB” %><%@ Import Namespace = “System.Web” %><%@ Import Namespace = “System.Web.Security” %><%@ Import Namespace = “System.Security.Principal” %><%@ Import Namespace = “System.Runtime.InteropServices” %><script runat=server>Dim LOGON32_LOGON_INTERACTIVE As Integer = 2Dim LOGON32_PROVIDER_DEFAULT As Integer = 0Dim impersonationContext As WindowsImpersonationContextDeclare Function LogonUserA Lib “advapi32.dll” (ByVal lpszUsername As String, _ByVal lpszDomain As String, _ByVal lpszPassword As String, _ByVal dwLogonType As Integer, _ByVal dwLogonProvider As Integer, _ByRef phToken As IntPtr) As IntegerDeclare Auto Function DuplicateToken Lib “advapi32.dll” ( _ByVal ExistingTokenHandle As IntPtr, _ByVal ImpersonationLevel As Integer, _ByRef DuplicateTokenHandle As IntPtr) As IntegerDeclare Auto Function RevertToSelf Lib “advapi32.dll” () As LongDeclare Auto Function CloseHandle Lib “kernel32.dll” (ByVal handle As IntPtr) As LongPublic Sub Page_Load(ByVal s As Object, ByVal e As EventArgs)If impersonateValidUser(“username”, “domain”, “password”) Then’Insert your code that runs under the security context of a specific user here.undoImpersonation()Else’Your impersonation failed. Therefore, include a fail-safe mechanism here.End IfEnd SubPrivate Function impersonateValidUser(ByVal userName As String, _ByVal domain As String, ByVal password As String) As BooleanDim tempWindowsIdentity As WindowsIdentityDim token As IntPtr = IntPtr.ZeroDim tokenDuplicate As IntPtr = IntPtr.ZeroimpersonateValidUser = FalseIf RevertToSelf() ThenIf LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT, token) <> 0 ThenIf DuplicateToken(token, 2, tokenDuplicate) <> 0 ThentempWindowsIdentity = New WindowsIdentity(tokenDuplicate)impersonationContext = tempWindowsIdentity.Impersonate()If Not impersonationContext Is Nothing ThenimpersonateValidUser = TrueEnd IfEnd IfEnd IfEnd IfIf Not tokenDuplicate.Equals(IntPtr.Zero) ThenCloseHandle(tokenDuplicate)End IfIf Not token.Equals(IntPtr.Zero) ThenCloseHandle(token)End IfEnd FunctionPrivate Sub undoImpersonation()impersonationContext.Undo()End Sub</script>Visual C# .NET

<%@ Page Language=”C#”%><%@ Import Namespace = “System.Web” %><%@ Import Namespace = “System.Web.Security” %><%@ Import Namespace = “System.Security.Principal” %><%@ Import Namespace = “System.Runtime.InteropServices” %><script runat=server>public const int LOGON32_LOGON_INTERACTIVE = 2;public const int LOGON32_PROVIDER_DEFAULT = 0;WindowsImpersonationContext impersonationContext; [DllImport("advapi32.dll")]public static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]public static extern bool RevertToSelf();[DllImport("kernel32.dll", CharSet=CharSet.Auto)]public static externbool CloseHandle(IntPtr handle);public void Page_Load(Object s, EventArgs e){ if(impersonateValidUser(“username”, “domain”, “password”)) { //Insert your code that runs under the security context of a specific user here. undoImpersonation(); } else { //Your impersonation failed. Therefore, include a fail-safe mechanism here. }}private bool impersonateValidUser(String userName, String domain, String password){ WindowsIdentity tempWindowsIdentity; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if(RevertToSelf()) { if(LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) { if(DuplicateToken(token, 2, ref tokenDuplicate) != 0) { tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); impersonationContext = tempWindowsIdentity.Impersonate(); if (impersonationContext != null) { CloseHandle(token); CloseHandle(tokenDuplicate); return true; } } } } if(token!= IntPtr.Zero) CloseHandle(token); if(tokenDuplicate!=IntPtr.Zero) CloseHandle(tokenDuplicate); return false;}private void undoImpersonation(){ impersonationContext.Undo();}</script>Visual J# .NET

<%@ Page language=”VJ#” %><%@ Import Namespace=”System.Web” %><%@ Import Namespace=”System.Web.Security” %><%@ Import Namespace=”System.Security.Principal” %><%@ Import Namespace=”System.Runtime.InteropServices” %><script runat=server>public static int LOGON32_LOGON_INTERACTIVE = 2;public static int LOGON32_PROVIDER_DEFAULT = 0;WindowsImpersonationContext impersonationContext; /** @attribute DllImport(“advapi32.dll”) */ public static native int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, System.IntPtr[] phToken);/** @attribute DllImport(“advapi32.dll”, CharSet=CharSet.Auto, SetLastError=true) */ public static native int DuplicateToken(System.IntPtr hToken, int impersonationLevel, System.IntPtr[] hNewToken);/** @attribute DllImport(“kernel32.dll”,CharSet=CharSet.Auto) */ public static nativeboolean CloseHandle(System.IntPtr[] handle);/** @attribute DllImport(“advapi32.dll”, CharSet=CharSet.Auto,SetLastError=true) */ public static native boolean RevertToSelf();public void Page_Load(Object s, System.EventArgs e){ if(impersonateValidUser(“username”, “domain”, ” password”)) { //Insert your code that runs under the security context of a specific user here. undoImpersonation(); } else { //Your impersonation failed. Therefore, include a fail-safe mechanism here. }}private boolean impersonateValidUser(String userName, String domain, String password){ WindowsIdentity tempWindowsIdentity; System.IntPtr[] token = new System.IntPtr[1]; System.IntPtr[] tokenDuplicate = new System.IntPtr[1]; if(RevertToSelf()) { if(LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, token) != 0) { if(DuplicateToken(token[0], 2, tokenDuplicate) != 0) { tempWindowsIdentity = new WindowsIdentity(tokenDuplicate[0]); impersonationContext = tempWindowsIdentity.Impersonate(); if (impersonationContext != null) { CloseHandle(tokenDuplicate); CloseHandle(token); return true; } } } } if(!token[0].Equals(System.IntPtr.Zero)) CloseHandle(token); if(!tokenDuplicate[0].Equals(System.IntPtr.Zero)) CloseHandle(tokenDuplicate); return false;}private void undoImpersonation(){ impersonationContext.Undo();}</script> Note The identity of the process that impersonates a specific user on a thread must have the “Act as part of the operating system” privilege if the Aspnet_wp.exe process is running on a Microsoft Windows 2000-based computer. The “Act as part of the operating system” privilege is not required if the Aspnet_wp.exe process is running on a Windows XP-based computer or on a Windows Server 2003-based computer. By default, the Aspnet_wp.exe process runs under a computer account named ASPNET. However, this account does not have the required privileges to impersonate a specific user. You receive an error message if you try to impersonate a specific user. .
To work around this problem, use one of the following methods: Grant the “Act as part of the operating system” privilege to the ASPNET account.
Note We do not recommend this method to work around the problem.Change the account that the Aspnet_wp.exe process runs under to the System account in the <processModel> configuration section of the Machine.config file.