Sunday, December 11, 2016

Fee Letter Save Data in Child Form

Option Compare Database
Option Explicit

Private m_ActionMode As Integer Private m_lngStoredFileInfoid As Integer Private Sub cmdCancel_Click()
DoCmd.Close acForm, Me.Name
End Sub

Private Sub cmdOK_Click()
Dim db As DAO.Database
Dim strSQL
If ValidateForm() Then
    strSQL = "INSERT INTO StoredFile (StoredFileInfoID,FileName,Description,AddedBy) VALUES " & _
        "(" & _
        m_lngStoredFileInfoid & "," & _
        "'" & Me.txtFileName.Value & "'," & _
        "'" & Me.txtDescription.Value & "'," & _
        "'" & "UT2998" & "'" & ")"
    Set db = CurrentDb()
    db.Execute strSQL, dbFailOnError
 
Else
    MsgBox "Error in saving record." & vbCrLf & _
        "Please try again", vbInformation, "Confirm Action"
    Exit Sub
End If

DoCmd.Close acForm, Me.Name
End Sub

Private Sub Form_Load()
If Not IsNull(Me.OpenArgs) Then
    m_lngStoredFileInfoid = CLng(Me.OpenArgs)
Else
    Me.txtFileName.Enabled = False
End If

End Sub

Private Function ValidateForm(Optional ByVal bDisplayMessage As Boolean = True) As Boolean
Dim strMessage As String
Dim strBlankFields As String

Dim bReturn As Boolean
If IsNull(Me.txtDescription) Then
    strBlankFields = strBlankFields & "Description;"
End If

If IsNull(Me.txtFileName) Then
    strBlankFields = strBlankFields & "FileName;"
End If

If Len(strBlankFields) > 0 Then
    If bDisplayMessage Then
        MsgBox "Some required fields are blank." & vbCrLf & vbCrLf & _
            "Please fill out " & strBlankFields, vbInformation, "Confirm Action"
    End If
End If
bReturn = Len(strBlankFields) = 0
exitproc:
    ValidateForm = bReturn
End Function


=========================================================

Option Compare Database
Option Explicit

Private Sub cmdAdd_Click()
Dim strFormName As String
Dim lngPKID As Long

lngPKID = 1

strFormName = "FileDetail"
DoCmd.OpenForm strFormName, windowmode:=acDialog, OpenArgs:=lngPKID
Me.cboFeeLetterPDF.Requery
End Sub

Private Sub cmdView_Click()
Dim strFileName
Dim strMessage
Dim strPath As String
Dim lngPKID As Long

If IsNull(Me.cboFeeLetterPDF) Then
    MsgBox "Please select a file name to open"
    Exit Sub
End If
strFileName = Me.cboFeeLetterPDF.Column(1)
'If vbYes = MsgBox("Open file " & strFileName & " in Adobe", vbInformation + vbYesNo, "Confirm action") Then
    strPath = "C:\Temp"
    strFileName = strPath & "\" & strFileName
    Application.FollowHyperlink strFileName
'End If
End Sub

Private Sub Form_Load()
With Me
    .cmdDelete.Enabled = False
End With
End Sub

Sunday, November 27, 2016

How To capture ADO provider errors that the VBA Error object does show

Err_Execute:

   ' Notify user of any errors that result from
   ' executing the query
   If rstTemp.ActiveConnection.Errors.Count > 0 Then
      For Each Err In rstTemp.ActiveConnection.Errors
         MsgBox "Error number: " & Err.Number & vbCr & _
            Err.Description
      Next Err
   End If

   Resume Next




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Err_Execute:

   ' Notify user of any errors that result from
   ' executing the query
   If rstTemp.ActiveConnection.Errors.Count > 0 Then
      For Each Err In rstTemp.ActiveConnection.Errors
         MsgBox "Error number: " & Err.Number & vbCr & _
            Err.Description
      Next Err
   End If

   Resume Next

How to release object variables in ADO

 ' clean up
    If Not rstTitles Is Nothing Then
        If rstTitles.State = adStateOpen Then rstTitles.Close
    End If
    Set rstTitles = Nothing

    If Not Cnxn Is Nothing Then
        If Cnxn.State = adStateOpen Then Cnxn.Close
    End If
    Set Cnxn = Nothin

How to make an ADO Connection to SQL Server

Microsoft continuos updates the drivers for ADODB so depending on which version of SQL use: '

Dim Cnxn As ADODB.Connection
Open connection strCnxn = "Provider='sqloledb';Data Source='MySqlServer';" & _ "Initial Catalog='Pubs';Integrated Security='SSPI';" 
 Set Cnxn = New ADODB.Connection 
 Cnxn.Open strCnxn

Saturday, November 26, 2016

Enterprise Application setup part 1/3

