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 Tagged ‘column’

How To Access and Modify SQL Server BLOB Data by Using the ADO Stream Object

Symptoms
The Stream object introduced in ActiveX Data Objects (ADO) 2.5 can be used to greatly simplify the code that needs to be written to access and modify Binary Large Object (BLOB) data in a SQL Server Database. The previous versions of ADO [ 2.0, 2.1, and 2.1 SP2 ] required careful usage of the GetChunk and AppendChunk methods of the Field Object to read and write BLOB data in fixed-size chunks from and to a BLOB column. An alternative to this method now exists with the advent of ADO 2.5. This article includes code samples that demonstrate how the Stream object can be used to program the following common tasks: Save the data stored in a SQL Server Image column to a file on the hard disk.Move the contents of a .gif file to an Image column in a SQL Server table.
Resolution
The following code samples are based on the data stored in the pub_info table in the SQL Server 7.0 pubs sample database. You need to modify the ADO connection string to point to your SQL Server installation. Example 1 : Saving the Data in a SQL Server Image Column to a File on the Hard Disk The code in this example opens a recordset on the pub_info table in the pubs database and saves the binary image data stored in the logo column of the first record to a file on the hard disk, as follows: Open a new Standard EXE Visual Basic project.On the Project menu, click to select References, and then set a reference to the Microsoft ActiveX Data Objects 2.5 Object Library.Place a CommandButton control on Form1.Make the following declarations in the form’s General declarations section:

Dim cn As ADODB.ConnectionDim rs As ADODB.RecordsetDim mstream As ADODB.Stream Cut and paste the following code into the Click event of the CommandButton that you added to the form:

Set cn = New ADODB.Connectioncn.Open “Provider=SQLOLEDB;data Source=<name of your SQL Server>;Initial Catalog=pubs;User Id=<Your Userid>;Password=<Your Password>”Set rs = New ADODB.Recordsetrs.Open “Select * from pub_info”, cn, adOpenKeyset, adLockOptimisticSet mstream = New ADODB.Streammstream.Type = adTypeBinarymstream.Openmstream.Write rs.Fields(“logo”).Valuemstream.SaveToFile “c:\publogo.gif”, adSaveCreateOverWriters.Closecn.Close Save and run the Visual Basic project.Click the CommandButton to save the binary data in the logo column of the first record to the file c:\publogo.gid. Look for this file in Windows Explorer and open it to view the saved image.
The code in this example declares an ADODB Stream object and sets its Type property to adTypeBinary to reflect that this object will be used to work with Binary data. Following this, the binary data stored in the logo column of the first record in the pub_info table is written out to the Stream object by calling its Write method. The Stream object now contains the binary data that is saved to the file by calling its SaveToFile method and passing in the path to the file. The adSaveCreateOverWrite constant passed in as the second parameter causes the SaveToFile method to overwrite the specified file if it already exists.Example 2 : Transfer the Image Stored in a .gif File to an Image Column in a SQL Server Table The code in this example saves an image stored in a .gif file to the logo column in the first record of the pub_info table by overwriting its current contents, as follows: Open a new Standard EXE Visual Basic project.On the Project menu, click to select References, and then set a reference to the Microsoft ActiveX Data Objects 2.5 Object Library.Place a CommandButton on Form1. Make the following declarations in the form’s General declarations section:

Dim cn As ADODB.ConnectionDim rs As ADODB.RecordsetDim mstream As ADODB.Stream Cut and paste the following code in the Click event of the CommandButton that you added to the form:

Set cn = New ADODB.Connectioncn.Open “Provider=SQLOLEDB;data Source=<name of your SQL Server>;Initial Catalog=pubs;User Id=<Your Userid>;Password=<Your Password>”Set rs = New ADODB.Recordsetrs.Open “Select * from pub_info”, cn, adOpenKeyset, adLockOptimisticSet mstream = New ADODB.Streammstream.Type = adTypeBinarymstream.Openmstream.LoadFromFile “<path to .gif file>”rs.Fields(“logo”).Value = mstream.Readrs.Updaters.Closecn.Close Save and run the Visual Basic project.Click on the CommandButton to run the code to stream the contents of the .gif file to the ADO Stream object, and save the data in the Stream to the logo column in the first record of the recordset.Verify that the image in the logo column has been modified by using the code in Example 1.

BUG: DBGrid Align Before Retrieve Fields Causes Hidden Data

Symptoms
Setting the Alignment property of a column in a DBGrid control at design-time, before selecting Retrieve Fields, results in the grid not showing anydata when the application is run.
Resolution
At design time, select Retrieve Fields from the custom control propertydialog box. Any changes made to the Alignment properties of columns in thegrid will no longer cause this problem. If the DatabaseName andRecordSource properties of the data control are not known until the programis run, using Retrieve Fields won’t be an option. In this case, just setthe Alignment property of the column(s) in question at run time, like this:

DBGrid1.Columns(0).Alignment = 2’select center alignment

INFO: VB 6.0 Readme Part 3: Control Issues

Symptoms
The information below includes the documentation and workarounds for VisualBasic 6.0. This information can also be found in the README.htm file thatships with Visual Basic 6.0 on the Visual Basic 6.0 CD-ROM. Please see theREFERENCES section of this article for a list of the Microsoft KnowledgeBase articles relating to the Visual Basic 6.0 readme.
Following is a list of all parts of the readme file:
Part 1.Important Issues – Please Read First!
Part 2.Data Access Issues and DataBinding Tips
Part 3.Control Issues
Part 4.Language Issues
Part 5.Samples Issues
Part 6.Wizard Issues
Part 7.Error Message Issues
Part 8.WebClass Designer Issues
Part 9.DHTML Page Designer Issues
Part 10. Extensibility issues
Part 11. Miscellaneous Issues
Part 12. Microsoft Transaction Server (MTS) Issues
Part 13. Dictionary Object
Part 14. Visual Component Manager
Part 15. Application Performance Manager
Resolution
Lightweight Controls Must Be BorderlessWhen creating a lightweight User control by setting the Windowless propertyto True, the BorderStyle property is invalidated. By definition alightweight control has no border.
If you first set the BorderStyle property to anything other than 0 – Noneand subsequently change the Windowless property to True, you will receivean error message “Windowless UserControls only support BorderStyle = None”.Run Time Error 711: Compiled .Exe Doesn’t Contain Information AboutUnreferenced Control Causing Controls.Add to Fail
Problem:
Create a new Standard EXE. Form1 is created by default.Add a user control to the project.Add the following code:

