Solved

recursive - can this be done?

Posted on 2002-03-06
24
261 Views
Last Modified: 2008-02-01
hi,

i have table that holds all the folders for a drive.
The table is made up like this:

FolderID  (autonumber - Pr.Key)
Foldername (name of the folder...)
FolderLevel (C: = 0, Winnt = 1, System32 = 2, etc)
FolderParentID (FolderID of the parentfolder, if Winnt
                has folderid 15, then system32 will
                have 15 as folderparentID)


this way i am able to use this table several times in one query to show a folder-structure.
Another table holds the nt-security-settings for each folder (with the local and global groups)

but, u guessed, this is not exactly a nice way of working

so i was thinking of loading this into a treeview,
and i assume i will need some sort of recursive function(s) for it to accomplish.

is this correct?
if so, has anyone have any experience with this  kind of thing?
again, if so, any directions...?

cheers
Ricky
0
Comment
Question by:Paurths
  • 8
  • 7
  • 5
  • +4
24 Comments
 
LVL 45

Expert Comment

by:aikimark
Comment Utility
Not really.  You aren't bound to use a recursive function. I'm not entirely sure I understand your problem or why you're changing something that already works.

Are you looking for alternatives?
Is your problem mostly a processing problem?
Performance problem?
Directory name/parentage data gathering problem?

I assume you need to support cascading security, group security, as well as user-specific security.  If I'm wrong, please let me know.

What are the details of this application?
0
 
LVL 45

Expert Comment

by:aikimark
Comment Utility
In addition:

What do you want to do with hidden and system directories?

What does the user need to do?  I ask this question because the Treeview control can slow your application needlessly if the user doesn't need to access this information.
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
hi akimark,

actually, i am still developing this program,
it has all (i hope) the issues about network.
routers, outlets, patchpanel, computers, printers, printservers (jet-direct and axis), desks, users, devisions, locations, local groups, global groups, etc...

this is only a small part of the entire program.
What i would like to do is:
if i could fill a treeview with all the folders, click on a node (e.g. a folder on a shared folder) immediatly know what groups, users, have what permissions.
I know i can retrieve this information in my form where the folders are shown/added.
I was just wondering if it can be done. (i would probably be the only person on this planet using this program, but i figured it would be good excercice...)

cheers
Ricky
0
 
LVL 45

Expert Comment

by:aikimark
Comment Utility
The quickest/easiest development effort will use a Directory (intrinsic) control.  When the user selects a directory, you gather the permissions and display them.

If you gather all the permissions, you can either loop through them, looking for candidates with the LIKE operator, or place them in a table and use SQL with a WHERE LIKE search criteria.

You will possibly have several rules that will cascade (apply) to the selected directory.
0
 
LVL 14

Expert Comment

by:puranik_p
Comment Utility
Dim ParentFolder as Scripting.Folder
Dim oFolder as Scripting.Folder

Private Sub Form_Load()
    Dim oFSO as Scripting.FileSystemObject
    Set oFolder = oFSO.GetFolder("your\path")
    Call DoTree(oFolder)
End Sub

Private Function DoTree(oFolder as Scripting.Folder)
    For Each Folder In oFolder.Folders
        'Code to Process the folder
        Call DoTree(oFolder)
    Next
End Function
0
 
LVL 1

Expert Comment

by:matthewroberts
Comment Utility
Here is a snippet I just did in an Access Module (referencing mscomctl.ocx) for loading an employee hierachy from the CEO down..

This assumes you have an MSAccess table called "tblEmp"
Fields:
EmpID (Long)
EmpName (Text)
ParentEmpID (Long)

Whack the following functions in a vb module or form class and call the function:

BuldTree TreeView1

in Form_Load event

Change the following code to loop your FileSystemObjects instead of the tblEmp table records... good luck!

Option Explicit

Public Sub BuildTree(oTreeView As TreeView)
   
    Dim sql         As String
    Dim rs          As Recordset
    Dim NodX        As Node
   
On Error GoTo ET