App Setup Section: Overview For a professional enterprise wide application, several critical tasks need to be accomplished at application's setup. They can loosely be defined as: setup: Define system wide settings like default output folder, printer settings and other configurable setting that will be used throughout the application's life cycle display a splash screen: Display application setting like application name, major/minor version info while giving the user something pretty to look at prompt to login a user: verify that the user is actually allowed to use the application and force him/her to enter a user id and password and be authenticated by the database - either MS Access or preferable a true enterprise wide database like MS SQL Server In reality, this is an expansive topic that covers a lot of ground so there will be separate blog posts to cover how to make a splash screen and validate a user's credentials via a login screen Section: Setup Global/PUblic variables are defined in modGlobals. Generally, these should be public constants and public variabls but MS Access has a known bug that values in public variables are lost if the application goes in BREAK mode so the TempVars variables will be used instead. Variable Name Data Type Note gbApp_SetupOccurred Boolean Flag indicates if setup occurred. Used to coordinate if certain menu options are enabled/disabled gstrUserName String The login of the user. Usually a call in the Windows API TempVars(“UserAccessLevel”) Variant User Access level which is configured per application. Basic values can be Read or Read/Write or finer level of permissions Dependencies modGlobal Public Const ERR_MSG_REQUIRED_FIELD_MISSING As String = _ "Required field. Can't be blank or missing." Public Const ERR_MSG_INVALID_START_DATE As String _ = "Invalid Start Date or must be less than ending Date" Public Const ERR_MSG_BLANK_NAME As String = "Required value -must supply a name" Public Const ERR_MSG_NO_RIGHTS_TO_FUNCTION As String = "Not enough priveleges to run this command. " & _ "Please contact system administrator for more assistance" Public Const ERR_MSG_EXISTS_IN_QUEUE As String = "No need to try again because it is all ready in the queue of pending changes." '===================================================== Public Const APP_NAME As String = "ProductivityTool" 'Public APP_PATH As String 'Public APP_INPUT_PATH As String 'Public APP_OUTPUT_PATH As String 'Public Const APP_PATH As String = CurrentProject.Path 'Public Const APP_INPUT_PATH As String = AddBS(APP_PATH) & "Input" 'Public Const APP_OUTPUT_PATH As String = AddBS(APP_PATH) & "Output" Public Const APP_LOCAL_APP_PATH As String = "C:\My Documents\My App" Public Const APP_LOCAL_INPUT_PATH As String = APP_LOCAL_APP_PATH & "\" & "Input" Public Const APP_LOCAL_OUTPUT_PATH As String = APP_LOCAL_APP_PATH & "\" & "Output" Public Const COMPANY_NAME As String = "Deutsche Bank AG" 'Public gbDEBUG_MODE As Boolean Public gbApp_SetupOccurred As Boolean Public Const MASK_DATE As String = "mm/dd/yyyy" Public Const MASK_MONEY As String = "$#,##0.00;($#,##0.00)" Public Const MASK_HOLDINGS As String = "#,##0;(#,##0)" Public lngMyEmpID As Long Public gstrUserName As String 'Public gUserAccessLevel As UserRole How Public Sub StartUp() 'will rename to init globals 'will read from INI file to get path for executable Dim objCatalog As Object 'ADOX.Catalog Dim objTable As Object 'ADOX.Table Dim strAppPath As String On Error Resume Next Set objCatalog = CreateObject("ADOX.Catalog") 'Set objCatalog = New ADOX.Catalog Set objCatalog.ActiveConnection = CurrentProject.Connection 'Set objTable = New ADOX.Table Set objTable = CreateObject("ADOX.Table") objTable.Name = "DailyWork" Set objTable.ParentCatalog = objCatalog Set objTable = objCatalog.Tables("DailyWork") strAppPath = JustPathfromFileName(objTable.Properties("Jet OLEDB:Link DataSource")) Application.TempVars.Add "AppPath", strAppPath gbApp_SetupOccurred = True 'getAppPath() 'Call SetErrorFilePath(CurrentProject.Path) 'log errors here Call SetErrorFilePath(strAppPath) 'log errors here gbDEBUG_MODE = Len(Dir$(AddBS(CurrentProject.Path) & "debug.ini")) > 0 'gsREG_APP= 'APP_NAME = "CPLI App" End Sub

Thursday, November 24, 2016

Head to Head ADO vs DAO CRUD Operations



--Setup

Create table dbo.SampleInvoice
(
SampleInvoiceID int identity(1,1) not null,
AsofDate datetime null,
[Amount] float not null,
userid nvarchar(255) null,
Source nvarchar(5)
)

create proc uspSampleInvoiceAdd
(
@asofdate datetime,
@amount float=null,
@userid nvarchar(255)=null,
@Source nvarchar(5)='ADO'
)
as

set nocount on
insert into SampleInvoice
(
AsofDate,
Amount,
UserId,
Source
)
values (@asofdate,@Amount,@userid,@Source)

-- test
exec uspSampleInvoiceAdd @asofdate='20160101',@amount=1.01,@userid='ut2998',@source='SQL'

select * from dbo.sampleinvoice
 ' Notify user of any errors that result from
    ' executing the query
    If rstTitles.ActiveConnection.Errors.Count >= 0 Then
       For Each Err In rstTitles.ActiveConnection.Errors
          MsgBox "Error number: " & Err.Number & vbCr & _
             Err.Description
       Next Err
    End If
Clean up resources

 ' clean up
    If Not rstTitles Is Nothing Then
        If rstTitles.State = adStateOpen Then rstTitles.Close
    End If
    Set rstTitles = Nothing

    If Not Cnxn Is Nothing Then
        If Cnxn.State = adStateOpen Then Cnxn.Close
    End If
    Set Cnxn = Nothing

Monday, November 21, 2016

Top 10 Using an ADO recordset with a form

How to delete a row
Set rs = Me.gridPhoneNumberDetail2.Form.Recordset
        If vbYes = MsgBox("Delete " & vbCrLf & strMsg, vbYesNo + vbInformation, "Confirm Action") Then
            rs.Delete
            If Not rs.EOF() Then rs.MoveNext
        End If
 

Set rs = Nothing

How to add a record?

Dim strSQL As String

If vbYes = MsgBox("Add a new requirement", vbInformation + vbYesNo, "Confirm action") Then
    strSQL = "INSERT INTO WJDPhoneNumber(PersonInfoId) VALUES(" & _
        Forms!wjdfrmpersoninfo!PersonInfoID & ")"
        CurrentDb.Execute strSQL
    Me.Refresh
End If

How to check if there are no rows in a form's DAO recordset

Dim rs As DAO.Recordset
Set rs = Me.gridPhoneNumberDetail2.Form.Recordset
Me.cmdDeleteRequirement.Enabled = rs.RecordCount > 0

How to set the width of a column in a subform
In the Form's Open event put the following code:

Private Sub Form_Open(Cancel As Integer)
Me.gridPhoneNumberDetail2.Form.Controls("PhoneNumber").ColumnWidth = 2160
End Sub

How to make a column invisible
in the form's Open event add:

Me.gridPhoneNumberDetail2.Form.Controls("Type").ColumnHidden = True



Procedure header

'===========================================================
'Author         :William DeCastro
'Created        :08/31/2016
'Last modified  :08/31/2016 1.0 Beta
'Objective      :will Save/update talent plus rate detail to the
'               appropriate tables
'
'Arguments      :
'Sample Call    :
'Called By      :
'===========================================================

Processing files generically in VBA


Option Compare Database
Option Explicit

Private Sub cboAsofDate_AfterUpdate()
Dim ReportDate As Date

ReportDate = CDate(Me.cboAsofDate.Value)
MsgBox "Filter for report date as of " & ReportDate
End Sub

Private Sub cboTransactionID_AfterUpdate()
Dim lngPKID As Long
lngPKID = Me.cboTransactionID.Value
'MsgBox "get exposures for id " & lngPKID

Dim qdf As QueryDef
Dim db As DAO.Database
Dim strSQL As String

Set db = CurrentDb()
Set qdf = db.QueryDefs("qryODBCExposuregetAllPerTransactionId")
With qdf
    Debug.Print "Connect property=" & .Connect
    strSQL = "EXEC uspExposuregetAllPerTransactionID " & Me.cboTransactionID.Value
    .SQL = strSQL
    Debug.Print "Sql=" & strSQL
    .ReturnsRecords = True
End With

With Me.lstExposure

    .RowSource = ""
    .ColumnCount = 3
    .RowSourceType = "Table/query"
    .ColumnWidths = "1 in;2 in;2 in"
    .RowSource = "qryODBCExposuregetAllPerTransactionId"
   
    '.Requery
