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 the ‘configuration’ Category

How To Use ADOMD to Return Out of Process Cellset

Symptoms
You may use ADOMD with the MSOLAP provider to return an Out of Process Cellset. This is useful with DCOM/MTS business objects. This code sample requires the MSOLAP OLEDB provider on the client computer and the Food Mart OLAP database on SQL Server OLAP Services computer. The MSOLAP OLEDB provider is installed when you install OLAP client components from SQL Server 7.0 CD.
Resolution
ServerSteps to AccomplishCreate a new Visual Basic ActiveX EXE Project. Class 1 is created by default.Set a Project Reference to the Microsoft ActiveX Data Objects (Multi-Dimensional) 1.0 Object Library.Change the name of the Project to ADOBusObj.Paste the following code into Class1:

Private strSQL As StringPrivate strConnect As StringDim adoCat As New ADOMD.CatalogPublic Function GetRs() As ADOMD.CellSetDim adoCst As New ADOMD.CellSetWith adoCstSet adoCst.ActiveConnection = adoCat.ActiveConnection.Source = strSQL.OpenEnd WithSet GetRs = adoCstEnd FunctionPrivate Property Get ConnectStr() As StringConnectStr = strConnectEnd PropertyPrivate Property Let ConnectStr(strCn As String)strConnect = strCnEnd PropertyPublic Property Get SQL() As StringSQL = strSQLEnd PropertyPublic Property Let SQL(nSQL As String)strSQL = nSQLEnd PropertyPublic Sub ADOMDConnect(strConnect As String, Optional CmdTimeOut As Integer = 20)adoCat.ActiveConnection = strConnectConnectStr = adoCnEnd Sub
ClientCreate a new Visual Basic Standard EXE Project. Form1 is created by default.Set a Project Reference to the Microsoft ActiveX Data Objects (version 2.0 or later) Library.Set a Project Reference to the ActiveX EXE ADOBusObj created earlier. Change the connection string and the SQL string to reflect your OLAP server’s configuration.Paste the following code into the General Declarations section of Form1:
NOTE: A cube query (MDX query) has the following layout that defines the number of Axes in the query. The count of the fields referenced between SELECT and FROM in the MDX statement are the number of Axes in the query.

SELECT <axis_specification> [, <axis_specification>...] FROM <cube_specification>WHERE <slicer_specification>

Option ExplicitConst strConnect = “Data Source=<DataSource>;PROVIDER=MSOLAP;INITIAL CATALOG=FoodMart”Private Sub Form_Click()On Error GoTo ErrorHandlerDim adoCst As ADOMD.CellsetDim objAdoData As ADOBusObj.Class1Dim strOutput As StringDim intStrLen As IntegerDim intDC0 As IntegerDim intDC1 As IntegerDim intPC0 As IntegerDim intPC1 As IntegerDim i As IntegerDim j As IntegerDim k As IntegerSet objAdoData = CreateObject(“ADOBusObj.Class1″)With objAdoData.SQL = “Select {[Measures].members} On Columns,” & _”Non Empty [Store].[Store City].members ” & _”Properties [Store].[Store Type], [Store].[Store Manager] ” & _”On Rows From Sales”.ADOMDConnect strConnect, 20 ‘Establish connection.End With’Return the Cellset from MD Data Object.Set adoCst = objAdoData.GetRs’it is known up front there are two axes for this query so,’just check each axis for number of dimensions.intDC0 = adoCst.Axes(0).DimensionCount – 1intDC1 = adoCst.Axes(1).DimensionCount – 1intPC0 = adoCst.Axes(0).Positions.Count – 1intPC1 = adoCst.Axes(1).Positions.Count – 1For i = 0 To intDC0For j = 0 To intPC0intStrLen = Len(adoCst.Axes(0).Positions(j).Members(i).Caption)If intStrLen > 15 Then intStrLen = 0strOutput = strOutput & “[" & adoCst.Axes(0).Positions(j).Members(i).Caption & "]” & _String(3, vbTab) & Space(15 – intStrLen)Next jNext iDebug.Print strOutput & vbCrLfFor i = 0 To intPC1strOutput = “”For j = 0 To intDC1Debug.Print “– ” & adoCst.Axes(1).Positions(i).Members(j).Caption & ” –”Next jFor k = 0 To intPC0intStrLen = Len(adoCst(k, i).FormattedValue)If intStrLen > 15 Then intStrLen = 0strOutput = strOutput & adoCst(k, i).FormattedValue & _Space(15 – intStrLen) & String(4, vbTab)Next kDebug.Print strOutputNext iMsgBox “Success”, vbOKOnly, “MD Data Object”Exit SubErrorHandler:MsgBox “Change Failed:” & vbCrLf & _Err.Number & _vbCrLf & Err.Description, _vbOKOnly, “Data Object”Exit SubEnd Sub

