How do I connect to a Lotus Notes DB through VBA? - vba

I'm trying to connect to a Lotus Notes database via VBA in Microsoft Access 2003. The code I have is as follows:
Set nSession = CreateObject("Notes.NotesSession")
Set nDatabase = nSession.GetDatabase("CN=MT_N01/O=Org Name", "LossPrevention\BrchPrVI.nsf", False)
I've tried variations for the server name, but nothing seems to work. In Lotus Notes it appears as "Server: MT_N01/Org Name". I've tried just "MT_N01" and "MT_N01/Org Name", but the NotesDatabase variable keeps ending up empty.
Any tips?

I might be wrong here, but I think you should call the Initialize() method of the session prior to using it.
Take a look at the samples here: http://www.ibm.com/developerworks/lotus/library/domino-msnet/index.html

I think that behaviour is normal; VBA knows nDatabase is a variant/object, but does not know anything about its contents. At least that is what I get when I try your code in Excel 2003.
Try to return something from the database object, for example nDatabase.ReplicaID should return the database identity string. If the databas is not properly loaded, you will get an error.
Many good links are posted in response to the ".NET and Lotus Notes Interop." question.

Unless you also need to us the NotesUIWorkspace class and its child classes to manipulate the Notes client user interface, you should be using the "Lotus.NotesSession" class instead of the "Notes.NotesSession" class. And as per the answer from #Sagultay, you should be calling nSession.Intialize().

Related

Read fields in Lotus Notes Documents Through VBA

I am trying to write VBA code that will read data from fields in a Lotus Notes document. Currently, I am able to read data using the FieldGetText method, however this only works when I have the document open. I need to be able to loop through documents without opening them, as there are several hundred. I need to be able to read these same fields from many documents, but cannot figure out how to loop through them. My code currently is:
Set LotusNotes = CreateObject("Notes.NotesUiWorkspace")
Set CurrentDoc = LotusNotes.CurrentDocument
While Not (CurrentDoc Is Nothing)
' Affectation of data
DueDate = CurrentDoc.FieldGetText("RevDueDate")
DueTime = CurrentDoc.FieldGetText("RevDueTime")
DateClosed = CurrentDoc.FieldGetText("DateClosed")
Wend
I understand that this uses a Front End object. I was able to use a Back End object that could loop through documents (without them being open), however the data (for the dates, specifically) did not match the field text from the documents. That code looked like this:
Set LotusNotes = CreateObject("Notes.NotesSession")
Set db = LotusNotes.GetDatabase("")
Set view = db.GetView(view_name)
view.AutoUpdate = False
Set columnview = view.AllEntries
Set doc = view.GetFirstDocument
While Not (doc Is Nothing)
revDate = doc.GetItemValueDateTimeArray("RevDueDate")
revDate = doc.RevDueDate
Set doc = view.GetNextDocument(doc)
Wend
Basically, I'm just wondering if it's possible to loop through multiple files using the NotesUIWorkspace class that I tried first, or if it's possible to somehow use FieldGetText in the NotesWorkspace class instead.
Any help is appreciated, thanks.
You're using the Notes "front-end" classes rooted at Notes.NotesUIWorkspace. These are OLE classes, which means that they need the Notes client to be running and they work on the open document. There are also back-end classes rooted at Notes.NotesSession. These are also OLE classes, so they still need the Notes client to be running but they can access other documents (and other databases, servers, etc.). There is also a set of back-end classes rooted at Lotus.NotesSession. Note the different prefix. These are COM classes, so they do not need the Notes client to be running - though it does have to be installed and configured, and your code will have to provide the user's password since the client won't prompt for it.
You can find documentation and examples for the NotesSession class here. Down near the bottom of the page, you'll find links to information about using them via OLE or COM. You can find a bunch of examples based on using the COM classes here, including one that traverses the documents in a view in database. Apart from the inital setup of the session, it would be the same if you use OLE.
It is possible, and also better to use the 'Back end' object Notes.NotesSession. So try this:
Set doc = view.GetFirstDocument
While Not (doc Is Nothing)
'Check if you have the field in the document
if doc.HasItem("RevDueDate") Then
revDate = doc.getFirstItem("RevDueDate").Text
End If
Set doc = view.GetNextDocument(doc)
Wend
It is also possible to use Notes.NotesUiWorkspaceobject by opening every document in the client, getting the fields data and closing the document but I would highly recommend NOT TO make it like this as there is high possibility that you will crash the Notes client, if you need to loop on more documents.