End With
End Sub

Private Sub cmdRefresh_Click()
Dim strMessage As String
Dim iNumberOfColumns As Integer
Dim qdf As QueryDef
Dim db As DAO.Database

If Me.cboDataAccessType = -1 Then
    MsgBox "Must select a data access type", vbInformation, "Confirm Action"
    Exit Sub
End If
    
If Me.cboDataAccessType.Value = "DAO" Then
    'MsgBox "Will refresh with DAO"
    Set db = CurrentDb()
    Set qdf = db.QueryDefs("qryStagingTableProgramFeeMainGetAll")
    With Me.lstData
        .RowSource = ""
        .RowSourceType = "Table/Query"
        .ColumnHeads = True
        .ColumnCount = qdf.Fields.Count
        .ColumnWidths = "2 in;2 in;2 in;2 in;2 in;2 ;2 in"
        .RowSource = qdf.Name
    End With
        
Else
    MsgBox "Will refresh with ADO"
End If



End Sub


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++



Option Compare Database
Option Explicit

Public Function OpeningForm(CloseForm As String, OpenForm As String)
DoCmd.Close acForm, CloseForm

DoCmd.OpenForm OpenForm, acNormal

End Function

Public Sub TestProcessFiles()
Call ProcessFiles(1)
End Sub
Public Function ProcessFiles(ByVal id As Integer)
Dim aFiles() As String
Dim objExcel As Excel.Application

Dim i As Integer
Dim bReturn As Boolean

Select Case id

    Case 1
        ReDim aFiles(0 To 0)
        'aFiles(1) = "Chase"
        aFiles(0) = "AMEX"
        
    Case Else
End Select


Set objExcel = New Excel.Application
For i = LBound(aFiles) To UBound(aFiles)
    
    bReturn = ProcessFile(objExcel, id, aFiles(i))
Next
Set objExcel = Nothing
        
ExitProc:
    ProcessFiles = bReturn
    Exit Function
    
ErrorHandler:
    
End Function

Public Function ProcessFile(objExcel As Excel.Application, id As Integer, ParamArray prm()) As Boolean
Dim bReturn As Boolean
Dim strInputPath As String
Dim strFileName As String
Const REPORT_NAME As String = "ProgramFeeAutoCalc"
Select Case id

    Case 1
       ' MsgBox "Processing " & strFileName
        strInputPath = CurrentProject.Path & "\Input\"
        strFileName = strInputPath & REPORT_NAME & "_" & prm(0) & ".xlsx"
        Debug.Print "Processing file " & strFileName & " @ " & Now()
        bReturn = ProgramFeeAccrualSave(objExcel, strFileName)
        If bReturn Then
            Debug.Print "Successfully processed file " & strFileName
        Else
            Debug.Print "Unsuccesfully processed file " & strFileName
        End If
    Case Else
End Select
    

Exit Function
    ProcessFile = bReturn
    
End Function


Private Function ProgramFeeAccrualSave(objExcel As Excel.Application, _
    ByVal strFileName As String) As Boolean

Const COL_DATE As Integer = 1
Const COL_REVENUE As Integer = 2
Const COL_COST As Integer = 3
Const COL_PROFIT As Integer = 4
'Dim objExcel As Excel.Application
Dim wb As Excel.Workbook
Dim wks As Excel.Worksheet
Dim db As DAO.Database

Dim lngStartRow As Long
Dim lngRowCount As Long
Dim bReturn As Boolean
Dim rngAsofDate As Excel.Range
Dim rngClientID As Excel.Range
Dim lngClientID As Long
Dim asofDate As Date


Dim i As Long
Dim strMessage As String

Dim qdf As DAO.QueryDef



Set db = CurrentDb()
'Set objExcel = New Excel.Application
With objExcel
    Set wb = .Workbooks.Open(strFileName, ReadOnly:=True)
    'Set rngClientID = wb.Names("RNG_ClientID").RefersToRange.Value
    lngClientID = wb.Names("RNG_Clientid").RefersToRange.Value

    
    Set rngAsofDate = wb.Names("RNG_AsofDate").RefersToRange
    If IsDate(rngAsofDate.Value) Then
        asofDate = CDate(rngAsofDate.Value)
    End If
    
    
    Set wks = wb.Worksheets(1)
    lngRowCount = wb.Names("RNG_RowCount").RefersToRange.Value
    lngStartRow = wb.Names("RNG_RowStart").RefersToRange.Value
    Set qdf = db.QueryDefs("qryStagingTableProgramFeeMainDeleteAll")
    qdf.Execute
    
    Set qdf = Nothing
    
    
    Set qdf = db.QueryDefs("qryStagingTableProgramFeeMainAdd")
    With qdf
        .Parameters("Asofdate") = asofDate
        .Parameters("ClientID") = lngClientID
    End With
    
    For i = lngStartRow To lngStartRow + lngRowCount - 1
    
        strMessage = "No " & i - lngStartRow - 1 & " " & "Date=" & CStr(wks.Cells(i, COL_DATE)) & " " & _
            "Profit=" & CStr(wks.Cells(i, COL_PROFIT))
        With qdf
            .Parameters("txtReportDate") = CStr(wks.Cells(i, COL_DATE).Value)
            .Parameters("txtAmount") = CStr(wks.Cells(i, COL_PROFIT).Value)
            .Parameters("RowNumber") = i - lngStartRow
            .Parameters("AddedBy") = "System"
        End With
        qdf.Execute
            
            
        Debug.Print strMessage
    Next
    
    wb.Close
End With

bReturn = True
ExitProc:
    On Error Resume Next
    ProgramFeeAccrualSave = bReturn
    Set wks = Nothing
    Set wb = Nothing
    Set objExcel = Nothing
    Set qdf = Nothing
    Set db = Nothing
    Exit Function
    
End Function

Tuesday, November 8, 2016

QueryDefs with DAO and SQL Server



http://www.databasejournal.com/features/msaccess/article.php/3407531/How-to-Execute-SQL-Stored-Procedures-from-Microsoft-Access.htm

Featured Database Articles


MS Access

Posted Sep 17, 2004

How to Execute SQL Stored Procedures from Microsoft Access

By Danny Lesandrini
The simplicity and popularity of SQL Server means that more and more developers who build applications with Microsoft Access will want to learn how to take advantage of server side processing using SQL Server Stored Procedures.  The following article will demonstrate a simple method for executing procs from Access.  In addition, we'll cover questions like these:
  • How to login to SQL Server from Access and refresh object connect properties.
  • Check for existence of stored procs and add new ones where necessary.
  • Build dynamic SQL Pass Through query with parameter values.
  • Display the results of the query output in a listbox.