How To Troubleshoot Run-time Error ‘70′ in DCOM Applications

Symptoms
Attempting to access a DCOM Server from a remote client application sometimes results in the following error:

Run-time error ‘70′:
Permission Denied
This article describes the most common scenarios in which this error is raised.
Resolution
Run-time error ‘70′ is typically the result of a security or permissions issue. The following is a list of possible causes of run-time error 70 but is by no means a complete or definitive list.
DCOM Is Not Enabled If the Server machine does not have DCOM enabled, client machines will receive run-time error 70 when attempting to access the server. This scenario applies to Windows 2000, Windows NT, Windows 95, Windows 98, and Windows Millennium Edition (Me) servers:
On the Server machine, run DCOM Config (DCOMCNFG.EXE). Choose the Default Properties tab. Ensure that Enable Distributed COM on this computer is checked. This value is stored in the Windows Registry at the following location:
HKEY_LOCAL_MACHINE\Software\Microsoft\OLE
The Client User Does Not Have Sufficient Permissions If the client user does not have the correct permissions, access to the DCOM Server can be denied. There are several steps to take in order to ensure your client has valid privileges.
If the Server is Windows 95, Windows 98, or Windows Me:
Run DCOM Config. Select the DCOM Server application from the list of available applications. Select the Properties button, or double-click the DCOM Server application in the list. Test the server with “Default Access Permissions.”
If run-time error ‘70′ still occurs, the default access permissions are restricting your user. If this is the case, then modify the Default Access Permissions from the Default Security tab in DCOM Config. Grant the client user access permissions.
If run-time error ‘70′ does not occur running with default access permissions, it is likely that the custom access permissions are restricting your client from accessing the DCOM Server. Choose custom access permissions and select the Edit button. Grant the client user access permissions. If the Server is Windows NT or Windows 2000:
Run DCOM Config. Select the DCOM Server application from the list of available applications. Select the Properties button, or double-click the DCOM Server application in the list. Test the server with “Default Access Permissions,” “Default Launch Permissions,” and “Custom Configuration Permissions.”
If run-time error ‘70′ still occurs, it is likely that the default access permissions are restricting your user. If this is the case, modify the Default Access Permissions from the Default Security tab in DCOM Config.
If run-time error ‘70′ does not occur, it is likely that the custom access permissions are restricting your client from accessing the DCOM Server. Choose to use Custom access permissions and choose the Edit button. Grant the client user account access permissions, or grant a group the client user belongs to access permissions. For more information regarding security groups on Windows NT see the table to follow.
There are several group accounts you will find when you configure users and groups on Windows NT and Windows 2000. The following list is a summary of who belongs to each group:

GroupDescription————————————————————————–InteractiveIncludes all users who log onto a Windows NT orWindows 2000 system locally (at the console). Itdoes not include users who connect to NTresources across a network or are started as aserver.NetworkIncludes all users who connect to Windows NT orWindows 2000 resources across a network. It doesnot include those who connect through aninteractive logon.Creator/OwnerThe Creator/Owner group is created for eachsharable resource in the Windows NT orWindows 2000 system. Its membership is the set ofusers who either create a resource (such as afile) and who take ownership of them.EveryoneAll users who access the system, whether locally,remotely, or across the network.SystemThe local operating system.
The above list includes the group accounts which are intrinsic to Windows NT and Windows 2000 systems. Your particular network may include more groups from which you may choose. In order to determine the membership of each custom group account, you must contact your network administrator.

The DCOM Server Raises Events to the Client If your DCOM server component raises events that are handled by the client application, you must configure DCOM security on the client computer to allow access, and you must configure DCOM security on the server computer. This allows the server to make callbacks to the client, so the event can be raised. If you do not configure DCOM security in this way, error 70 is generated whenever the client application calls the server. This results in an event being raised back to the client. If the server application does not raise events, you do not have to configure DCOM security on the client computers.
If the client computer is running Windows 95, Windows 98, or Windows Me, follow these steps:
Run DCOM Config (DCOMCNFG.exe). Click the Default Security tab. Click the Edit Default button. Click the Add button. Click to select The World, and then click the Grant Access button to grant permissions. Click Ok to close the Add Access Permissions dialog box. Click Ok to close the Access Permissions dialog box. Click Ok to close the DCOM Config Properties dialog box. Test the application again.
The client application successfully handles the event.
If the client computer is running Windows NT orWindows 2000, follow these steps:
Run DCOM Config (DCOMCNFG.exe).Click the Default Security tab. Click the Edit Default button. Click the Add button.Click to select the Everyone account, and then click to select Allow Access in the Type of Access box. Click Ok. Click Ok again to close the Registry Values Permission dialog box. Click Ok to close the DCOM Config Properties dialog box. Test the application again.
The client application successfully handles the event.
Attempting to Access DCOM Server Across Non-Trusted Domains If your DCOM Server resides in one Windows NT or Windows 2000 domain, and your client logs on to a second Windows NT or Windows 2000 domain that is not “trusted” by the first, you will receive run-time error ‘70′ when attempting to access the DCOM Server.