'    With oTreeView
'        .Font = 1 ' .Font = "Tahoma"
'        .Font.Size = "12"
'        .Font.Bold = True
'        '.Indentation = "500"
'        .LabelEdit = False
'        '.LineStyle = 1
'        '.Style = 7
'        '.FullRowSelect = True
'    End With

'The following comments is a sample of adding nodes to the tree
       
'    Set nodX = oTreeView.Nodes.Add(, , "R", "Root")
'    Set nodX = oTreeView.Nodes.Add("R", tvwChild, "C1", "Child 1")
'    Set nodX = oTreeView.Nodes.Add("R", tvwChild, "C2", "Child 2")
'    Set nodX = oTreeView.Nodes.Add("R", tvwChild, "C3", "Child 3")
'    Set nodX = oTreeView.Nodes.Add("R", tvwChild, "C4", "Child 4")
'    Set nodX = oTreeView.Nodes.Add("C4", tvwChild, "C5", "Child 5")
'    Set nodX = oTreeView.Nodes.Add("C5", tvwChild, "C6", "Child 6")
'    nodX.EnsureVisible
   
'Add Parent Root Node ie. CEO

    'assume CEO's EmpID=1
    Set NodX = oTreeView.Nodes.Add(, , "Key=1", DLookup("EmpName", "tblEmp", "EmpID = 1"))

    AddChildNodes oTreeView, 1

    NodX.Bold = True
    NodX.ForeColor = 255
   
    Exit Sub

ET:
    MsgBox Err.Number & " - " & Err.Description, vbCritical
End Sub

Private Sub AddChildNodes(oTreeView As TreeView, EmpID As Integer)
   
    Dim rs      As Recordset
    Dim sql     As String
    Dim NodX    As Node
   
    sql = "SELECT EmpID, EmpName, ParentEmpID"
    sql = sql & " FROM tblEmp"
    sql = sql & " WHERE ParentEmpID = " & EmpID
    sql = sql & " ORDER BY EmpID;"
    Set rs = CurrentDb.OpenRecordset(sql, dbOpenForwardOnly)
   
    Do Until rs.EOF
        Set NodX = oTreeView.Nodes.Add("Key=" & EmpID, tvwChild, "Key=" & rs!EmpID, rs!EmpName)
        AddChildNodes oTreeView, rs!EmpID
        rs.MoveNext
    Loop
    rs.Close
    Set rs = Nothing

End Sub

Public Sub DelTree(oTreeView As TreeView)

    Do While oTreeView.Nodes.Count > 0
        oTreeView.Nodes.Remove (1)
    Loop
   
End Sub
0
 
LVL 45

Accepted Solution

by:
aikimark earned 50 total points
Comment Utility
In order to get the puranik_p example to work:
1. add the Microsoft Scripting Runtime reference to your project.
2.
Option Explicit

Dim Folder As Scripting.Folder  'Not ParentFolder

'Dim strDirectories(12000) As String
'Dim intDircount As Integer

Private Function DoTree(oFolder As Scripting.Folder)
   For Each Folder In oFolder.SubFolders  'not oFolder.Folders
       'Code to Process the folder
       'intDircount = intDircount + 1
       'strDirectories(intDircount) = Folder.Path
       Call DoTree(Folder)
   Next
End Function