The  download  for this article contains all the code from the article in both Access 97 and Access 2003 versions.  You will need access to the Pubs database on a Microsoft SQL Server, including the necessary permissions to read the sysobjects table and create stored procs.  The best way to understand the process is to step through the code in debug mode and watch as it happens, but in the mean time let's look at some of the more key code scripts.

Login to SQL Server

The first step, if your application has not already managed it, is to collect and apply the login credentials to your local DAO table and/or query objects. I wrote an article about this process about four years ago and it is still available here at Database Journal.  To read it for yourself, follow this link:       ODBC DSN-Less Connection Tutorial

In fact, that's where I started when preparing the code for this article, so if you've already read that article, this login screen will be familiar to you.  The premise is simple:  collect login parameters, test validity and relink local tables and Queries.

If you name your text boxes well, the code will be very easy to read.  You will need to test each one for existence, except for the password, which may be blank, although you should be scolded if you allow blank passwords.
   ' Check for existence of Server, Database and User Name.
 ' If missing, inform user and exit.
    If IsNull(Me!txtServer) Then
        strMsg = "Enter name of your company's Server." & _
            & "(See your database administrator)"
        MsgBox strMsg, vbInformation, "Missing Data"
        Me!txtServer.SetFocus
    ElseIf IsNull(Me!txtDatabase) Then
        strMsg = "Enter name of database. (Example: PUBS)"
        MsgBox strMsg, vbInformation, "Missing Data"
        Me!txtDatabase.SetFocus
    ElseIf IsNull(Me!txtUID) Then
        strMsg = "Enter user login.  (Example: sa)" = ""
        MsgBox strMsg, vbInformation, "Missing Data"
        Me!txtDatabase.SetFocus
    Else
        strServer   = Me!txtServer
        strDatabase = Me!txtDatabase
        strUID      = Me!txtUID
        ' Password may be NULL, so provide for that possibility
        strPWD      = Nz(Me!txtPWD, "")
        
        ' Prepare connection string
        strConnect = "ODBC;DRIVER={SQL Server}" _
                & ";SERVER=" & strServer _
                & ";DATABASE=" & strDatabase _
                & ";UID=" & strUID _
                & ";PWD=" & strPWD & ";"
    End If
As you can see from the screen shot, the code also allows you to read connection information from an ini file.  While I will not take the time to list the code for that here, it is included in the download.  One might suggest that a DSN be used in place of dynamic parameters, but I have found that it is more clumsy to set up user desktops with a new DSN than it is to simply allow them to enter login credentials from the application and save them for subsequent logins.  That is my preference, so I will not cover DSNs in this article.

Make Sure Your Procs Exist

The sample application (shown below) leverages four existing stored procedures from the Pubs database, and two new ones that I created.  The metadata for these procs is stored in a local Access database, including the script to create each of them.  The next step in our process is to test for their existence and create them if they are missing.
  Private Sub CheckForStoredProcs()
    On Error Resume Next
    
    Dim qdf As dao.QueryDef
    Dim dbs As dao.Database
    Dim rst As dao.Recordset
    Dim sSQL As String
    
    ' Open a recordset of the stored procs to be used, and tested for.
    Set dbs = CurrentDb
    sSQL = "select ProcObjectName, ProcText from tblSQLProcList"
    Set rst = dbs.OpenRecordset(sSQL, dbOpenSnapshot)
    
    ' Create a querydef object and set its CONNECT property.
    Set qdf = dbs.QueryDefs("qryCheckProcs")
    qdf.Connect = strConnect
    qdf.ReturnsRecords = True
    
    ' Loop through the list, check for existance and create if needed.
    Do Until rst.EOF
        sSQL = "select count(*) as ProcExists from sysobjects " & _
               "where Name='" & rst!ProcObjectName & "'"
        qdf.SQL = sSQL
        If DLookup("[ProcExists]", "[qryCheckProcs]") = 0 Then
            ' (ProcText contains the script to create the stored proc.)
            qdf.SQL = rst!ProcText
            qdf.ReturnsRecords = False
            qdf.Execute
        End If
        rst.MoveNext
    Loop
    
    Err.Clear
    
    Set rst = Nothing
    Set qdf = Nothing
    Set dbs = Nothing
    
    End Sub
The key part in the above script is the  QueryDef.ReturnRecords  property, which must be set to TRUE when selecting records and FALSE when executing a script to create and/or alter database objects.  By the way, these procs are created automatically when you successfully login to SQL Server so they will run without error when selected in the Demo application.

Prepare and Execute Parameterized Stored Procs

The above screen shot illustrates the context sensitive nature of the criteria collection process.  Not all procs take the same parameters.  The one selected, df_Orders, requires a date range while df_Employee takes an employee name.  The table that stores the list of procs and their scripts also exposes attributes that identify which criteria options to enable.  As you click through the list, criteria collection boxes enable and disable themselves accordingly.

The code for building the SQL necessary to execute the procedures with the correct parameter values is not especially reusable, but the principal is simple and extensible.  It looks like this and the output of this script is displayed just above the listbox containing the query results. (See screen shot above.)
  Set dbs = CurrentDb
    Set qdf = dbs.QueryDefs("qryCurrentProc")
    sSQL = "exec " & lstProcs.Column(1)
    qdf.SQL = sSQL
    
    If txtPercent.Enabled Then sSQL = sSQL & " @percentage=" & txtPercent
    If txtLoLimit.Enabled Then sSQL = sSQL & " @LoLimit=" & txtLoLimit & ", "
    If txtHiLimit.Enabled Then sSQL = sSQL & " @HiLimit=" & txtHiLimit & ", "
    If txtType.Enabled Then sSQL = sSQL & " @Type='" & txtType & "'"
    If txtEmployee.Enabled Then sSQL = sSQL & " @Employee='" & txtEmployee & "'"
    If txtStart.Enabled Then sSQL = sSQL & " @Start='" & txtStart & "', @End='" & txtEnd & "'"
    
    Me.lblQuery.Caption = sSQL
    qdf.SQL = sSQL
The effect of this code is to swap out the SQL text property of the SQL Pass Through query that will be used to retrieve data.  The final step is to load the query into the listbox.  Just to make sure, the code assigns our connect string to the query's connect property.  Next, the listbox RowSource property is set to our newly updated query object and is requeried.
      qdf.Connect = strConnect
      Me.lstResults.RowSource = "qryCurrentProc"
      Me.lstResults.Requery
In addition to exposing the SQL text property of the query on the Demo application main form, there is a button that will open the actual query, along with its properties window, where you can examine all the properties exposed for a SQL Pass Through query.  Below you can see that for our ListBox query, the Return Records property is TRUE and our SQL Server login credentials are displayed in the ODBC Connect String property.