What type of object is returned by GetObject("SAPGUI")?

TL;DR ---------------
If I properly declare the variables in the initialisation script, I can't attach to the "connection" objects of a SAPFEWSELib.GuiApplication .
The collection MyApplication.Children(0), is empty but if I comment out the declaration block, it just works !?
TL;DR ---------------
I am trying to create a more reliable connection between my SAP client and my excel application.
My current issue is with the establishing of the connection. The SAP client provides a sample vbscript when using its script recording function.
If Not IsObject(MyApplication) Then
Debug.Print "yep"
Set SapGuiAuto = GetObject("SAPGUI")
Set MyApplication = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = MyApplication.Children(0)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
This other question on stackoverflow came close to answer, but fell short
stackoverflow.com/questions/24738998/vba-using-variables-that-were-not-declared
The original code is here, I have modified slightly so it would work in excel/vba.
(I dropped the IsObject(Wscript) and I had to replace Application with MyApplication)
First thing I want to do is explicitly declare all variables.
Using code I got at the following address
stackoverflow.com/questions/19783180/get-list-of-all-properties-for-an-object
I used the "TypeLib Information" and the function TypeName() to determine each object type. I tried declaring as follows
Dim session as GuiSession
Dim MyApplication as GuiApplication
Dim Connection as ISapConnectionTarget
Dim SapGuiAuto as object
I'm getting the User-defined type not defined error.
After a bit of searching, I found the partial answer at this address.
scn.sap.com/thread/3254335
I feel manual adding the "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\sapfewse.ocx" reference will break easily. If there's a better way to do this please let me know.
Ok now I can declare like this and it works.
Dim MyApplication As SAPFEWSELib.GuiApplication
Dim Connection As SAPFEWSELib.GuiConnection
Dim session As SAPFEWSELib.GuiSession
Dim SapGuiAuto As Object
I don't like the SapGuiAuto As Object as it doesn't really say what it is and I can't use CTRL+SPACE to view available properties and functions of this object (one of the VB features I can't live without now !)
All I know about this object is that it has a .GetScriptingEngine function (method ?).
While doing the research to write this question I came across this thread on the sap.com forums.
scn.sap.com/thread/3448120
Here it is mentioned that "GetScriptingEngine is a method of the class GuiApplication".
So I tried the following declarations and it seems to work.
Dim MyApplication As SAPFEWSELib.GuiApplication
Dim Connection As SAPFEWSELib.GuiConnection
Dim session As SAPFEWSELib.GuiSession
Dim SapGuiAuto As SAPFEWSELib.GuiApplication
Now if I type "session." the list of possible properties appear.
But there is a problem !
If I type the following line
Debug.Print session.FindById("wnd[0]").Text
It gives an error (while it used to work just fine !).
The error is "Object variable or With bock variable not set".
If I comment out the variable declarations, it works just fine !
Using the TLI function while session is undeclared I get the following members
DumpProperties session.FindById("wnd[0]")
output here -> pastebin.mozilla.org/8882551
but if I run the same command with session properly declared I get.. the same error
So after a bit more research, it turns out that the beginning of the script doesn't work the same now.
If Not IsObject(MyApplication) Then
Will not execute if MyApplication has been declared with Dim MyApplication As SAPFEWSELib.GuiApplication
So I tried executing the commands without the IFs.
Set MyApplication = SapGuiAuto.GetScriptingEngine
Set Connection = MyApplication.Children(0)
Set session = Connection.Children(0)
This fails with the "Object variable or With bock variable not set" error on Set MyApplication = SapGuiAuto.GetScriptingEngine
The solution to this issue was to create a new instance of SapGuiAuto like this.
Set SapGuiAuto = New SAPFEWSELib.GuiApplication
Now the above code executes, until it fails at Set Connection = MyApplication.Children(0)
The error : "The enumerator of the collection cannot find en element with the specified index"
A quick test with the following line reveals, the .Children collection is empty.
For Each chld In MyApplication.Children: Debug.Print "one exists": Next
This is the same error I would normally get if I am currently disconnected from SAP, but I am connected and commenting out the declaration block, fixes the issue.
This answer on stackoverflow is ominous
stackoverflow.com/questions/36751819/sap-gui-scripting-error-the-enumerator-of-the-collection-cannot-find-an-elemen
I'm not an administrator, it's 10 PM on a Friday and asking IT anything is a nightmare. Hopefully I don't have to resort to that.
I will try on another computer.
Just tried, I get the same thing. At this point I have to throw in the towel, I can't get this to work without some help or at least a good night's rest !
Thanks for any advice or comments
Some extra links I found very useful for the people on the same path as I am.
SAP GUI Scripting API PDF
Using the VBA debugger to discover SAP GUI properties and functions
scn.sap.com/docs/DOC-39696
SAP GUI Scripting API Documentation (I couldn't open this file but it's full of good stuff)
www.sdn.sap.com/irj/scn/go/portal/prtroot/docs/library/uuid/a034a16b-3bfe-2a10-e2bb-8bd880db0b3c
SAP GUI Scripting API : How to Automate User Interaction (unfortunately my system lacks the "Script development tools")
scn.sap.com/docs/DOC-4614
Also the BIBS function might be helpful to you, however it was not working on my system
scn.sap.com/docs/DOC-4612
When I use this I also get 0 children as if not connected to SAP:
Set sapCon = New SAPFEWSELib.GuiApplication
By using this instead it's actually working:
Set sapCon = GetObject("SAPGUI").GetScriptingEngine
As per this: https://answers.sap.com/questions/12487790/what-are-the-differences-in-vba-methods-to-connect.html?childToView=12494892
I just came accross this issue myself, and found a solution for the "enumerator" error. Also posted it in the referenced stackoverflow post you mentioned.
Change this:
Set Connection = Sap_Application.Children(0)
Into this:
Set Connection = Sap_Application.Children(1)
As I explained there, not sure why this happens, or what it means, I just messed with the numbers and it worked.
Hope it's not too late, or maybe it will help someone else.
Regards