How To Retrieve Printer Name from Windows 95/98/Me Registry in VB

Symptoms
The Registry is used by Windows 95, Windows 98, and Windows Me to determine whatapplication programs and hardware items are installed in the computersystem. This article explains how to retrieve the name of the defaultprinter from the Registry from within a Visual Basic application program.
Resolution
Manipulating the Registry in Visual BasicThe Windows 95/98/Me Registry is a database of information containingconfiguration details about the hardware and software installed in yourcomputer system. Under Windows 3.1, this information is maintained throughinitialization (INI) files.
The Registry is comprised of keys. Each key may contain a specific value orother subkeys that in turn may contain values or other subkeys. You canexamine or modify the contents of the registration database by using theWin32 Registry API functions in a Visual Basic program or by using theRegistry Editor (REGEDIT).
WARNING: 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.

The demonstration program below shows how to use the Win32 Registry APIfunctions to retrieve the default printer’s name from the Registry.
The first step to retrieve the printer name is to call the RegOpenKeyExfunction. This function opens the specified key in the registrationdatabase. In our case, we want to open the key that is associated withthe printer. This key is stored in the Registry as:

SystemCurrent Control SetControlPrintPrintersDefault All of the above items are keys and subkeys. We are interested in thePrinters subkey.
We also need to tell the RegOpenKeyEx function that we want to work withthe Default subkey. After calling this function, a value is returnedthat is set to zero if the function was successful.The next step is to retrieve the actual value stored for the key we areinterrogating. Because we want to retrieve the name that is assigned tothe default printer, we want to call the RegQueryValueEx function. Wemust tell this function that we want to retrieve the value that wasgiven to the Default subkey.The last step is mandatory. You must call the RegCloseKey function torelease the handle of the key you have been accessing in theRegistration database. This terminates access to the registrationdatabase and frees the handle for future use by the computer system.
How to Create the Demonstration ProgramThe demonstration program below shows how to retrieve the name of thedefault printer from the Windows 95, Windows 98, or Windows Me Registry.
Create a new project in Visual Basic. Form1 is created by default.Add the following constant and Declare statements to the GeneralDeclarations section of Form1:

Private Declare Function RegOpenKeyEx Lib “advapi32″ Alias _”RegOpenKeyExA” (ByVal hKey As Long, ByVal lpSubKey As String, _ByVal dwReserved As Long, ByVal samDesired As Long, phkResult _As Long) As LongPrivate Declare Function RegQueryValueEx Lib “advapi32″ Alias _”RegQueryValueExA” (ByVal hKey As Long, ByVal lpValueName$, ByVal _lpdwReserved As Long, lpdwType As Long, lpData As Any, lpcbData As _Long) As LongPrivate Declare Function RegCloseKey Lib “advapi32″ (ByVal hKey As _Long) As LongConst HKEY_CURRENT_CONFIG As Long = &H80000005 Add a Text Box control to Form1.Add a Command Button control to Form1.Add the following code to the Click event for Command1:

Private Sub Command1_Click()Dim PName As StringPName = GetCurrPrinter()Text1.Text = PNameEnd Sub Create a new procedure called GetCurrPrinter. Add the following code to this procedure:

Function GetCurrPrinter() As StringGetCurrPrinter = RegGetString$(HKEY_CURRENT_CONFIG, _”System\CurrentControlSet\Control\Print\Printers”, “Default”)End Function Create a new procedure called RegGetString. Add the following code tothis procedure:

Function RegGetString$(hInKey As Long, ByVal subkey$, ByVal valname$)Dim RetVal$, hSubKey As Long, dwType As Long, SZ As LongDim R As LongRetVal$ = “”Const KEY_ALL_ACCESS As Long = &H9F003FConst ERROR_SUCCESS As Long = 0Const REG_SZ As Long = 1R = RegOpenKeyEx(hInKey, subkey$, 0, KEY_ALL_ACCESS, hSubKey)If R <> ERROR_SUCCESS Then GoTo Quit_NowSZ = 256: v$ = String$(SZ, 0)R = RegQueryValueEx(hSubKey, valname$, 0, dwType, ByVal v$, SZ)If R = ERROR_SUCCESS And dwType = REG_SZ ThenRetVal$ = Left$(v$, SZ)ElseRetVal$ = “–Not String–”End IfIf hInKey = 0 Then R = RegCloseKey(hSubKey)Quit_Now:RegGetString$ = RetVal$End Function Execute the demonstration program by pressing the F5 function key. When youclick the Command Button control, the name of your default printer isdisplayed in the Text Box control.

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.