Private Sub Form_Load()
    Dim oFolder As Scripting.Folder
    Dim oFSO As New Scripting.FileSystemObject  'NEW
    Set oFolder = oFSO.GetFolder("c:\")
    Call DoTree(oFolder)
End Sub

=========================================
Here is a low-tech approach to gather the directory tree data:
1. shell a batch file with the following statement
dir c:\ /ad /b /s > dirlist.txt
2. when the batch file is finished, read the contents of the file into your program

=========================================
Alternatively, you could also use the Windows API calls to collect the directory data if performance is an issue.  The Scripting Runtime library wraps these APIs, so you could remove one of the layers.

=========================================
If you use the directory control, you wait until the user selects the directory to gather and display data.  This should provide the best user-perceived performance, since the user begins using the application with the least amount of delay, due to postponed and avoided processing.
0
 
LVL 18

Expert Comment

by:mdougan
Comment Utility
I wrote a form to do pretty much what you are asking.  First off, yes, you can use recursion to go through all folders and load them into a treeview but a word of warning, it's very slow.  You might not realize it but there are maybe hundreds or thousands of folders under Program Files, WINNT or some of the major folders.  Even if you are just looking at directories, it can take a long time to load the tree.

I finally settled on loading one level at a time.  So, first load all of the top level folders.  Then, as you expand a folder just get it's direct child folders etc.

My example was also trying to track the folder sizes to help me locate disk-hogs.  Here is some of the code.  If you want the stuff that actually gets the directory size let me know.  With a little tinkering this should do what you want.

Open a projet with a Treeview, a ListView, a Drive File List, name them appropriatly and paste in this code.  You might have to comment out the calls to GetDirectorySize.

Private Sub Drive1_Change()
Dim oNode As Node
    tvwDirectory.Nodes.Clear
    Set Node = tvwDirectory.Nodes.Add(, , Left$(Drive1.Drive, 1) & ":", Left$(Drive1.Drive, 1) & ":", 1)
    GetDirContents Left$(Drive1.Drive, 1) & ":"
    tvwDirectory_NodeClick tvwDirectory.Nodes(1)
    tvwDirectory.Nodes(1).Expanded = True
End Sub

Private Sub Form_Load()
    FormLoading = True
    lvwDisplay.View = lvwReport
    lvwDisplay.ColumnHeaders.Add , , "Name", lvwDisplay.Width * 0.3, lvwColumnLeft
    lvwDisplay.ColumnHeaders.Add , , "Size", lvwDisplay.Width * 0.2, lvwColumnRight
    lvwDisplay.ColumnHeaders.Add , , "Relative", lvwDisplay.Width * 0.5, lvwColumnLeft
   
    Drive1.Drive = "C:"
    Drive1_Change
    FormLoading = False
       
End Sub

Private Sub GetDirContents(sPath As String)
Dim oNode As Node
Dim sTemp As String
Dim sMatch As String

    If tvwDirectory.Nodes(sPath).Children > 0 Then Exit Sub
   
    If Right$(sPath, 1) = "\" Then
        sTemp = sPath
    Else
        sTemp = sPath & "\"
    End If
   
    sMatch = Dir$(sTemp & "\*.", vbDirectory)
   
    Do While sMatch <> ""
        If sMatch <> "." And sMatch <> ".." Then
            If ((GetAttr(sTemp & sMatch) And vbDirectory) = vbDirectory) Then
                Set Node = tvwDirectory.Nodes.Add(sPath, tvwChild, sTemp & sMatch, sMatch, 2)
            End If
        End If
        sMatch = Dir$()
    Loop
   

End Sub

Private Sub tvwDirectory_Collapse(ByVal Node As MSComctlLib.Node)
    Node.Image = 2
End Sub

Private Sub tvwDirectory_Expand(ByVal Node As MSComctlLib.Node)
Dim oNode As Node
Dim vIndex As Variant
    Node.Image = 3
    GetDirContents Node.Key
    If Node.Children > 0 Then
        Set oNode = Node.Child
'        GetDirContents oNode.Key
        If Not oNode.LastSibling Is Nothing Then
            vIndex = oNode.LastSibling.Index
            Do While Not oNode Is Nothing
                GetDirContents oNode.Key
                If oNode.Index <> vIndex Then
                    Set oNode = oNode.Next
                Else
                    Set oNode = Nothing
                End If
            Loop
        End If
    End If

End Sub

Private Sub tvwDirectory_NodeClick(ByVal Node As MSComctlLib.Node)
Dim oNode As Node
Dim oListItem As ListItem
Dim vIndex As Variant
Dim dblDirSize As Double
Dim dblTemp As Double

    lvwDisplay.ListItems.Clear
   
    GetDirContents Node.Key
    Set oListItem = lvwDisplay.ListItems.Add(, , "Files", 4, 4)
 '   dblDirSize = GetDirectorySize(Node.Key)
    oListItem.SubItems(1) = Format((dblDirSize + 1) / 1000, "###,###,###,##0") & "KB"
    oListItem.SubItems(2) = "*****"
    If Node.Children > 0 Then
        Set oNode = Node.Child
'        GetDirContents oNode.Key
        If Not oNode.LastSibling Is Nothing Then
            vIndex = oNode.LastSibling.Index
            Do While Not oNode Is Nothing
                GetDirContents oNode.Key
                Set oListItem = lvwDisplay.ListItems.Add(, , oNode.Text, 2, 2)
                dblDirSize = GetDirectorySize(oNode.Key)
                oListItem.SubItems(1) = Format((dblDirSize + 1) / 1000, "###,###,###,##0") & "KB"
                oListItem.SubItems(2) = "*****"
                If oNode.Index <> vIndex Then
                    Set oNode = oNode.Next
                Else
                    Set oNode = Nothing
                End If
            Loop
        End If
    End If
    dblDirSize = 0
    For i = 1 To lvwDisplay.ListItems.Count
        Set oListItem = lvwDisplay.ListItems(i)
        dblDirSize = dblDirSize + CDbl(Left(oListItem.SubItems(1), Len(oListItem.SubItems(1)) - 2))
    Next i
    For i = 1 To lvwDisplay.ListItems.Count
        Set oListItem = lvwDisplay.ListItems(i)
        dblTemp = CDbl(Left(oListItem.SubItems(1), Len(oListItem.SubItems(1)) - 2))
        If dblTemp > 0 Then
            oListItem.SubItems(2) = String(((dblTemp / dblDirSize) * 100), "*")
        End If
    Next i
   
End Sub
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
hi all,

actually, this one works for me:

code provided by ameba:

**************************************
To load a tree, I suggest Chris Eastwood's code, which first adds all nodes to root, and later reparents
them. .Tag property is used to cache ParentID.


Private Sub FillTree()
   Dim lCount As Long
   Dim rsSections As Recordset
   Dim sParent As String
   Dim sKey As String
   Dim sText As String
   Dim bBookMark As Boolean
   Dim nNode As Node
   On Error GoTo vbErrorHandler
'
' Populate our TreeView Control with the Data from our database
'
   Set rsSections = mDB.OpenRecordset("select * from codeitems order by parentid")
   
   Set tvCodeItems.ImageList = Nothing
   Set tvCodeItems.ImageList = ImageList1

   If rsSections.BOF And rsSections.EOF Then
       tvCodeItems.Nodes.Add , , "ROOT", "Code Library", "VIEWBOOKMARKS"
       BoldTreeNode tvCodeItems.Nodes("ROOT")
       Exit Sub
   End If
       
   TreeRedraw tvCodeItems.hwnd, False
   
   rsSections.MoveFirst
   Set tvCodeItems.ImageList = Nothing
   Set tvCodeItems.ImageList = ImageList1
'
' Populate the TreeView Nodes
'

   With tvCodeItems.Nodes
       .Clear
       .Add , , "ROOT", "Code Library", "VIEWBOOKMARKS"
'
' Make our Root Item BOLD
'
       BoldTreeNode tvCodeItems.Nodes("ROOT")
'
' Now add all nodes into TreeView, but under the root item.
' We reparent the nodes in the next step
'
       Do Until rsSections.EOF
           sParent = rsSections("ParentID").Value
           sKey = rsSections("ID").Value
           sText = rsSections("Description").Value
           Set nNode = .Add("ROOT", tvwChild, "C" & sKey, sText, "FOLDER")
'
' Record parent ID
'
           nNode.Tag = "C" & sParent
           rsSections.MoveNext
       Loop
   
   End With
'
' Here's where we rebuild the structure of the nodes
'
   For Each nNode In tvCodeItems.Nodes
       sParent = nNode.Tag
       If Len(sParent) > 0 Then        ' Don't try and reparent the ROOT !
           If sParent = "C0" Then
               sParent = "ROOT"
           End If
           Set nNode.Parent = tvCodeItems.Nodes(sParent)
       End If
   Next
'
' Now setup the images for each node in the treeview & set each node to
' be sorted if it has children
'
   For Each nNode In tvCodeItems.Nodes
       If nNode.Children = 0 Then
           nNode.Image = "CHILD"
       Else
           nNode.Sorted = True
       End If
   Next
   
   Set rsSections = Nothing
'
' Expand the Root Node
'
   tvCodeItems.Nodes("ROOT").Sorted = True
   tvCodeItems.Nodes("ROOT").Expanded = True
   
   TreeRedraw tvCodeItems.hwnd, True
   Exit Sub

vbErrorHandler:
   TreeRedraw tvCodeItems.hwnd, True
   MsgBox Err.Number & " " & Err.Description & " " & Err.Source
End Sub

Private Sub TreeRedraw(ByVal lHwnd As Long, ByVal bRedraw As Boolean)
   SendMessageLong lHwnd, WM_SETREDRAW, bRedraw, 0
End Sub

************************




all agree that this solves it for me? (i agree, b/c it did exactly what i wanted...)

0
 
LVL 18

Expert Comment

by:mdougan
Comment Utility
ameba, I hadn't heard of this technique before.  Is it faster to load this way?  Or does is just simplify retrieving the data so that you don't have to order the recordset with all children following their parents.
0
 
LVL 45

Expert Comment

by:aikimark
Comment Utility
Paurths,

What advantage is there to recreate the function/contents of the DirectoryList box?  Messing with a Treeview control is slower and performs unnecessary to iterate/add-node for a directory the user isn't interested in seeing.
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
that is correct aikimark,

but there wont be no users using this program.
its for my use only.
comment of Date: 03/06/2002 03:47PM PST
****************************
What i would like to do is:
if i could fill a treeview with all the folders, click on a node (e.g. a folder on a shared folder)
immediatly know what groups, users, have what permissions.
I know i can retrieve this information in my form where the folders are shown/added.
I was just wondering if it can be done. (i would probably be the only person on this planet using this
program, but i figured it would be good excercice...)
*****************************

since the database will hold all the users, global groups, local groups, folders, permissions on folders it would / could give me a quick view 'who can do what' when i click a folder.
Sometimes when i receive a call from any user of our network asking me why on earth (s)he can not write/delete/access a certain folder i need to look up permissions. The way it is done now takes too long.
with a click on folder in the treeview i want to see why this user calls me.
In the end there wont be that many folders in this database.
Only the folders where the shared data is, will be present. (for several servers tho) So i'm not talking about a couple of thousand folders. (perhaps in the future)
Since the security only goes 3 or 4 levels deep, this must be managable.
If a user adds a folder at level e.g. 7 just for her/his sake i dont need that in the database. (for now)


like i said, there might be programs out there that have a solution for this, but i really want a total program where i can also place computers on desks. (using Visio for the graphical interface of the building / offices --> is build automatically on the click of a button, nice tool, when a desk gets moved i give it other co-ordinates in the program and it will show up at the correct place in the graphical overview --> once it is finished that is!)
connect computers to outlets, the outlets to the swichtes,
desks have several outlets at their disposal, so u can connect computers to a desk/outlet, printers and printservers.
there are several other issues in it, but i cant name them all or i'll fill at least 3 pages here...

It is big...

cheers
Ricky

0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 18

Expert Comment

by:mdougan
Comment Utility
ameba,

I tried the code above but the declaration for the API SendMessageLong is missing.  I tried pasting SendMessage from the API text viewer, re-aliasing it to SendMessageLong.  I also set the lParam value to ByVal as this sometimes causes problems if it's passed ByRef, but still the call is appearantly failing.

What happens is that the tree keeps trying to redraw, and this makes the process incredibly slow.  The SendMessageLong returns a zero, so, it looks like it works...

I tried every combination I could think of for SendMessage and still no luck.  Finally, I found an alternative API for LockWindowUpdate.  This worked perfectly.


'Private Declare Function SendMessageLong Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'Private Const WM_SETREDRAW = &HB

Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwndLock As Long) As Long