How to get user-Information from domino-server via vba

I writing a macro for ms word, that starts when the document is loaded and fills a few fields with user information (tel,email etc.). I want this information to come form our domino-servers, as they are our primary database.
I have tried using notes objects in vba to establish a session on the server, but that requires that user to keep their notes-client open(as far as I know), so thats not an option.
Currently I am trying to get the information via ldap request(the domino-server runs the ldap-service), however I cant find information on how the code and search string has to look like.
The last site I tried was this one (http://www.selfadsi.org/bind.htm), using the "Bind using special credentials" variant.
But I am getting a protocol error.(the string proably needs to be adjusted for connecting to domino, I tried "LDAP://[Server-FQN]/dc=DE" hoping it would show me all users registered as C=DE, but it did not work.)
I have also searched through IBMs Support Site and Knowledge-Center, but could not find the info I need.
If anyone could provide me an example on how to connect to the domino ldap and pull the information for a user, I would be very grateful.
There are two different sets of Notes objects available to you in VBA. There are OLE objects, which you access this way:
Set Session = CreateObject("Notes.NotesSession")
And there are COM objects, which you access this way:
Set Session = CreateObject("Lotus.NotesSession")
The key differences between them are that OLE objects require that the Notes client must be running and they also include the "front-end" classes like Notes.NotesUIWorkspace that can actually drive the Notes client, while the COM objects do not require that the Notes client is running (though either it, or the Domino server, must be installed) and it does not provide the front-end classes.
If you want to stick with the LDAP approach, the first thing you should probably do is download an LDAP client. I like the SoftTerra LDAP browser, but I've also heard that a lot of people like the Apache Directory Studio. Browsing the tree is really the best way to figure out what queries will get you the info you need.
s mentioned in the commment on Richards answer, I also tried finding the LDAP-String using a LDAP-Browser. Doing that and some testing with ADODB Objects I was able to come up with the following code:
Set objConnection = CreateObject("ADODB.Connection")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"
Set objCommand = CreateObject("ADODB.Command")
Set objCommand.ActiveConnection = objConnection
objCommand.CommandText = "SELECT UID, mail FROM 'LDAP://[Server-FQN]:389 'WHERE ObjectClass='dominoPerson'"
Set objRecordSet = objCommand.Execute
While Not objRecordSet.EOF
varMail = objRecordSet.Fields("mail").Value
Debug.Print varMail(0)
objRecordSet.MoveNext
Wend
Which extracts the email-adress of all our users using anonymous access and prints the result into the debug window.
Now all I have to do is to adjust the WHERE-Statement to get the data I want per user. :-)