There are a number of subtleties that are not described above, like trapping for missing login parameters and moving back and forth between the login screen and the main form.  The  download  has the complete code listings and while it is nearly complete, you will likely discover some quirkiness to it.  Please overlook the minor errors and take it for what it is, a tutorial.
Also, as a final caveat I would like to admit that there other ways to accomplish the same feat, including the use of Access Data Projects (ADPs).  I have not expanded on these alternates here because I prefer the above method.  In fact, I am currently considering converting a client's ADP back to a traditional MDB and implementing the above process for data access to SQL Stored Procs.  I suppose that will give me a benchmark to test the performance difference between the access methods.  If I find that the ADP performs better, I will repent in dust and ashes and print a retraction.
      CurrentDB.QueryDefs("qryCurrentProc").SQL = "df_orders '6/15/1992', '9/15/1994'"
Sweet, huh? By assuming that our Access query has had its CONNECT property set, we just reduced the last code script to a single line.  This is easy to call for combobox sources, listboxes and even Access reports.  That is really all you need to get your Access applications to play nice with SQL Server stored procedures.  Happy computing!
» See All Articles by Columnist Danny J. Lesandrini

 

Sunday, November 6, 2016

Check whether an Excel File is Open on a Network

This function is useful if you want to see if someone else on a network has the file open

Private Declare Function lOpen Lib "kernel32" Alias "_lopen" (ByVal lpPathName As String, ByVal iReadWrite As Long) As Long
Private Declare Function lClose Lib "kernel32" Alias "_lclose" (ByVal hFile As Long) As Long

private const OF_SHARE_EXCLUSIVE=&H10

Private Function IsFileAlreadyOpen(FileName As String) As Boolean
    Dim hFile As Long
    Dim lastErr As Long
    hFile = -1
    lastErr = 0
    'hFile = lOpen(FileName, &H10)
hFile = lOpen(FileName, OF_SHARE_EXCLUSIVE)
    If hFile = -1 Then
        lastErr = Err.LastDllError
    Else
        lClose (hFile)
    End If
    sFileAlreadyOpen = (hFile = -1) And (lastErr = 32)
End Function
Private Sub Form_Load()
    MsgBox IsFileAlreadyOpen("c:\autoexec.bat")
End Sub


Private Sub CheckFileOpen()
if IsFileAlreadyOpen("C:\XYZ Corp.xlsx") then
MsgBox "File is open"
else
MsgBox "File is not open?


Saturday, November 5, 2016

Inform the use will doing a long running process in MS Access

 DoCmd.Hourglass True
    lngStartTime = GetTickCount()
    Call SysCmd(acSysCmdInitMeter, "Downloading files ...", Me.lvHistory.ListItems.Count)
    For Each objli In Me.lvHistory.ListItems
       
       
                Call CreateDailyWorkWB5(objli.SubItems(DailyWorkDetail.ClientID), _
                    objli.SubItems(DailyWorkDetail.ClientName), _
                    COB_Date, _
                    intVersionNo, _
                    intPriorVersionNo:=getPriorVersionNo())
              
                iCounter = iCounter + 1
                Call SysCmd(acSysCmdUpdateMeter, iCounter)
               
          
    Next
    lngEndTime = GetTickCount()
    lngElapsedTime = (lngEndTime - lngStartTime) * 0.001
    MsgBox "Just exported " & Format(iCounter, "##,##0") & " record(s) in " & _

        Format(lngElapsedTime, "##,##0") & " second(s) ", vbInformation, "Results"

Useful WinAPI calls


Private Declare Function ShellExecute Lib "shell32.dll" Alias _
   "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation _
   As String, ByVal lpFile As String, ByVal lpParameters _
   As String, ByVal lpDirectory As String, ByVal nShowCmd _
   As Long) As Long

Public Declare Function GetTickCount Lib "kernel32" () As Long

Private Declare Function GetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Private Declare Function GetComputerName _
Lib "kernel32" Alias "GetComputerNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long

Function getWindowsUserId() As String
' Returns the network login name.
Dim lngLen As Long, lngX As Long
Dim strUserName As String
strUserName = String$(254, 0)
lngLen = 255
lngX = GetUserName(strUserName, lngLen)
If lngX <> 0 Then
    getWindowsUserId = Left$(strUserName, lngLen - 1)
Else
    getWindowsUserId = "Unknown"
End If

End Function


Public Function GetWorkstationId() As String
' Retrieve the name of the computer.
Const acbcMaxComputerName = 15
Dim strBuffer As String
Dim lngLen As Long
strBuffer = Space(acbcMaxComputerName + 1)
lngLen = Len(strBuffer)
If CBool(GetComputerName(strBuffer, lngLen)) Then
    GetWorkstationId = Left$(strBuffer, lngLen)
Else
    GetWorkstationId = ""
End If
End Function

Public Function OpenPDFFile(ByVal strFileName) As Boolean
Dim lngErr As Long
'Dim objShell As Object

'objShell.ShellExecute
Const SW_SHOWNORMAL = 1
lngErr = ShellExecute(0, "OPEN", strFileName, vbNullString, vbNullString, SW_SHOWNORMAL)

OpenPDFFile = lngErr > 32
End Function

Useful WinAPI calls


Private Declare Function ShellExecute Lib "shell32.dll" Alias _
   "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation _
   As String, ByVal lpFile As String, ByVal lpParameters _
   As String, ByVal lpDirectory As String, ByVal nShowCmd _
   As Long) As Long

Public Declare Function GetTickCount Lib "kernel32" () As Long

Private Declare Function GetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Private Declare Function GetComputerName _
Lib "kernel32" Alias "GetComputerNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long

Function getWindowsUserId() As String
' Returns the network login name.
Dim lngLen As Long, lngX As Long
Dim strUserName As String
strUserName = String$(254, 0)
lngLen = 255
lngX = GetUserName(strUserName, lngLen)
If lngX <> 0 Then
    getWindowsUserId = Left$(strUserName, lngLen - 1)
Else
    getWindowsUserId = "Unknown"
End If

End Function


Public Function GetWorkstationId() As String
' Retrieve the name of the computer.
Const acbcMaxComputerName = 15
Dim strBuffer As String
Dim lngLen As Long
strBuffer = Space(acbcMaxComputerName + 1)
lngLen = Len(strBuffer)
If CBool(GetComputerName(strBuffer, lngLen)) Then
    GetWorkstationId = Left$(strBuffer, lngLen)
Else
    GetWorkstationId = ""
End If
End Function

Public Function OpenPDFFile(ByVal strFileName) As Boolean
Dim lngErr As Long
'Dim objShell As Object