Private Sub TreeRedraw(ByVal lHwnd As Long, ByVal bRedraw As Boolean)

'    SendMessageLong lHwnd, WM_SETREDRAW, bRedraw, 0
'    SendMessageLong lHwnd, WM_SETREDRAW, bRedraw, &O0
'    SendMessageLong lHwnd, WM_SETREDRAW, bRedraw, 0&
'    SendMessageLong lHwnd, WM_SETREDRAW, bRedraw, ByVal 0&
'    SendMessageLong lHwnd, WM_SETREDRAW, -CLng(bRedraw), 0&
'    SendMessageLong lHwnd, WM_SETREDRAW, Abs(CLng(bRedraw)), 0&

   
    If bRedraw Then
        LockWindowUpdate 0
    Else
        LockWindowUpdate lHwnd
    End If
End Sub
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
there is more,

'BoldTreeNode tvCodeItems.Nodes("ROOT")
is replaced by (b/c VB6)
tvCodeItems.Nodes("ROOT").Bold = True
       
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
i guess its time to close this one.

any suggestions?

cheers
Ricky
0
 
LVL 18

Expert Comment

by:mdougan
Comment Utility
Despite the slight omissions in the code, I think ameba's answer fits your needs.  It also taught me a new and valuable trick.  I've often gone to great lengths to try to order my rows in a hierarchical self-referencing table in order to add them to the tree in the proper order, and now I know that I can add them in any order and then re-parent them.  It's orders of magnitude faster than whatever I've done before.... so, it's a technique well worth the points.
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
have already given ameba the points for his solution on 03/07/2002.
http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=visualbasic&qid=20274655