How can I connect to Lotus thru ODBC using VBA?

I'm interested in setting up an Access db to run a report automatically. To save myself the trouble of going to each client computer and setting up the appropriate DSNs, I'd like to set up the ODBC connections in the VB script itself if possible.
I've googled and checked this site and found some good starter code, but not enough to make all the error messages go away. Can someone complete the code below?
Sub SetupODBC(Str_Server as string, Str_Db as string)
'Str_Server=Name of Server
'Str_db=Name of Database
Dim C as ADODB.Connection
Set C = new ADODB.Connection
C.ConnectionString = ??
C.Open
Debug.print C.State
Exit Sub
Welcome to the board. ConnectionStrings is indeed your friend, but the issue you are having is that you don't have the driver:) Lotus Notes is not a relational database it is a document oriented database. Historically there has not been a way to Access it like it is a relational database for that reason. However IBM eventually got around to writing a sort of translator in the form of NotesSQL. If you follow the link and get the driver you should be able to use ODBC. It is worth noting that Notes exposes itself to COM. So if push comes to shove you can automate the client.
This site is your friend: http://www.connectionstrings.com/access
I didn't follow your question correctly at first. I see you want to create a link from Access to Lotus to report on Lotus Notes data. Well there are a few ways to do so.
I frequently use a method of exposing Lotus Notes data as XML, then accessing that XML from the remote system. You can easily create a Notes Page with the XML start tag, root element, and then insert an embedded view in between the root element. That embedded view then needs to display as HTML and contain columns that resolve to xml tags. For instance, each row of the view would look similar to this:
<Person><FirstName>Ken</FirstName><LastName>Pespisa</LastName></Person>
and your column formulas would be:
"<Person><FirstName>" + FirstName + "</FirstName>"
for the first name column, and for the last name column it would be this:
"<LastName> + LastName + </LastName></Person>"
Note that this assumes that your Notes server has the HTTP service turned on and you can reach the database via a browser.
However as mentioned by other answers, you can use other methods such as NotesSQL and COM. It sounds like you are putting this solution on many workstations, though, and NotesSQL would require you to install the driver on each workstation. The COM method would work without requiring any extra work at the users' desks so I'd favor that solution in this case.
Looks like a great site for my needs, even if it hasn't been updated in a year. But still no cigar. Now, I'm getting "Data source name not found and default driver not specified"
(Obviously, ServerNameGoesHere and DatabaseNameGoesHere are subsitutions)
Sub dbX()
Dim C As adodb.Connection
Set C = New adodb.Connection
C.Open _
"Driver={Lotus NotesSQL 3.01 (32-bit) ODBC DRIVER (*.nsf)};" & _
" Server=ServerNameGoesHere;" & _
" Database=DatabaseNameGoesHere.nsf;"
C.Close
End Sub

