Local loStream As ADODB.Stream, lcDataSource, lcSQL, lcColumnHeaders lcDataSource = _samples+'data' TEXT to m.lcSQL textmerge noshow Select Country, Region, City, Cust_Id, Company, Contact From Customer ENDTEXT *** We want to use custom headers on columns, rather than fieldnames *** Our list should match the order of columns in our select *** We could simply omit passing headers, then field names would be used as column names lcColumnHeaders = "Country, Region, City, CustomerID, Company Name, Contact Name" loStream = GetDataAsAdoStream("Provider=VFPOLEDB;Data Source="+m.lcDataSource, m.lcSQL) *** Main Excel automation part now oExcel = Createobject("Excel.Application") With oExcel .DisplayAlerts = .F. .Workbooks.Add .Visible = .T. With .ActiveWorkBook.ActiveSheet .Name = 'Customer List' * Send the data - safe copy to replacement VFP2ExcelVariation(m.loStream, .Range("A1"), m.lcColumnHeaders) .Columns.AutoFit() Endwith Endwith Function VFP2ExcelVariation(toStream, toRange, tcHeaders) Local loRS As ADODB.Recordset,ix loRS = Createobject('Adodb.Recordset') m.loRS.Open( m.toStream ) * Use first row for headers Local Array aHeader[1] m.toRange.Offset(1,0).CopyFromRecordSet( m.loRS ) && Copy data starting from headerrow + 1 For ix=1 To Iif( !Empty(m.tcHeaders), ; ALINES(aHeader, m.tcHeaders,1,','), ; m.loRS.Fields.Count ) m.toRange.Offset(0,m.ix-1).Value = ; Iif( !Empty(m.tcHeaders), ; Alltrim(aHeader[m.ix]), ; Proper(m.loRS.Fields(m.ix-1).Name) ) m.toRange.Offset(0,m.ix-1).Font.Bold = .T. Endfor m.loRS.Close() Endfunc Procedure GetDataAsAdoStream(tcConnection, tcSQL) Local loStream As 'AdoDb.Stream', ; loConn As 'AdoDb.Connection', ; loRS As 'AdoDb.Recordset' loStream = Createobject('AdoDb.Stream') loConn = Createobject("Adodb.connection") loConn.ConnectionString = m.tcConnection m.loConn.Open() loRS = loConn.Execute(m.tcSQL) m.loRS.Save( loStream ) m.loRS.Close m.loConn.Close Return m.loStream Endproc