cheers
Ricky
0
 
LVL 45

Expert Comment

by:aikimark
Comment Utility
Paurths,

What are you going to do with THIS question?

Please close this question if we've answered it.  If you have questions, please consult the Community Support TA and ask them what you should do.
0
 
LVL 18

Expert Comment

by:mdougan
Comment Utility
Paurths,

It's important to award the point to the expert inside of the question.  Because then the question gets saved to the Previously Asked Questions area and someone else will eventually "buy" the question and get the benefit of the excellent advice you've received here.  If you award the points in some other question without the technical stuff, then this question ends up deleted and then all of the good advice gets lost for others.......
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
0
 
LVL 45

Expert Comment

by:aikimark
Comment Utility
Did you leave someone out?
If not, you will probably need to lower your points from 200 to 150 to be evenly divisible into three 50-point slices.
0
 
LVL 1

Expert Comment

by:Computer101
Comment Utility
Points refunded and reduced to 50 for a point split.  Now you can accept an experts comment as an answer and make questions in this topic area for the other experts.

Computer101
E-E Moderator
0
 
LVL 12

Author Comment

by:Paurths
Comment Utility
0
 
LVL 15

Expert Comment

by:ameba
Comment Utility
Oh, sorry, I didn't participate in this thread.
- the function I suggested in another thread is not recursive, so I didn't want to jump in here.

The sample is somewhere on codeguru, but I don't have the exact link, and it works only for version 5 of the Common Controls.


mdougan,

> I tried the code above but the declaration for the API SendMessageLong is missing

You have the right version of SendMessageLong, but it is possible it doesn't work with version 6 of the TreeView.
LockWindowUpdate can work OK in most cases.  Or if there are not too many items, "tv.Visible = False" can work.

I don't use Treeview often, but for Listview, I got best results when sending WM_SETREDRAW message to PARENT FORM:

' from caList class
Public Property Let Redraw(ByVal Redraw As Boolean)
    Dim rc As RECT, ret As Long
   
    If Redraw Then
        Call SendMessage(ListView.Parent.hwnd, WM_SETREDRAW, REDRAWON, 0&)
        ' this is a bit less flicker
        ret = GetClientRect(ListView.hwnd, rc)
        ret = InvalidateRect(ListView.hwnd, rc, 0&)
    Else
        Call SendMessage(ListView.Parent.hwnd, WM_SETREDRAW, REDRAWOFF, 0&)
    End If
End Property
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now