'objShell.ShellExecute
Const SW_SHOWNORMAL = 1
lngErr = ShellExecute(0, "OPEN", strFileName, vbNullString, vbNullString, SW_SHOWNORMAL)

OpenPDFFile = lngErr > 32
End Function

Wednesday, October 26, 2016

C# Error Logger

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ErrorLogger
{
    // ===========================================================
    public class AppLog
    {
        private string _OutputFolder;
        private string _fileName;
        //
        public AppLog(string OutputFolder,string prefix="OUTPUT")
        {
            string fileName;
            fileName = prefix + "_" + this.getUserName() + "_" + this.getJulianDate() + "_" + this.getTimeStamp() + "_" + this.getRandomNumber() + ".txt";
            _fileName=Path.Combine(OutputFolder,fileName);
            //
            _OutputFolder = OutputFolder;
        }


      /// <summary>
      /// will log error info: DateStamp,UserName and error message
      /// </summary>
      /// <param name="dateStamp"></param>
      /// <param name="UserName"></param>
      /// <param name="ErrorMsg"></param>
      /// <returns></returns>
      ///
        // ===============================================
        public string getUserName()
        {
            return Environment.UserName;
        }
        // ================================================
        public string getJulianDate()
        {
            string value;
            value = DateTime.Now.ToString("yyyyMMdd");
            return value;
        }
        // ===============================================
        public string getTimeStamp()
        {
            string rvalue;
            rvalue=DateTime.Now.ToString("HHmmss");
            return rvalue;
        }
        // ===============================================
        public string getRandomNumber()
        {
            int seed = (int)DateTime.Now.Ticks;
            Random rndNumber = new Random(seed);
            int value = rndNumber.Next(0,10000);
            string rvalue = String.Format(value.ToString(),"{0:00000}");
            return rvalue;
        }
        // ========================================================
        public bool LogEvent(DateTime dateStamp, string UserName, string ErrorMsg)
        {
            bool returnValue;
            try
            {
                string output = UserName + "," + dateStamp.ToString() + "," + ErrorMsg;
                using (StreamWriter sw = new StreamWriter(new FileStream(path: _fileName, mode: FileMode.Append, access: FileAccess.Write)))
                {
                    sw.WriteLine(output);
                }
                returnValue = true;
            }
            catch (Exception )
            {
                returnValue = false;
            }
            return returnValue;
        }
        /// <summary>
        /// wjd 4-26-2016 added overload method to capture non-fatal errors will reading the file via OpenXML
        /// </summary>
        /// <param name="dateStamp"></param>
        /// <param name="UserName"></param>
        /// <param name="ErrorMsg"></param>
        /// <param name="ValidationErrors"></param>
        /// <returns></returns>
        ///
        // ============================================================================================
        public bool LogEvent(DateTime dateStamp, string UserName, IEnumerable<string> ValidationErrors)
        {
            bool returnValue;
            try
            {
                string output = UserName + "," + dateStamp.ToString();
                using (StreamWriter sw = new StreamWriter(new FileStream(path: _fileName, mode: FileMode.Append, access: FileAccess.Write)))
                {
                    sw.WriteLine(output);
                    foreach (string validationError in ValidationErrors)
                    {
                        sw.WriteLine( validationError);
                    }
                }
                returnValue = true;
            }
            catch (Exception ex)
            {
                returnValue = false;
            }
            return returnValue;
        }
    }
}

Thursday, October 20, 2016

Common WinAPI functionality

(1) Declare WinAPI
(2) Write public functions


Option Compare Database
Option Explicit





Private Declare Function ShellExecute Lib "shell32.dll" Alias _
   "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation _
   As String, ByVal lpFile As String, ByVal lpParameters _
   As String, ByVal lpDirectory As String, ByVal nShowCmd _
   As Long) As Long
'************** Code Start **************
'This code was originally written by Terry Kreft.
'It is not to be altered or distributed,
'except as part of an application.
'You are free to use it in any application,
'provided the copyright notice is left unchanged.
'
'Code courtesy of
'Terry Kreft

Private Type BROWSEINFO
  hOwner As Long
  pidlRoot As Long
  pszDisplayName As String
  lpszTitle As String
  ulFlags As Long
  lpfn As Long
  lParam As Long
  iImage As Long
End Type

Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias _
            "SHGetPathFromIDListA" (ByVal pidl As Long, _
            ByVal pszPath As String) As Long
           
Private Declare Function SHBrowseForFolder Lib "shell32.dll" Alias _
            "SHBrowseForFolderA" (lpBrowseInfo As BROWSEINFO) _
            As Long


Private Const BIF_RETURNONLYFSDIRS = &H1

Public Declare Function GetTickCount Lib "kernel32" () As Long

Private Declare Function GetUserName Lib "advapi32.dll" Alias _
"GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Private Declare Function GetComputerName _
Lib "kernel32" Alias "GetComputerNameA" _
(ByVal lpBuffer As String, nSize As Long) As Long

Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias _
"GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long

Private Type OPENFILENAME
    lStructSize As Long
    hwndOwner As Long
    hInstance As Long
    lpstrFilter As String
    lpstrCustomFilter As String
    nMaxCustFilter As Long
    nFilterIndex As Long
    lpstrFile As String
    nMaxFile As Long
    lpstrFileTitle As String
    nMaxFileTitle As Long
    lpstrInitialDir As String
    lpstrTitle As String
    Flags As Long
    nFileOffset As Integer
    nFileExtension As Integer
    lpstrDefExt As String
    lCustData As Long
    lpfnHook As Long
    lpTemplateName As String
End Type


Private Declare Function GetSaveFileNameA Lib "comdlg32.dll" (pOpenfilename As OPENFILENAME) As Long
Private Declare Function GetActiveWindow Lib "user32" () As Long

Public Function SaveAsCommonDialog(iOfficeVersion As OfficeProduct, _
    strForm As Form, _
    Optional sTitle = "Save File", _
    Optional sDefaultDir As String, _
    Optional filename As String = "") As String
   
Const clBufferLen As Long = 255
Dim OFName As OPENFILENAME, sBuffer As String * clBufferLen
Dim sFilter As String
On Error GoTo ExitFunction

OFName.lStructSize = Len(OFName)
OFName.hwndOwner = strForm.hwnd ' GetActiveWindow  'or Me.hwnd in VB
'OFName.hInstance = 0                'or App.hInstance in VB

'If Len(sFilter) Then
'    OFName.lpstrFilter = sFilter
'Else
'    OFName.lpstrFilter = "Text Files (*.txt)" & Chr$(0) & "*.txt" & Chr$(0) & "All Files (*.*)" & Chr$(0) & "*.*" & Chr$(0)
'End If
   
