I followed the solution posted in below link to execute a simple SAS Query through VBA:
Calling SAS through VBA
Dim obObjectFactory As New SASObjectManager.ObjectFactory
Dim obObjectKeeper As New SASObjectManager.ObjectKeeper
Dim obServer As New SASObjectManager.ServerDef
Dim obSAS As SAS.Workspace
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
obServer.MachineDNSName = "xxxx#company.com"
obServer.Protocol = ProtocolBridge
obServer.Port = 8561
obObjectFactory.LogEnabled = True
Set obSAS = obObjectFactory.CreateObjectByServer("sas", False, obServer, "", "")
obSAS.LanguageService.Submit "PROC SQL; CREATE TABLE ME.TABLE1; RUN;" 'Error at submit
But I'm getting error at the above submit line as "Object variable or With block variable not set"
You are trying to create an Asynchronous connection. I would try to create a syncronous connection instead (change second parameter to true).
Set obSAS = obObjectFactory.CreateObjectByServer("sas", True, obServer, "", "")
Synchronous indicates whether a connection is synchronous or
asynchronous. The synchronous connection is most frequently used and
is the simplest connection to create. If this parameter equals TRUE,
CreateObjectByServer does not return until a connection is made. If
this parameter equals FALSE, the function returns a null value
immediately. When a connection is made, the object is stored in the
ObjectKeeper.
From SAS documentation. Thus why your variable is Nothing right away.
http://support.sas.com/rnd/itech/doc9/dev_guide/dist-obj/winclnt/omcreate.html
Now for the Submit method, I suggest you add some error checking code like
If obSAS Is Nothing Then
MsgBox("Connection failed")
Else
obSAS.LanguageService.Submit "PROC SQL; CREATE TABLE ME.TABLE1; RUN;" 'Error at submit
End If
That above will answer your question of why you are getting the error Object variable or With block variable not set.
For the later Run Time Error '-2147213310 (80042002)' that is a different issue/question. And you should try to contact SAP tech support, with the information you provided there is nothing much we can do. The error must give you additional information in form of html tags. From the link you supplied, it seems this error is caused by a bad connection settings/parameters.
The workspaceservers default port is 8591. Perhaps the
workspaceserver also runs on a different machine. Connect to your
profile, go to the serverlist, locate the server you want to connect
to and right click the context menu "properties" to see the right
connection profile for your workspaceserver.
BTW: if you are using IWA (integrated windows authentication) you must
not provide a username and password (Nothing).
Set obSAS = obObjectFactory.CreateObjectByServer("sas", True, obServer, Nothing, Nothing)
Related
I did create a new form, where I have a table with 2 column's.
The last row of this table is the status.
I would like to do this: While my Notes Agent is running, it will go trough few action stepts. If one of the steps done, it should add the result of this action into a cell that I have definded.
Something like this:
----------------------------------------
| First action was done successfully. |
| Second action was done successfully. |
| Third action was done successfully. |
----------------------------------------
I tried the following code:
Sub Initialize
Dim sess As NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim item As NotesItem
Set db = sess.CurrentDatabase
Set doc = db.GetDocumentById("100B")
'do some code stuff.....
Set item = doc.AppendItemValue( "field_Status", "First action was done successfully." & Chr(13) )
Call doc.Save( False, True )
'do some code stuff.....
Set item = doc.AppendItemValue( "field_Status", "Second action was done successfully." )
Call doc.Save( False, True )
End Sub
Unfortunately I get always this message:
Object variable not set
Im not sure what is missing and if this is actually the right way how to realize my idea in code. I hope you have an idea / hint for me. Thank you.
First of all: NEVER write even one line of code without error handler.
That said: The easiest error handler would be
On Error Goto ErrorHandler
...your complete code goes here
EndOfRoutine:
Exit Sub
ErrorHandler:
Messagebox Err & "," & Error & " in line " & Erl
Resume EndOfRoutine
This would have given you this error line:
Set db = sess.CurrentDatabase
But wait: WHICH Object variable is not set?
Its "sess", as you only wrote:
Dim sess as NotesSession
Assigned, but not set... you need either:
Dim sess as New NotesSession
Or if you want to keep your line then just before the assignment of db:
Set sess = New NotesSession
Additional advice: finding a document via its NoteID is not a good Idea, and hardcoding it is even worse: the NoteId changes in different replicas. The same document will have a different NoteId in another replica of the database (e.g. A local replica or in a cluster). And if someone deletes that document and recreates it, then you need to update your code. Use a sorted view and GetDocumentByKey with a specific key you set in your document or a Profile document to store this information. Or at least use DocumentUniqueId, as this Is the same in every replica (though the recreation issue stays the same)
I am using a set of scripts that pull a lot of different data from iSeries via ODBC.
ActiveWorksheets.RefreshAll does not work as it doesn't leave enough time to run the background queries
I've tried the below,but to no avail
Dim qry As Connections
'Set qry =
For Each qry In ActiveWorksheets.Connections
qry.BackgroundQuery = False
qry.RefreshAll
DoEvents
Next qry
This gives me the expected Error 424 Object expected.
I don't expect to use Set qry = here, as I need to run through 30 different connections
Let's just call them connection1, connection2 etc for now, as their names are all over the place
Is the simplest option to stop the background query, refresh, activate background query - before the data import, or is there a better way?
I've looked all over SO - but can't find info on multiple ODBC connections
EDIT:
Dim qry As WorkbookConnection
For Each qry In ActiveWorkbook.Connections
qry.Refresh
DoEvents
Next qry
I believe your
Dim qry As Connections
should read
Dim qry As WorkbookConnection
The ActiveWorksheets.Connections.Item property returns an object of type WorkbookConnection. If you are trying to refresh the connections one at a time as it seems from your For Each statement, that object represents a single connection with methods like Refresh rather than the collection of all connections.
I managed to work this out. So all who may need this in the future can see:
Dim qry As WorkbookConnection
For Each qry In ActiveWorkbook.Connections
qry.ODBCConnection.BackgroundQuery = False
qry.Refresh
qry.ODBCConnection.BackgroundQuery = True
Next qry
Although it doesn't look like BackgroundQuery = True/False doesn't look like it's vital here. Turning it off means when you qry.Refresh, it pulls the data and refreshes it.
Also using For Each qry means that rather than writing out out 20 times, I can just look every connection and turn them off, refresh, and turn them back on
Preface
I'm making this question specific to conform to SO asking guidelines, but feel free to suggest wholesale redesign if you wish. I may be using some bad practices.
Basic Question
I use ADO to execute a multi-step SQL Server query that takes several minutes to execute. I use Raiserror in my tsql queries to let myself know more verbosely which steps have finished. Is it possible to pass these messages to VBA before the complete query finishes, while still continuing with the query?
Details and Code
I use the vba below to execute the t-SQL query underneath. As you can see, there are two errors raised in the t-SQL that display "Step 1 complete" and "Step 2 complete". Could I pass these messages (or alternately use error numbers and pass those) back to VBA in a way that would allow me to detect them and update a progress bar while continuing to execute the query?
VBA used to execute the query:
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandTimeout = 0
cmd.CommandText = strQuery
Set rst = New ADODB.Recordset
rst.Open cmd
'Go to the second to last recordset of the multi-step query
String1 = Replace(strQuery, ";", "")
For Loop2 = 1 To (Len(strQuery) - (Len(String1) + 1))
Set rst = rst.NextRecordset
Next Loop2
'Copy results
If Not rst.EOF Then
(snip - actions)
Else
MsgBox "Error: No records returned."
End If
Stripped-down piece of multi-step tSQL query:
--#DRS1: The numbers being researched
select distinct numbers
into #DRS1
from Table1 (nolock)
where numbers in ()
--#DRS1: Index
create nonclustered index Idx_DRS1
on #DRS1(numbers);
Raiserror(“Step 1 complete”,1,1) with nowait;
--#DRS2: Table2 for numbers being researched
select distinct
DRS1.numbers
,a.ID
into #DRS2
from #DRS1 DRS1
join Table2 (nolock) a
on DRS1.numbers = a.numbers
Raiserror(“Step 2 complete”,1,1) with nowait;
--MORE STEPS
(more steps)
(more raiserror statements)
Clarification
I am not interested in:
A method that doesn't allow me to update a progress bar until the query is completely done.
A method that uses Progress/MaxProgress, because as I understand it that would return separate numbers for each of the steps in my query, rather than one progress measure for the entire query.
I am less interested in:
Using # records affected messages to determine progress, because some steps may return equal numbers of records to previous steps.
Research
The closest thing I have found to what I'm looking for is here, but as the discussion of that solution here says:
This approach would only work for stored procedures that are not intended to return results, say procs that insert data into tables. Another approach would be needed if your stored proc returns a result set.
Since I return results in the final step of my query to be manipulated in Excel I don't think this would work for me.
External link code for reference
SQL:
CREATE PROCEDURE dbo.updTesting As
Declare #RetVal integer
Exec #RetVal = updTesting2
Return #RetVal
GO
CREATE PROCEDURE dbo.updTesting2 As
raiserror('Error From Testing 2 procedure',16,1)
Return -2
GO
VBA:
Private Sub Command1_Click()
On Error GoTo ErrorHandler
Dim db As ADODB.Connection
Dim cmd As ADODB.Command
Set db = New ADODB.Connection
db.CursorLocation = adUseClient
db.Open "provider=sqloledb;data source=handel;initial catalog=northwind;integrated security=sspi"
Set cmd = New ADODB.Command
With cmd
Set .ActiveConnection = db
.CommandText = "updTesting"
.CommandType = adCmdStoredProc
.Parameters.Append .CreateParameter("#RetVal", adInteger, adParamReturnValue)
.Execute , , adExecuteNoRecords
End With
ExitPoint:
On Error Resume Next
Set cmd.ActiveConnection = Nothing
Set cmd = Nothing
db.Close
Set db = Nothing
Exit Sub
ErrorHandler:
MsgBox "Error # " & Err.Number & vbNewLine & vbNewLine & Err.Description
Resume ExitPoint
End Sub
There are several possibilities to work out a solution for your problem:
(1) Capture the error messages as they occur while the query is running. That's the requested approach.
(2) Break-down the big, long query into several smaller chunks and run them one after the other. Like this you know which part is completed and you can update your progress bar based on that information just before sending the next chunk to the server.
(3) Update the big, long query to log its progress on the server in a temp table and then read out this log while the other query is still running.
While I'd recommend to use errors only when errors occur and not to "abuse" them for logging, tracking, or feedback, both options (1 & 2) are quite feasible with events:
Similar to Worksheet events Worksheet_Change, Worksheet_Activate, or Worksheet_BeforeDoubleClick there are also ADODB events for ADODB.Connection and ADODB.Recordset. Both are well documented and can be easily viewed within the VBE by (1) adding a reference to Microsoft ActiveX Data Objects x.x Library (2) pressing F2 (3) selecting the ADODB library in the drop-down menu at the top (4) and finally looking up Recordset or Connection within the classes. Here are the available events for Connection:
As you can see, all events are marked with a lightning. To capture / use these events you need to create a Class Module in the VBE and add the following line to it:
Dim WithEvents adoConnection As ADODB.Connection
Afterwards, you can make use of the newly created ADODB.Connection event and select the required event from the top of the list:
The applicable event for option (1) is the InfoMessage event which occurs "[...] whenever a warning occurs during a ConnectionEvent operation." The import part here is during a connection. So, this event fires automatically whenever an ADODB connection "gets" an error.
Of course, this means that the original query to the server must be sent without waiting for an answer. Instead you should use the above event to capture any errors while the query is executing and create yet another event to automatically fire when the entire query completed.
For some more help in respect to asynchronous ADODB connection and possible problems with them you might want to have a look at the following two posts here:
ExecuteComplete ADODB Connection event not fired with adAsyncExecute parameter
Running multiple async queries with ADODB - callbacks not always firing
A similar approach can be used with option (3) as described above and asynchronous ADODB connections.
Let me know if this solves your problems or if you have any further questions.
All available ADODB events can be reviewed here https://msdn.microsoft.com/en-us/library/ms675083%28v=vs.85%29.aspx
I have windows service that periodically checks the database every 10 seconds, retrieves the mails not yet sent and performs the task for pending mails.
The problem is that the memory increases step by step. Please help if any adjustment needed.
My code visual basic:
Private Sub TimerMail_Elapsed(sender As Object, e As Timers.ElapsedEventArgs) Handles TimerMail.Elapsed
Dim SqlConnection As New SqlConnection("Data Source=.;Initial Catalog=xxx;Integrated Security=True")
Dim cmd As New System.Data.SqlClient.SqlCommand
cmd.CommandType = System.Data.CommandType.Text
cmd.CommandText = "SELECT DISTINCT UserName, objet, contenu, email FROM message WHERE envoimail='false'"
SqlConnection.Open()
cmd.Connection = SqlConnection
Dim monReader As SqlDataReader = cmd.ExecuteReader()
While monReader.Read
Try
EnvoiMail(monReader("objet"), monReader("contenu"), monReader("email"), mailport, serveur, username, password, True)
Dim SqlConnection2 As New SqlConnection("Data Source=.;Initial Catalog=CGP;Integrated Security=True")
Dim cmd2 As New System.Data.SqlClient.SqlCommand
cmd2.CommandType = System.Data.CommandType.Text
cmd2.CommandText = "UPDATE destinataire SET envoimail='true' WHERE UserName='" & monReader("UserName") & "'"
SqlConnection2.Open()
cmd2.Connection = SqlConnection2
cmd2.ExecuteNonQuery()
Catch ex As Exception
logger.Error(ex.Message)
End Try
Threading.Thread.Sleep(60000)
End While
End Sub
What you have is not a resource leak, but rather delayed finalization of resources, due to non-deterministic nature of garbage collection in .Net. There are quite a few instances of SqlConnection objects created in your code -- in the reader loop you create a new connection for every row in your SELECT query results. You have to make sure you close SqlConnection. Every instance of SqlConnection should look like this:
Using connection As New SqlConnection(connectionString)
connection.Open()
' Do work here; connection closed on following line.
End Using
The Using statement will ensure connection is closed when execution goes outside of the Using block. See more details in MSDN.
Inside my solution I used COM3 port to connect the windows service to modem device and using GSMComm library.
after several tests, i constat that my problem is not located on sending mail function, but in senidng sms.
The service is stable and every think is going well, but after the service is running (COM3 port open by the service programme) and device unplagued suddenly, the service still running but the memory increased potentially from some Mo to more than Go.
comm = New GsmCommMain(3, 10000, 30000)
If comm.IsConnected Then
If comm.IsOpen Then
'------------
Else
Me.Stop()
End If
Else
Me.Stop()
End If
I am maintaining an application that was written in Visual Basic 6.0 and makes use of the several OLE controls with Excel.Sheet.8 class objects. Several users are getting the following error when they reach a point in code that attempts to manipulate the excel objects.
Run-time error '91': Object variable or With block variable not set
Below are examples of the code that trigger this error. I believe that the issue happens at:
Set oExcel = oleXl.object
Here are the points in the code where it happens:
Private Sub Form_Load()
Dim i As Integer
Dim j As Integer
Dim sTempStringA As String
Dim sTempStringB As String
'Set up excel sheet
centerform Me
Set oOutGrid = oleXlOutput.object
...
Private Sub Form_Load()
centerform Me
Set oOtherFx = oleXlFx.object
...
Private Sub Form_Load()
Dim iRet As Integer
Dim i As Integer
On Error GoTo Err_Handler
centerform Me
Call InitArray
Me.Caption = "TJUJ | Version " & version & " | Enter Custom Fx"
Set oBook = oleExcel.object
...
Is there a specific situation or environment in which this error would be generated from this line of code OR a way that I can ensure the object will always be accessible at this point in the code?
The error only happens occasionally, and I can't reproduce it on my developer machine at all. I also do not have access to the machines that it is happening on, but it seems to be encountered when there is an instance of the EXCEL.EXE process running.
When you get runtime-error 91, you can bet there's an uninitialized object somewhere in the statement. In other words, you are trying to use the properties or methods of a variable/object with a value of Nothing.
In your examples, oleXl, oleXlFx, and oleExcel are probably Nothing. So when you refer to their .object property, you trigger the RTE.
Somewhere in your code these variables have to be initialized to something. Look for statements like Set oleXl = CreateObject("Excel.Application") or Set oleXl = New Excel.Application
One suggestion; when you find the statements that actually initialize those OLE objects, check to see how the error-handling is coded. If you see things like this:
On Error Resume Next
Set oleXl = CreateObject(...
add a test to make sure the object was instantiated
On Error Resume Next
Set oleXl = CreateObject(...
If oleXl Is Nothing Then
MsgBox "Hey, my object is Nothing!"
End If
Microsoft suggests that we can fix error 91 by creating a new registry key. To create a new key follow the steps below.
Click on the Windows Start menu
Type Regedit in the search box
Press Enter
Locate the following entry in the registry. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Transaction Server
Now select the transaction server and right click on it
Select New and then choose Key
Name the key as Debug
Right click on the Debug key and choose New
Now select Key and name the key as RunWithoutContext
Ref: http://backspacetab.com/error-91/