Intermittent error when attempting to control another database

I have the following code:
Dim obj As New Access.Application
obj.OpenCurrentDatabase (CurrentProject.Path & "\Working.mdb")
obj.Run "Routine"
obj.CloseCurrentDatabase
Set obj = Nothing
The problem I'm experimenting is a pop-up that tells me Access can't set the focus on the other database. As you can see from the code, I want to run a Subroutine in another mdb. Any other way to achieve this will be appreciated.
I'm working with MS Access 2003.
This is an intermittent error. As this is production code that will be run only once a month, it's extremely difficult to reproduce, and I can't give you the exact text and number at this time. It is the second month this happened.
I suspect this may occur when someone is working with this or the other database.
The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database.
Maybe, it's because of the first line in the 'Routines' code:
If vbNo = MsgBox("Do you want to update?", vbYesNo, "Update") Then
Exit Function
End If
I'll make another subroutine without the MsgBox.
I've been able to reproduce this behaviour. It happens when the focus has to shift to the called database, but the user sets the focus ([ALT]+[TAB]) on the first database. The 'solution' was to educate the user.
This is an intermittent error. As this is production code that will be run only once a month, it's extremely difficult to reproduce, and I can't give you the exact text and number at this time. It is the second month this happened.
I suspect this may occur when someone is working with this or the other database.
The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database.
Maybe, it's because of the first line in the 'Routines' code:
If vbNo = MsgBox("Do you want to update?", vbYesNo, "Update") Then
Exit Function
End If
I'll make another subroutine without the MsgBox.
I've tried this in our development database and it works. This doesn't mean anything as the other code also workes fine in development.
I guess this error message is linked to the state of one of your databases. You are using here Jet connections and Access objects, and you might not be able, for multiple reasons (multi-user environment, unability to delete LDB Lock file, etc), to properly close your active database and open another one. So, according to me, the solution is to forget the Jet engine and to use another connexion to update the data in the "other" database.
When you say "The dataflow is to update all 'projects' once a month in one database and then make this information available in the other database", I assume that the role of your "Routine" is to update some data, either via SQL instructions or equivalent recordset updates.
Why don't you try to make the corresponding updates by opening a connexion to your other database and (1) send the corresponding SQL instructions or (2) opening recordset and making requested updates?
One idea would be for example:
Dim cn as ADODB.connexion,
qr as string,
rs as ADODB.recordset
'qr can be "Update Table_Blablabla Set ... Where ...
'rs can be "SELECT * From Table_Blablabla INNER JOIN Table_Blobloblo
set cn = New ADODB.connexion
cn.open
You can here send any SQL instruction (with command object and execute method)
or open and update any recordset linked to your other database, then
cn.close
This can also be done via an ODBC connexion (and DAO.recordsets), so you can choose your favorite objects.
If you would like another means of running the function, try the following:
Dim obj As New Access.Application
obj.OpenCurrentDatabase (CurrentProject.Path & "\Working.mdb")
obj.DoCmd.RunMacro "MyMacro"
obj.CloseCurrentDatabase
Set obj = Nothing
Where 'MyMacro' has an action of 'RunCode' with the Function name you would prefer to execute in Working.mdb
I've been able to reproduce the error in 'development'.
"This action cannot be completed because the other application is busy. Choose 'Switch To' to activate ...."
I really can't see the rest of the message, as it is blinking very fast. I guess this error is due to 'switching' between the two databases. I hope that, by educating the user, this will stop.
Philippe, your answer is, of course, correct. I'd have chosen that path if I hadn't developed the 'routine' beforehand.
"I've been able to reproduce this behaviour. It happens when the focus has to shift to the called database, but the user sets the focus ([ALT]+[TAB]) on the first database. The 'solution' was to educate the user." As it is impossible to prevent the user to switch application in Windows, I'd like to close the subject.