Select Case iOfficeVersion
    Case OfficeProduct.Excel2007Only
     
        sFilter = "Excel 2007 Workbooks (*.xlsx)" & Chr(0) & "*.xlsx" & Chr(0) & _
            "Excel 2003 Workbooks (*.xls)" & Chr(0) & "*.xls" & Chr(0)
       
    Case OfficeProduct.Access2007Only
        sFilter = "Access Databases 2007(*.acdb*)" & Chr(0) & "*.acdb" & Chr(0) & _
            "Access Databases 2003 (*.MDB)" & Chr(0) & "*.MDB & Chr(0)"
   
    Case Else
        sFilter = "All Files (*.*)" & Chr(0) & "*.*"
End Select
   
   
OFName.lpstrFilter = sFilter
OFName.nFilterIndex = 1
   
' set file to initialDir and Filename (Note - need to retain length of sBuffer)
If filename <> "" Then
    Dim initialFilePath As String
    If Right(sDefaultDir, 1) = "\" Then
        initialFilePath = sDefaultDir & filename
    Else
        initialFilePath = sDefaultDir & "\" & filename
    End If
    sBuffer = initialFilePath & (Right(sBuffer, Len(sBuffer) - Len(initialFilePath)))
End If

OFName.lpstrFile = sBuffer
OFName.nMaxFile = clBufferLen       'Set max number of characters
OFName.lpstrFileTitle = sBuffer
OFName.nMaxFileTitle = clBufferLen  'Set max number of characters
   
'Set the initial directory
If Len(sDefaultDir) Then
    OFName.lpstrInitialDir = sDefaultDir
Else
    OFName.lpstrInitialDir = CurDir$
End If

OFName.lpstrTitle = sTitle
OFName.Flags = 0

'debug.Print "sBuffer: " & sBuffer

'Show dialog
If GetSaveFileNameA(OFName) Then
    SaveAsCommonDialog = Left$(OFName.lpstrFile, InStr(1, OFName.lpstrFile, Chr(0)) - 1)
Else
    SaveAsCommonDialog = ""
End If
ExitFunction:
    On Error GoTo 0
End Function


Function getWindowsUserId() As String
' Returns the network login name.
Dim lngLen As Long, lngX As Long
Dim strUserName As String
strUserName = String$(254, 0)
lngLen = 255
lngX = GetUserName(strUserName, lngLen)
If lngX <> 0 Then
    getWindowsUserId = Left$(strUserName, lngLen - 1)
Else
    getWindowsUserId = "Unknown"
End If

End Function


Public Function GetWorkstationId() As String
' Retrieve the name of the computer.
Const acbcMaxComputerName = 15
Dim strBuffer As String
Dim lngLen As Long
strBuffer = Space(acbcMaxComputerName + 1)
lngLen = Len(strBuffer)
If CBool(GetComputerName(strBuffer, lngLen)) Then
    GetWorkstationId = Left$(strBuffer, lngLen)
Else
    GetWorkstationId = ""
End If
End Function


Public Function BrowseFolder(szDialogTitle As String) As String
  Dim X As Long, bi As BROWSEINFO, dwIList As Long
  Dim szPath As String, wPos As Integer
 
    With bi
        .hOwner = hWndAccessApp
        .lpszTitle = szDialogTitle
        .ulFlags = BIF_RETURNONLYFSDIRS
    End With
   
    dwIList = SHBrowseForFolder(bi)
    szPath = Space$(512)
    X = SHGetPathFromIDList(ByVal dwIList, ByVal szPath)
   
    If X Then
        wPos = InStr(szPath, Chr(0))
        BrowseFolder = Left$(szPath, wPos - 1)
    Else
        BrowseFolder = vbNullString
    End If
End Function


Function APIGetOpenFileNameCD(iOfficeVersion As OfficeProduct, _
    strForm As Form, Optional _
    InitialFileName As String) As String
Dim OpenFile As OPENFILENAME
Dim lReturn As Long
Dim sFilter As String
   
   
OpenFile.lStructSize = Len(OpenFile)
OpenFile.hwndOwner = strForm.hwnd
   
Select Case iOfficeVersion
    Case OfficeProduct.Excel2007Only
     
        sFilter = "Excel 2007 Workbooks (*.xlsx)" & Chr(0) & "*.xlsx" & Chr(0) & _
            "Excel 2003 Workbooks (*.xls)" & Chr(0) & "*.xls" & Chr(0)
       
    Case OfficeProduct.Access2007Only
        sFilter = "Access Databases 2007(*.acdb*)" & Chr(0) & "*.acdb" & Chr(0) & _
            "Access Databases 2003 (*.MDB)" & Chr(0) & "*.MDB & Chr(0)"
   
    Case Else
        sFilter = "All Files (*.*)" & Chr(0) & "*.*"
End Select
    'sFilter = "All Files (*.*)" & Chr(0) & "*.*" & Chr(0) & _
      "JPEG Files (*.JPG)" & Chr(0) & "*.JPG" & Chr(0)
OpenFile.lpstrFilter = sFilter
OpenFile.nFilterIndex = 1
OpenFile.lpstrFile = String(257, 0)
OpenFile.nMaxFile = Len(OpenFile.lpstrFile) - 1
OpenFile.lpstrFileTitle = OpenFile.lpstrFile
OpenFile.nMaxFileTitle = OpenFile.nMaxFile
If Len(InitialFileName) > 0 Then
    OpenFile.lpstrInitialDir = InitialFileName
Else
    OpenFile.lpstrInitialDir = "C:\"
End If
   

OpenFile.lpstrTitle = "Select a file name"
OpenFile.Flags = 0
lReturn = GetOpenFileName(OpenFile)
If lReturn = 0 Then
    'MsgBox "A file was not selected!", vbInformation, _
      "Select a file using the Common Dialog DLL"
    Exit Function
Else
    APIGetOpenFileNameCD = Trim(Left(OpenFile.lpstrFile, InStr(1, OpenFile.lpstrFile, vbNullChar) - 1))
End If
End Function


Public Function OpenPDFFile(ByVal strFileName) As Boolean
Dim lngErr As Long
'Dim objShell As Object

'objShell.ShellExecute
Const SW_SHOWNORMAL = 1
lngErr = ShellExecute(0, "OPEN", strFileName, vbNullString, vbNullString, SW_SHOWNORMAL)

OpenPDFFile = lngErr > 32
End Function

Wednesday, October 12, 2016

Form Picker (Access VBA)









Option Compare Database

Private m_bOk As Boolean
Private m_frmParent As Form
Private Sub cmdCancel_Click()
DoCmd.Close acForm, Me.Name
End Sub


Private Sub cmdOk_Click()
Dim strSourceControlName As String
Dim strDestinationControlName As String
Dim lngFindPos As Long