Dim WithEvents x as VBControlExtenderPrivate Sub Form_Load ()Set x = Controls.Add (“Project1.Usercontrol1″, “XX”)x.Visible = TrueEnd Sub On the File menu, click Make Project1.exe (Don’t run the project.)Run the EXE.
Result: You get an error (711) stating that Project1.Usercontrol1 is aninvalid ProgID since no info about it can be found in the exe.
Solution: Before compiling the project, under the Project menu, clickProject1 Properties. On the Make tab, clear the “Remove informationabout unused ActiveX controls” check box.
Remarks
By default, ActiveX controls that are referenced but not placed on any typeof form at design time are not available for Controls.Add at runtime or inan executable.
Hierarchical FlexGrid Control: ColWordWrapOption, ColWordWrapOptionBand,
ColWordWrapOptionFixed, ColWordWrapOptionHeader PropertiesThe following properties are part of the Hierarchical FlexGrid control’sfeature set but are not documented in the control’s help:
ColWordWrapOption, ColWordWrapOptionBand, ColWordWrapOptionFixed,ColWordWrapOptionHeader. Descriptions and syntaxes for these properties arefound below. Settings for all properties are the same, and can be found atthe bottom of the topic:
ColWordWrapOption Property
Returns or sets a value that specifies how text is wrapped in a specifiedcolumn.
Syntax

object.ColWordWrapOption (Index) = integer
The ColWordWrapOption property syntax has these parts:

PartDescription—————————————————-objectAn object expression that evaluates to a HierarchicalFlexGrid control.IndexLong. The number of the column to get or set word wrapon. The value must be in the range of -1 to Cols – 1.Setting this value to -1 selects all columns.integerA numeric expression that determines how words will wrap,as shown in settings.
ColWordWrapOptionBand Property
Returns or sets a value that specifies how text is wrapped in a specifiedband.
Syntax

object.ColWordWrapOptionBand (BandNumber, BandColIndex) = integer
The ColWordWrapOption property syntax has these parts:

PartDescription—————————————————-objectAn object expression that evaluates to a HierarchicalFlexGrid control.BandNumberLong. The number of the band to get or set word wrap on.The value must be in the range of 0 to Bands – 1.BandColIndexLong. The number of the column to get or set word wrapon. This optional parameter defaults to -1, indicatingall columns in the band. Valid values are -1 to Cols -1.integerA numeric expression that determines how words will wrap,as shown in settings.
ColWordWrapOptionBand Property
Returns or sets a value that specifies how text is wrapped in a specifiedband.
Syntax

object.ColWordWrapOptionBand (BandNumber, BandColIndex) = integer
The ColWordWrapOption property syntax has these parts:

PartDescription—————————————————————objectAn object expression that evaluates to aHierarchical FlexGrid control.BandNumberLong. The number of the band to get or setword wrap on. The value must be in the rangeof 0 to Bands – 1.BandColIndexLong. The number of the column to get or setword wrap on. This optional parameterdefaults to -1, indicating all columns in theband. Valid values are -1 to Cols -1.integerA numeric expression that determines howwords will wrap, as shown in settings.
ColWordWrapOptionFixed Property
Returns or sets a value that specifies how text is wrapped in a specifiedfixed column.
Syntax

object.ColWordWrapOptionFixed(index) = integer
The ColWordWrapOptionFixed property syntax has these parts:

PartDescription—————————————————-objectAn object expression that evaluates to a HierarchicalFlexGrid control.indexLong. The number of the column to get/set word wrap on.This optional parameter defaults to -1. Valid values are-1 to Cols -1.IntegerA numeric expression that determines how words will wrap,as shown in settings.
ColWordWrapOptionFixed Property
Returns or sets a value that specifies how text is wrapped in a specifiedfixed column.
Syntax

object.ColWordWrapOptionFixed(index) = integer The ColWordWrapOptionFixed property syntax has these parts:

PartDescription——————————————————————objectAn object expression that evaluates to aHierarchical FlexGrid control.indexLong. The number of the column to get/setword wrap on. This optional parameterdefaults to -1. Valid values are -1 to Cols-1.integerA numeric expression that determines howwords will wrap, as shown in settings.
ColWordWrapOptionHeader Property
Returns or sets a value that specifies how text is wrapped in columnheaders.
Syntax

object.ColWordWrapOptionHeader(BandNumber, BandColIndex) = integer The ColWordWrapOptionHeader property syntax has these parts:

PartDescription——————————————————————–objectAn object expression that evaluates to aHierarchical FlexGrid control.BandNumberLong. The number of the band to get/set wordwrap on. The value must be in the range of 0to Bands – 1.BandColIndexLong. The number of the column to get/setword wrap on. This optional parameterdefaults to -1 indicating all column headersin the band. Valid values are -1 to Cols -1.integerA numeric expression that determines howwords will wrap, as shown in settings.
Settings
The settings for integer are:

ConstantValueDescription————————————————————flexSingleLine0(Default) Displays text on asingle line only.flexWordBreak1The lines are automaticallybroken between words.flexWordEllipsis2Truncates text that does notfit in the rectangle and addsellipsis.flexWordBreakEllip3Breaks words between lines andsisadds ellipsis if text doesn’tfit in the rectangle.
Hierarchical FlexGrid Control: ColIsVisible and RowIsVisible Properties are
Read OnlyThe ColIsVisible and RowIsVisible properties are read-only properties andcannot be set programmatically. You can use the properties to test whethera column or row is visible, and hide the column or row, if appropriate, asshow below:

With MSHFlexGrid1If .ColIsVisible(1) Then .ColWidth(1) = 0If .RowIsVisible(1) Then .RowHeight(1) = 0End With
Hierarchical FlexGrid Control: Additional Settings for GridLines,GridLinesBand, GridLinesFixed, GridLinesHeader, GridLinesIndent, and
GridLinesUnpopulated PropertiesTwo additional settings are possible for the following properties:
ridLines, GridLinesBand, GridLinesFixed, GridLinesHeader,GridLinesIndent, GridLinesUnpopulated Properties. The possible settingsare show in the table below:

ConstantValueDescription—————————————————————flexGridDashes4Dashed Lines. Sets line stylebetween cells to dashed lines.flexGridDots5Dotted Lines. Sets line stylebetween cells to dotted lines.
Remarks:
These settings can be used in addition to flexGridNone, flexGridFlat,flexGridInset and flexGridRaised.
DataRepeater Control: Setting Public Properties Affect only the Current
ControlWhen creating a user control to be used in a DataRepeater control, be awarethat public properties of the control will be set only on the currentcontrol (the “live” control with the focus). For example, if you expose theFont property of a user control, at run time, resetting that property (asshown in the example code below) will only affect the current control inthe DataRepeater control. The font of repeated controls will not beaffected.

Private Sub Command1_Click()’ Only the current control’s Font will be affected.DataRepeater1.RepeatedControl.FontName = “Courier”End Sub
The corresponding code in the user control would resemble the following:

Public Property Get FontName() As StringFontName = txtProductName.Font.NameEnd PropertyPublic Property Let FontName(ByVal newFontName As String)txtProductName.Font.Name = newFontNameEnd Property
TabStrip Control: Separators show only when the Style property =
TabFlatButtonsSeparators will only appear on a TabStrip control when the Style propertyis set to TabFlatButtons. An example is shown below:

Private Sub Form_Load()With TabStrip1.Style = tabFlatButtons.Separators = TrueEnd WithEnd Sub
Data Report Designer: Error in Event Handling CodeIn the topic titled Data Report Events, there is an error in code thatshows how to handle asynchronous errors. For more information, searchonline, with Search titles only selected, for “Data Report Events” in theMSDN Library Visual Studio 6.0 documentation.
The code is found under the heading “Error Events’ for Asynchronous Events.”The code omits a “Select Case ErrObj.ErrorNumber” statement. The correctedcode is:

Private Sub DataReport_Error(ByVal JobType As _MSDataReportLib.AsyncTypeConstants, ByVal Cookie As Long, _ByVal ErrObj As MSDataReportLib.RptError, ShowError As Boolean)Select Case ErrObj.ErrorNumberCase rptErrPrinterInfo ‘ 8555MsgBox “A printing error has occurred. ” & _”You may not have a Printer installed.”ShowError = FalseExit SubCase Else ‘ handle other cases here.ShowError = TrueEnd SelectEnd Sub
RichTextBox Control: SelPrint Method Has New ArgumentThe SelPrint method now features a second, optional argument. The syntaxand part descriptions are shown below:
Syntax

object.SelPrint(lHDC As Long, [vStartDoc])
The SelPrint method syntax has these parts:

PartDescription—————————————————–objectAn object expression that evaluates to aRichTextbox control.lHDCLong. The device context of the device youplan to use to print the contents of thecontrol.vStartDocBoolean. Specifies the behavior of thecontrol regarding startdoc and enddoc printercontrol operations, as shown in settings.
SettingsThe settings for vStartDoc are:

ConstantValueDescription—————————————————————True-1(Default) The control retains itsoriginal behavior and sends startdocand enddoc commands to the printer.False0The control doesn’t send startdoc andenddoc commands, but sends onlystartpage and endpage commands to theprinter.
Remarks:
The argument was added to remedy situations when printers do not print withthe default behavior. When the SelPrint method is invoked, both VisualBasic and the RichTextBox control send startdoc and enddoc commands to theprinter resulting in a nested pair of startdoc/enddoc commands. Someprinters respond only to the first pair of commands and thereby becomedisabled when the RichTextbox control sends the second pair. In that case,setting the vStartDoc argument to False prevents the second pair ofcommands from being sent.
Visual Basic 5 Version of MSChart Control Available in Tools DirectoryFor pre-release users of Visual Basic only:
A Visual Basic 5.0x version of the MSChart control is now included withVisual Basic. If you need a Visual Basic 5 version of the Chart control,and you have installed the pre-release version of the MSChart control,please overwrite the pre-release version with the version contained in theTools directory of the Visual Basic CD.
Toolbar Control: Style Property Settings ChangedThe Style property settings for the Toolbar control have been changed. Thehelp topic for the property lists tbrTransparent and tbrRight as possiblesettings, however these are not implemented in the current version. Theactual possible settings and descriptions are shown below:

ConstantValueDescription————————————————————–tbrStandard0(Default) Standard toolbar.tbrFlat1Flat. The borders of a buttondynamically appear when the cursorhovers over the button.
Visual Basic Run-Time Error 720: Attempting to Add Anything Except a
Control to Controls Collection Causes Run-Time ErrorAttempting to add an object that is not a control to the Controlscollection causes run-time error 720. You can only add Visual Basicintrinsic controls or ActiveX controls to the collection.To reproduce:
Create a new Standard Exe. Form1 is created by default.Add the following code:

Private Sub Form_Load ()Controls.Add “Excel.Application”, “MyExcelApp”)End Sub Run the exe.Result: You get an error (720): Invalid class string.
Hierarchical FlexGrid Control: Correcting Errors Binding a Recordset to the
HFlexGridIf you receive the following error when trying to bind the HierarchicalFlexGrid to an ADO Recordset object, “DataSource settings may beincorrect”, try changing some of the behavioral properties associated withthe ADO Recordset Object or Command. For example, change the CursorLocationproperty to adUseNone or adUseClient.
Hierarchical FlexGrid Control: How to Change the Font of Individual BandsSince the same font object is used for the entire grid object, you mustcreate a new font object to change the fonts of individual bands, ratherthan changing the font directly.
For example, this way will not change the font for the individual band:

MSHFlexGrid1.FontBand(1).Name = “Arial”
Since you are directly modifying the font object, this will change thefonts in all of the bands to Arial.
To change an individual band, first create a new Font object, then assignthat Font object to the FontBand property:

Dim ft As New StdFontft.Name = “Arial”Set MSHFlexGrid1.FontBand(1) = ft
This will change just the band’s font to Arial.
Hierarchical FlexGrid Control: Avoiding the display of duplicate headersBy default, the Hierarchical FlexGrid control uses the first FixedRow inthe Hierarchical FlexGrid as a set of headers (which means it displays thenames of the fields bound to each column in this row). Since, by default,the HFlexGrid control displays one FixedRow, if you enable the display ofheaders on Band 0, it will appear as though the header is being duplicatedtwice. To avoid this, set the FixedRow property to 0, or clear out the textvalues in the first FixedRow using code.
ADO Data Control: FetchProgress and FetchComplete Events Not ImplementedAlthough the reference topic for the ADO Data Control includes links to theFetchProgress and FetchComplete events, the events are not implemented forthe control.
DataGrid: SizeMode and Size Properties Do Not Accept Value of 2
(dbgNumberOfColumns)The reference topics for the Split object’s SizeMode and Size propertiesrefer to a non-existent property value of 2 (dbgNumberOfColumns). Pleaseignore this value.
Controls: ImageList Control on Page DesignerWhen using the ImageList control on a DHTML Page designer, images cannot beadded at design time. If you try to use the following code in an uncompiled.dll project, you will get the run-time error: -2147418113 (8000ffff),”Method ‘Add’ of object images failed”.

Private Sub DHTMLPage_Load()ImageList1.ListImages.Add , , LoadPicture(“C:\Winnt\winnt.bmp”)End Sub
However, the code will work when the .dll project is compiled.
MSComm Control: EOFEnable Property Doesn’t Stop Data InputThe EOFEnable property determines if the OnComm event occurs when an EOFcharacter is detected. Contrary to the documentation for the property,however, input does not stop.
Treeview Control: Node Object’s Visible Property is Read-OnlyThe Visible property of the Treeview control’s Node object is a read-onlyproperty. If the node is not visible, you can use the EnsureVisible methodto make it visible, as shown in the example:

Private Sub Command1_Click()If Not TreeView1.Nodes(10).Visible ThenTreeView1.Nodes(10).EnsureVisibleEnd IfEnd Sub
SysInfo Control: Constants Not SupportedThe reference topics for the following events have lists of constants thatidentify devices and device data.:
DeviceArrival EventDeviceOtherEvent EventDeviceQueryRemove EventDeviceQueryRemoveFailed EventDeviceRemoveComplete EventDeviceRemovePending EventContrary to the documentation, however, these constants are not supportedby the events or the SysInfo control. The values associated with theconstants listed in the help topics are valid, but the constant names arenot.
User Control: Binary Persistence of PropertyBag Data Causes Page Designer
to FailThe PropertyBag saves data in binary format. Due to a known problem withbinary persistence and the DHTML page designer, however, such data causesthe page designer and Visual Basic to fail. See Page Designer: BinaryPersistence Issue for more information.

How To Use ADO with Excel Data from Visual Basic or VBA