'lngFindPos = InStr(1, Nz(Me.OpenArgs), "-")
'If lngFindPos Then
'    strSourceControlName = Mid(Me.OpenArgs, 1, lngFindPos - 1)
'    strDestinationControlName = Mid(Me.OpenArgs, lngFindPos + 1)
'Else
'    strDestinationControlName = Nz(Me.OpenArgs)
'End If

strSourceControlName = Nz(Me.OpenArgs)
m_bOk = True
'Unload Me

'With Forms(m_frmParent.Name).Controls(strSourceControlName)
 '   .RowSource = vbNullString
 '   .RowSource = Me.TargetList()
'End With
Call setLVRowSourceProperty(Forms(m_frmParent.Name).Controls(strSourceControlName), _
    Me.TargetList())
DoCmd.Close acForm, Me.Name
End Sub

Private Sub cmdToDestination_Click()

If Not (Me.lbSource.ListIndex = -1) Then
    'Me.lbSource.AddItem strNewEntry, Me.lbSource.ListIndex + 1
    Me.lbDestination.AddItem lbSource.Value
    Me.lbSource.RemoveItem Me.lbSource.ListIndex
End If
End Sub

Private Sub cmdToSource_Click()
If Not (Me.lbDestination.ListIndex = -1) Then
    'Me.lbSource.AddItem strNewEntry, Me.lbSource.ListIndex + 1
    Me.lbSource.AddItem lbDestination.Value
    Me.lbDestination.RemoveItem Me.lbDestination.ListIndex
End If
End Sub

Public Property Let TargetList(ByVal strValue As String)
If Len(strValue) Then
    Me.lbDestination.RowSource = strValue
End If
End Property

Public Property Get TargetList() As String
    TargetList = Me.lbDestination.RowSource
End Property

Public Property Get bOK() As Boolean
bOK = m_bOk
End Property

Private Sub Command8_Click()
Dim i As Integer
With Me.lbSource
    .RowSourceType = "Value List"
    .RowSource = vbNullString
    .ColumnCount = 1
    .BoundColumn = 1
   ' .AddItem "Yankees;East;AL"
   ' .AddItem "Boston RedSox;East;AL"
   ' .AddItem "Floriday Marlins;East;AL"
    '.AddItem "Seattle Mariners;West;AL"
   ' .AddItem "NY Mets;East;NL"
    For i = 1 To 12
        .AddItem MonthName(i)
    Next
End With
End Sub

Private Sub Form_Load()
Const ssource As String = "Form_Load"
On Error GoTo ErrorHandler
DoCmd.Hourglass True
Dim strSQL As String, strTable As String
Dim rs As ADODB.Recordset
Dim objConn As ADODB.Connection
Dim i As Integer
Dim varItem As Variant
Dim strCriteria, aCriteria() As String
Dim strValue As String

Dim strControlName As String
Dim strSourceControlName As String
Dim strDestinationControlName As String
Dim lngFindPos As Long
Dim lbSource As Control 'ListBox

Set m_frmParent = Screen.ActiveForm
'lngFindPos = InStr(1, Nz(Me.OpenArgs), "-")
'If lngFindPos Then
'    strSourceControlName = Mid(Me.OpenArgs, 1, lngFindPos - 1)
'    strDestinationControlName = Mid(Me.OpenArgs, lngFindPos + 1)
'Else
'    strDestinationControlName = Nz(Me.OpenArgs)
'End If

strSourceControlName = Nz(Me.OpenArgs)
With Me
    .lbDestination.RowSourceType = "Value List"
    .lbDestination.ColumnCount = 1
    .lbSource.RowSourceType = "Value List"
    .lbSource.ColumnCount = 1
   
    'build lb's
    'Call Command8_Click
    'do not include user's selections
    '.lbDestination.RowSource = Forms(m_frmParent.Name).Controls(strSourceControlName).RowSource
    .lbDestination.RowSource = getLVRowSourceProperty(Forms(m_frmParent.Name).Controls(strSourceControlName))
End With

Set lbSource = Forms(m_frmParent.Name).Controls(strSourceControlName)
With Me.lbSource
   
    .RowSource = ""
    .RowSourceType = "Value List"
    .ColumnHeads = False
    .ColumnCount = 1
    .ColumnWidths = "2 in"
  
   
    'For Each varItem In lb.ItemsSelected
    '    strValue = strValue & lb.Column(1, varItem) & ","
    'Next
   
    '11/29 took out
    'strValue = lbSource.RowSource
    strValue = Me.lbDestination.RowSource
   
    aCriteria() = Split(strValue, ";")
    For i = LBound(aCriteria) To UBound(aCriteria)
        strCriteria = strCriteria & " " & " Note LIKE " & "'%" & aCriteria(i) & "%' OR"
    Next
    'avoid duplicating user's selections
    If Len(strCriteria) Then
        'remove trailing OR
        strCriteria = Left(strCriteria, Len(strCriteria) - 3)
        strSQL = "SELECT Note FROM tblLanguage WHERE " & _
        " NOT (" & strCriteria & " )" & _
        " ORDER BY Note "
    Else
        strSQL = "SELECT Note" & _
            " FROM tblLanguage " & _
            " ORDER BY Note"
    End If
   
    'Debug.Print strSQL
   
    Set rs = New ADODB.Recordset
    With rs
        .LockType = adLockOptimistic
        .CursorType = adOpenDynamic
    End With
   
    Set objConn = New ADODB.Connection
    Set objConn = CurrentProject.Connection
   
    rs.Open strSQL, objConn, Options:=adCmdText
    If Not (rs.EOF() And rs.BOF) Then
        strSQL = ""
        Do While Not rs.EOF
            For i = 0 To rs.Fields.Count - 1
                strSQL = strSQL & Nz(rs.Fields(i)) & ";"
            Next
            strSQL = Mid(strSQL, 1, Len(strSQL) - 1)
            .AddItem strSQL
            strSQL = ""
            rs.MoveNext
        Loop
    End If
  
End With

ExitProc:
    On Error Resume Next
    Set objConn = Nothing
    Set rs = Nothing
    DoCmd.Hourglass False
    Exit Sub

ErrorHandler:
   
    If bCentralErrorHandler("frmPicker", ssource) Then
        Stop
        Resume
    Else
        Resume ExitProc
    End If

End Sub

Private Sub Form_Open(Cancel As Integer)
If IsNull(Me.OpenArgs) Then
    Cancel = True
    Exit Sub
End If

End Sub

Private Sub lbDestination_DblClick(Cancel As Integer)
Call cmdToSource_Click
End Sub


Private Sub lbSource_DblClick(Cancel As Integer)
Call cmdToDestination_Click
End Sub