Symptoms
This article discusses the use of ActiveX Data Objects (ADO) with Microsoft Excel spreadsheets as a data source. The article also highlights syntax issues and limitations specific to Excel. This article does not discuss OLAP or PivotTable technologies or other specialized uses of Excel data.
For additional information, click the article number below to view the article in the Microsoft Knowledge Base:
303814?(http://support.microsoft.com/kb/303814/EN-US/) How To Use ADOX with Excel Data from Visual Basic or VBA
Resolution
INTRODUCTION The rows and columns of a Microsoft Excel spreadsheet closely resemble the rows and columns of a database table. As long as users keep in mind that Microsoft Excel is not a relational database management system, and recognize the limitations that this fact imposes, it often makes sense to take advantage of Excel and its tools to store and analyze data.
Microsoft ActiveX Data Objects makes it possible to treat an Excel workbook as if it were a database. This article discusses how to accomplish this in the following sections: Connect to Excel with ADORetrieve and Edit Excel Data with ADORetrieve Data Source Structure (Metadata) from ExcelNOTE: The testing for this article was conducted with Microsoft Data Access Components (MDAC) 2.5 on Microsoft Windows 2000 with Visual Basic 6.0 Service Pack 3 and Excel 2000. This article may not acknowledge or discuss differences in behavior that users may observe with different versions of MDAC, Microsoft Windows, Visual Basic, or Excel.
Connect to Excel with ADO ADO can connect to an Excel data file with either one of two OLE DB Providers included in MDAC: Microsoft Jet OLE DB Provider -or-
Microsoft OLE DB Provider for ODBC DriversHow to Use the Microsoft Jet OLE DB Provider The Jet Provider requires only two pieces of information in order to connect to an Excel data source: the path, including the file name, and the Excel file version.
Jet Provider Using a Connection String

Dim cn as ADODB.ConnectionSet cn = New ADODB.ConnectionWith cn .Provider = “Microsoft.Jet.OLEDB.4.0″ .ConnectionString = “Data Source=C:\MyFolder\MyWorkbook.xls;” & _”Extended Properties=Excel 8.0;” .OpenEnd With Provider Version: It is necessary to use the Jet 4.0 Provider; the Jet 3.51 Provider does not support the Jet ISAM drivers. If you specify the Jet 3.51 Provider, at run time you receive the following error message:

Couldn’t find installable ISAM. Excel Version: Specify Excel 5.0 for an Excel 95 workbook (version 7.0 of Excel), and Excel 8.0 for an Excel 97, Excel 2000, or Excel 2002 (XP) workbook (versions 8.0, 9.0, and 10.0 of Excel).
Jet Provider Using the Data Link Properties Dialog Box
If you use the ADO Data Control or the Data Environment in your application, then the Data Link Properties dialog box is displayed to gather the necessary connection settings.
On the Provider tab, select the Jet 4.0 Provider; the Jet 3.51 Provider does not support the Jet ISAM drivers. If you specify the Jet 3.51 Provider, at run time you receive the following error message:

Couldn’t find installable ISAM. On the Connection tab, browse to your workbook file. Ignore the “User ID” and “Password” entries, because these do not apply to an Excel connection. (You cannot open a password-protected Excel file as a data source. There is more information on this topic later in this article.)On the All tab, select Extended Properties in the list, and then click Edit Value. Enter Excel 8.0; separating it from any other existing entries with a semicolon (;). If you omit this step, you receive an error message when you test your connection, because the Jet Provider expects a Microsoft Access database unless you specify otherwise.Return to the Connection tab and click Test Connection. Note that a message box appears informing you that the process has succeeded. Other Jet Provider Connection Settings
Column headings: By default, it is assumed that the first row of your Excel data source contains columns headings that can be used as field names. If this is not the case, you must turn this setting off, or your first row of data “disappears” to be used as field names. This is done by adding the optional HDR= setting to the Extended Properties of the connection string. The default, which does not need to be specified, is HDR=Yes. If you do not have column headings, you need to specify HDR=No; the provider names your fields F1, F2, etc. Because the Extended Properties string now contains multiple values, it must be enclosed in double quotes itself, plus an additional pair of double quotes to tell Visual Basic to treat the first set of quotes as literal values, as in the following example (where extra spaces have been added for visual clarity).

.ConnectionString = “Data Source=C:\MyFolder\MyWorkbook.xls;” & _”Extended Properties=” ” Excel 8.0; HDR=No;” ” ” Using Microsoft OLE DB Provider for ODBC Drivers The provider for ODBC drivers (which this article refers to as the “ODBC Provider” for the sake of brevity) also requires only two (2) pieces of information in order to connect to an Excel data source: the driver name, and the workbook path and filename.
IMPORTANT: An ODBC connection to Excel is read-only by default. Your ADO Recordset LockType property setting does not override this connection-level setting. You must set ReadOnly to False in your connection string or your DSN configuration if you want to edit your data. Otherwise, you receive the following error message:

Operation must use an updateable query. ODBC Provider Using a DSN-Less Connection String

Dim cn as ADODB.ConnectionSet cn = New ADODB.ConnectionWith cn .Provider = “MSDASQL” .ConnectionString = “Driver={Microsoft Excel Driver (*.xls)};” & _”DBQ=C:\MyFolder\MyWorkbook.xls; ReadOnly=False;” .OpenEnd With ODBC Provider Using a Connection String with a DSN

Dim cn as ADODB.ConnectionSet cn = New ADODB.ConnectionWith cn .Provider = “MSDASQL” .ConnectionString = “DSN=MyExcelDSN;” .OpenEnd With ODBC Provider Using the Data Link Properties Dialog Box
If you use the ADO Data Control or the Data Environment in your application, then the Data Link Properties dialog box is displayed to gather the necessary connection settings. On the Provider tab, select Microsoft OLE DB Provider for ODBC Drivers.On the Connection tab, select the existing DSN that you want to use, or choose Use connection string. This brings up the standard DSN configuration dialog box to gather the necessary connection settings. Remember to deselect the default read-only setting if desired, as mentioned previously.Return to the Connection tab, and click Test Connection. Note that a message box appears informing you that the process has succeeded.Other ODBC Provider Connection Settings
Column headings: By default, it is assumed that the first row of your Excel data source contains columns headings, which can be used as field names. If this is not the case, you must turn this setting off, or your first row of data “disappears” to be used as field names. This is done by adding the optional FirstRowHasNames= setting to the connection string. The default, which does not need to be specified, is FirstRowHasNames=1, where 1 = True. If you do not have column headings, you need to specify FirstRowHasNames=0, where 0 = False; the driver names your fields F1, F2, and so forth. This option is not available in the DSN configuration dialog box.
However, due to a bug in the ODBC driver, specifying the FirstRowHasNames setting currently has no effect. In other words, the Excel ODBC driver (MDAC 2.1 and later) always treats the first row in the specified data source as field names. For additional informationon the Column Heading bug, click the article number below to view the article in the Microsoft Knowledge Base:
288343?(http://support.microsoft.com/kb/288343/EN-US/) BUG: Excel ODBC Driver Disregards the FirstRowHasNames or Header SettingRows to Scan: Excel does not provide ADO with detailed schema information about the data it contains, as a relational database would. Therefore, the driver must scan through at least a few rows of the existing data in order to make an educated guess at the data type of each column. The default for “Rows to Scan” is eight (8) rows. You can specify an integer value from one (1) to sixteen (16) rows, or you can specify zero (0) to scan all existing rows. This is done by adding the optional MaxScanRows= setting to the connection string, or by changing the Rows to Scan setting in the DSN configuration dialog box.
However, due to a bug in the ODBC driver, specifying the Rows to Scan (MaxScanRows) setting currently has no effect. In other words, the Excel ODBC driver (MDAC 2.1 and later) always scans the first 8 rows in the specified data source in order to determine each column’s datatype.
For additional information about the Rows to Scan bug, including a simple workaround, click the article number below to view the article in the Microsoft Knowledge Base:
189897?(http://support.microsoft.com/kb/189897/EN-US/) XL97: Data Truncated to 255 Characters with Excel ODBC DriverOther Settings: If you construct your connection string by using the Data Link Properties dialog box, you may notice some other Extended Properties settings added to the connection string that are not absolutely necessary, such as:

… DefaultDir=C:\WorkbookPath;DriverId=790;FIL=excel 8.0;MaxBufferSize=2048;PageTimeout=5; “Collating Sequence” Error Message in the Visual Basic Editor
In the Visual Basic design environment with certain versions of MDAC, you may see the following error message the first time your program connects to an Excel data source at design time:

Selected collating sequence not supported by the operating system. This message appears only in the IDE and will not appear in the compiled version of the program. For additional information, click the article number below to view the article in the Microsoft Knowledge Base:
246167?(http://support.microsoft.com/kb/246167/EN-US/) PRB: Collating Sequence Error Opening ADODB Recordset the First Time Against an Excel XLSConsiderations That Apply to Both OLE DB ProvidersA Caution about Mixed Data Types
As stated previously, ADO must guess at the data type for each column in your Excel worksheet or range. (This is not affected by Excel cell formatting settings.) A serious problem can arise if you have numeric values mixed with text values in the same column. Both the Jet and the ODBC Provider return the data of the majority type, but return NULL (empty) values for the minority data type. If the two types are equally mixed in the column, the provider chooses numeric over text.
For example: In your eight (8) scanned rows, if the column contains five (5) numeric values and three (3) text values, the provider returns five (5) numbers and three (3) null values. In your eight (8) scanned rows, if the column contains three (3) numeric values and five (5) text values, the provider returns three (3) null values and five (5) text values.In your eight (8) scanned rows, if the column contains four (4) numeric values and four (4) text values, the provider returns four (4) numbers and four (4) null values. As a result, if your column contains mixed values, your only recourse is to store numeric values in that column as text, and to convert them back to numbers when needed in the client application by using the Visual Basic VAL function or an equivalent.
To work around this problem for read-only data, enable Import Mode by using the setting “IMEX=1″ in the Extended Properties section of the connection string. This enforces the ImportMixedTypes=Text registry setting. However, note that updates may give unexpected results in this mode. For additional information about this setting, click the article number below to view the article in the Microsoft Knowledge Base:
194124?(http://support.microsoft.com/kb/194124/EN-US/) PRB: Excel Values Returned as NULL Using DAO OpenRecordsetYou Cannot Open a Password-Protected Workbook
If the Excel workbook is protected by a password, you cannot open it for data access, even by supplying the correct password with your connection settings, unless the workbook file is already open in the Microsoft Excel application. If you try, you receive the following error message:

Could not decrypt file. For additional information, click the article number below to view the article in the Microsoft Knowledge Base:
211378?(http://support.microsoft.com/kb/211378/EN-US/) XL2000: “Could Not Decrypt File” Error with Password Protected File
Retrieve and Edit Excel Data with ADO This section discusses two aspects of working with your Excel data: How to select data -and-
How to change dataHow to Select Data There are several ways to select data. You can:
Select Excel data with code.Select Excel data with the ADO Data control.Select Excel data with Data Environment commands.Select Excel Data with Code Your Excel data may be contained in your workbook in one of the following:
An entire worksheet.A named range of cells on a worksheet.An unnamed range of cells on a worksheet.Specify a Worksheet
To specify a worksheet as your recordsource, use the worksheet name followed by a dollar sign and surrounded by square brackets. For example:

strQuery = “SELECT * FROM [Sheet1$]” You can also delimit the worksheet name with the slanted single quote character (`) found on the keyboard under the tilde (~). For example:

strQuery = “SELECT * FROM `Sheet1$`” Microsoft prefers the square brackets, which are the standing convention for problematic database object names.
If you omit both the dollar sign and the brackets, or just the dollar sign, you receive the following error message:

… the Jet database engine could not find the specified object If you use the dollar sign but omit the brackets, you will see the following error message:

Syntax error in FROM clause. If you try to use ordinary single quotes, you receive the following error message:

Syntax error in query. Incomplete query clause. Specify a Named Range
To specify a named range of cells as your recordsource, simply use the defined name. For example:

strQuery = “SELECT * FROM MyRange” Specify an Unnamed Range
To specify an unnamed range of cells as your recordsource, append standard Excel row/column notation to the end of the sheet name in the square brackets. For example:

strQuery = “SELECT * FROM [Sheet1$A1:B10]” A caution about specifying worksheets: The provider assumes that your table of data begins with the upper-most, left-most, non-blank cell on the specified worksheet. In other words, your table of data can begin in Row 3, Column C without a problem. However, you cannot, for example, type a worksheeet title above and to the left of the data in cell A1.
A caution about specifying ranges: When you specify a worksheet as your recordsource, the provider adds new records below existing records in the worksheet as space allows. When you specify a range (named or unnamed), Jet also adds new records below the existing records in the range as space allows. However, if you requery on the original range, the resulting recordset does not include the newly added records outside the range.
With MDAC versions prior to 2.5, when you specify a named range, you cannot add new records beyond the defined limits of the range, or you receive the following error message:

Cannot expand named range. Select Excel Data with the ADO Data Control After you specify the connection settings for your Excel data source on the General tab of the ADODC Properties dialog box, click on the Recordsource tab. If you choose a CommandType of adCmdText, you can enter a SELECT query in the Command Text dialog box with the syntax described previously. If you choose a CommandType of adCmdTable, and you are using the Jet Provider, the drop-down list displays both the named ranges and worksheet names that are available in the selected workbook, with named ranges listed first.
This dialog box properly appends the dollar sign to worksheet names, but does not add the necessary square brackets. As a result, if you simply select a worksheet name and click OK, you receive the following error message later:

Syntax error in FROM clause. You must manually add the square brackets around the worksheet name. (This combo box does allow editing.) If you are using the ODBC Provider, you see only named ranges listed in this drop-down list. However, you can manually enter a worksheet name with the appropriate delimiters. Select Excel Data with Data Environment Commands After setting up the Data Environment Connection for your Excel data source, create a new Command object. If you choose a Source of Data of SQL Statement, you can enter a query in the textbox using the syntax described previously. If you choose a Source of Data of Database Object, select Table in the first drop-down list, and you are using the Jet Provider, the drop-down list displays both named ranges and worksheet names available in the selected workbook, with named ranges listed first. (If you choose a worksheet name in this location, you do not need to add square brackets around the worksheet name manually as you do for the ADO Data Control.) If you are using the ODBC Provider, you see only named ranges listed in this drop-down list. However, you can manually enter a worksheet name. How to Change Excel Data: Edit, Add, and DeleteEdit
You can edit Excel data with the normal ADO methods. Recordset fields which correspond to cells in the Excel worksheet containing Excel formulas (beginning with “=”) are read-only and cannot be edited. Remember that an ODBC connection to Excel is read-only by default, unless you specify otherwise in your connection settings. See earlier under “Using the Microsoft OLE DB Provider for ODBC Drivers.”
Add
You can add records to your Excel recordsource as space allows. However, if you add new records outside the range that you originally specified, these records are not visible if you requery on the original range specification. See earlier under “A caution about specifying ranges.”
In certain circumstances, when you use the AddNew and Update methods of the ADO Recordset object to insert new rows of data into an Excel table, ADO may insert the data values into the wrong columns in Excel. For additional information, click the article number below to view the article in the Microsoft Knowledge Base:
314763?(http://support.microsoft.com/kb/314763/EN-US/) FIX: ADO Inserts Data into Wrong Columns in ExcelDelete
You are more restricted in deleting Excel data than data from a relational data source. In a relational database, “row” has no meaning or existence apart from “record”; in an Excel worksheet, this is not true. You can delete values in fields (cells). However, you cannot: Delete an entire record at once or you receive the following error message:

Deleting data in a linked table is not supported by this ISAM. You can only delete a record by blanking out the contents of each individual field.Delete the value in a cell containing an Excel formula or you receive the following error message:

Operation is not allowed in this context. You cannot delete the empty spreadsheet row(s) in which the deleted data was located, and your recordset will continue to display empty records corresponding to these empty rows.A caution about editing Excel data with ADO: When you insert text data into Excel with ADO, the text value is preceded with a single quote. This may cause problems later in working with the new data.
Retrieve Data Source Structure (Metadata) from Excel You can retrieve data about the structure of your Excel data source (tables and fields) with ADO. Results differ slightly between the two OLE DB Providers, although both return at least the same small number of useful fields of information. This metadata can be retrieved with the OpenSchema method of the ADO Connection object, which returns an ADO Recordset object. You can also use the more powerful Microsoft ActiveX Data Objects Extensions for Data Definition Language and Security (ADOX) library for this purpose. In the case of an Excel data source however, where a “table” is either a worksheet or a named range, and a “field” is one of a limited number of generic datatypes, this additional power is not useful. Query Table Information Of the various objects available in a relational database (tables, views, stored procedures, and so forth), an Excel data source exposes only table equivalents, consisting of the worksheets and the named ranges defined in the specified workbook. Named ranges are treated as “Tables” and worksheets are treated as “System Tables,” and there is not much useful table information you can retrieve beyond this “table_type” property. You request a list of the available tables in the workbook with the following code:

Set rs = cn.OpenSchema(adSchemaTables) The Jet Provider returns a recordset with nine (9) fields, of which it populates only four (4):
table_nametable_type (“Table” or “System Table”)date_created date_modified The two date fields for a given table always show the same value, which appears to be the “date last modified.” In other words, “date_created” is not reliable.
The ODBC Provider also returns a recordset with nine (9) fields, of which it populates only three (3):
table_catalog, the folder in which the workbook is located.table_name.table_type, as noted earlier. According to the ADO documentation, it is possible to retrieve a list of worksheets only, for example, by specifying the following additional criteria to the OpenSchema method:

Set rs = cn.OpenSchema(adSchemaTables, Array(Empty, Empty, Empty, “System Table”)) Unfortunately, this does not work against an Excel data source with MDAC versions later than 2.0, using either provider. Query Field Information Every field (column) in an Excel data source is one of the following datatypes:
numeric (ADO datatype 5, adDouble)currency (ADO datatype 6, adCurrency)logical or boolean (ADO datatype 11, adBoolean)date (ADO datatype 7, adDate, using Jet; 135, adDBTimestamp, using ODBC)text (an ADO ad…Char type, such as 202, adVarChar, 200, adVarWChar or similar) The numeric_precision for a numeric column is always returned as 15 (which is the maximum precision in Excel); the character_maximum_length of a text column is always returned as 255 (which is the maximum display width, but not the maximum length, of text in an Excel column). There is not much useful field information that you can obtain beyond the data_type property. You request a list of the available fields in a table with the following code:

Set rs = cn.OpenSchema(adSchemaTables, Array(Empty, Empty, “TableName”, Empty)) The Jet Provider returns a recordset that contains 28 fields, of which it populates eight (8) for numeric fields and nine (9) for text fields. The useful fields are likely to be these:
table_namecolumn_nameordinal_positiondata_type The ODBC Provider returns a recordset containing 29 fields, of which it populates ten (10) for numeric fields and 11 for text fields. The useful fields are the same as earlier. Enumerate Tables and Fields and Their Properties Visual Basic code (such as the following sample) can be used to enumerate the tables and columns in an Excel data source and the available fields of information about each. This sample outputs its results to a Listbox, List1, on the same form.

Dim cn As ADODB.ConnectionDim rsT As ADODB.RecordsetDim intTblCnt As Integer, intTblFlds As IntegerDim strTbl As StringDim rsC As ADODB.RecordsetDim intColCnt As Integer, intColFlds As IntegerDim strCol As StringDim t As Integer, c As Integer, f As IntegerSet cn = New ADODB.ConnectionWith cn .Provider = “Microsoft.Jet.OLEDB.4.0″ .ConnectionString = “Data Source=” & App.Path & _”\ExcelSrc.xls;Extended Properties=Excel 8.0;” ‘.Provider = “MSDASQL” ‘.ConnectionString = “Driver={Microsoft Excel Driver (*.xls)};” & _”DBQ=” & App.Path & “\ExcelSrc.xls; ” .CursorLocation = adUseClient .OpenEnd WithSet rsT = cn.OpenSchema(adSchemaTables)intTblCnt = rsT.RecordCountintTblFlds = rsT.Fields.CountList1.AddItem “Tables: ” & intTblCntList1.AddItem “——————–”For t = 1 To intTblCnt strTbl = rsT.Fields(“TABLE_NAME”).Value List1.AddItem vbTab & “Table #” & t & “: ” & strTbl List1.AddItem vbTab & “——————–” For f = 0 To intTblFlds – 1 List1.AddItem vbTab & rsT.Fields(f).Name & _vbTab & rsT.Fields(f).Value Next List1.AddItem “——————–” Set rsC = cn.OpenSchema(adSchemaColumns, Array(Empty, Empty, strTbl, Empty)) intColCnt = rsC.RecordCount intColFlds = rsC.Fields.Count For c = 1 To intColCnt strCol = rsC.Fields(“COLUMN_NAME”).Value List1.AddItem vbTab & vbTab & “Column #” & c & “: ” & strCol List1.AddItem vbTab & vbTab & “——————–” For f = 0 To intColFlds – 1 List1.AddItem vbTab & vbTab & rsC.Fields(f).Name & _vbTab & rsC.Fields(f).Value Next List1.AddItem vbTab & vbTab & “——————–” rsC.MoveNext Next rsC.Close List1.AddItem “——————–” rsT.MoveNextNextrsT.Closecn.Close Use the Data View Window If you create a data link to an Excel data source in the Visual Basic Data View window, the Data View window displays the same information that you can retrieve programmatically as described earlier. In particular, note that the Jet Provider lists both worksheets and named ranges under “Tables,” where the ODBC Provider shows only named ranges. If you are using the ODBC Provider and have not defined any named ranges, the “Tables” list will be empty. Excel Limitations The use of Excel as a data source is bound by the internal limitations of Excel workbooks and worksheets. These include, but are not limited to:
Worksheet size: 65,536 rows by 256 columnsCell contents (text): 32,767 charactersSheets in a workbook: limited by available memoryNames in a workbook: limited by available memory

How To Access and Modify SQL Server BLOB Data by Using the ADO Stream Object

Symptoms
The Stream object introduced in ActiveX Data Objects (ADO) 2.5 can be used to greatly simplify the code that needs to be written to access and modify Binary Large Object (BLOB) data in a SQL Server Database. The previous versions of ADO [ 2.0, 2.1, and 2.1 SP2 ] required careful usage of the GetChunk and AppendChunk methods of the Field Object to read and write BLOB data in fixed-size chunks from and to a BLOB column. An alternative to this method now exists with the advent of ADO 2.5. This article includes code samples that demonstrate how the Stream object can be used to program the following common tasks: Save the data stored in a SQL Server Image column to a file on the hard disk.Move the contents of a .gif file to an Image column in a SQL Server table.
Resolution
The following code samples are based on the data stored in the pub_info table in the SQL Server 7.0 pubs sample database. You need to modify the ADO connection string to point to your SQL Server installation. Example 1 : Saving the Data in a SQL Server Image Column to a File on the Hard Disk The code in this example opens a recordset on the pub_info table in the pubs database and saves the binary image data stored in the logo column of the first record to a file on the hard disk, as follows: Open a new Standard EXE Visual Basic project.On the Project menu, click to select References, and then set a reference to the Microsoft ActiveX Data Objects 2.5 Object Library.Place a CommandButton control on Form1.Make the following declarations in the form’s General declarations section:

Dim cn As ADODB.ConnectionDim rs As ADODB.RecordsetDim mstream As ADODB.Stream Cut and paste the following code into the Click event of the CommandButton that you added to the form:

Set cn = New ADODB.Connectioncn.Open “Provider=SQLOLEDB;data Source=<name of your SQL Server>;Initial Catalog=pubs;User Id=<Your Userid>;Password=<Your Password>”Set rs = New ADODB.Recordsetrs.Open “Select * from pub_info”, cn, adOpenKeyset, adLockOptimisticSet mstream = New ADODB.Streammstream.Type = adTypeBinarymstream.Openmstream.Write rs.Fields(“logo”).Valuemstream.SaveToFile “c:\publogo.gif”, adSaveCreateOverWriters.Closecn.Close Save and run the Visual Basic project.Click the CommandButton to save the binary data in the logo column of the first record to the file c:\publogo.gid. Look for this file in Windows Explorer and open it to view the saved image.
The code in this example declares an ADODB Stream object and sets its Type property to adTypeBinary to reflect that this object will be used to work with Binary data. Following this, the binary data stored in the logo column of the first record in the pub_info table is written out to the Stream object by calling its Write method. The Stream object now contains the binary data that is saved to the file by calling its SaveToFile method and passing in the path to the file. The adSaveCreateOverWrite constant passed in as the second parameter causes the SaveToFile method to overwrite the specified file if it already exists.Example 2 : Transfer the Image Stored in a .gif File to an Image Column in a SQL Server Table The code in this example saves an image stored in a .gif file to the logo column in the first record of the pub_info table by overwriting its current contents, as follows: Open a new Standard EXE Visual Basic project.On the Project menu, click to select References, and then set a reference to the Microsoft ActiveX Data Objects 2.5 Object Library.Place a CommandButton on Form1. Make the following declarations in the form’s General declarations section:

Dim cn As ADODB.ConnectionDim rs As ADODB.RecordsetDim mstream As ADODB.Stream Cut and paste the following code in the Click event of the CommandButton that you added to the form:

Set cn = New ADODB.Connectioncn.Open “Provider=SQLOLEDB;data Source=<name of your SQL Server>;Initial Catalog=pubs;User Id=<Your Userid>;Password=<Your Password>”Set rs = New ADODB.Recordsetrs.Open “Select * from pub_info”, cn, adOpenKeyset, adLockOptimisticSet mstream = New ADODB.Streammstream.Type = adTypeBinarymstream.Openmstream.LoadFromFile “<path to .gif file>”rs.Fields(“logo”).Value = mstream.Readrs.Updaters.Closecn.Close Save and run the Visual Basic project.Click on the CommandButton to run the code to stream the contents of the .gif file to the ADO Stream object, and save the data in the Stream to the logo column in the first record of the recordset.Verify that the image in the logo column has been modified by using the code in Example 1.

FIX: Visual Basic Crashes When Appending a New Column to an Existing Table

Symptoms
Microsoft Visual Basic crashes when appending a newly-created column to a table by setting the ParentCatalog property of a column to an active catalog and adding it to an existing table.
Resolution
Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.
This problem has been corrected in MDAC 2.5 and later.