Preventing Scheduled Agent from executing when modified - vba

I have a scheduled agent that runs Weekly at one particular time on a target of All new & modified documents.
If I modify this agent, even if I only save it, it runs again.
If I remember correctly from long long ago, I have to add code such as this:
Dim db As NotesDatabase
Dim agent As NotesAgent
Set db = s.CurrentDatabase
Set agent = db.GetAgent("myAgent")
If agent.HasRunSinceModified = False
Exit Sub
End If
Am I remembering correctly? And I always wondered, why would an agent fire off after being modified? Makes no sense to me.

My response corresponds to your title: Preventing Scheduled Agent from executing when modified.
The solution is to move all your code to a script library, and never change the agent (since no need of it).
When you modify your code in the script library the agent is not fired.
You can also read Notes Designer runs agent after saving which suggest (I didn't test) Amgr_SkipPriorDailyScheduledRuns=1

Related

Releasing an .MDF File in VB.NET

I have an application that checks to see if it's the most recent version. If not, it updates itself by using File.Copy to replace the DB attached to the application with a fresh one (that may or may not have had changes made to it). In an attempt to keep the data from being deleted, I created a backup system that writes all the data to an XML file before the database is deleted and restores the data once the database has been copied.
I am having a problem with the File.Copy method, however, in that an error pops up telling me the .MDF is being used by another process.
I was told that stopping SQL Server would work, but it hasn't. I've also been told I can use SMO, but also have not been able to make that work. With this seeming so close to complete, SMO also seems like it won't be necessary.
My code is this:
'This is the backup. I make sure to close the SQL Connection when the process is complete.
Dim db As String = "C:\ACE DB\localACETest.mdf"
Dim dbLog As String = "C:\ACE DB\localACETest_log.ldf"
If File.Exists(db) = True Then
'Backup process
'...
End If
'"Data/localACETest.mdf" referenced below is the file located inside of my application that is used to overwrite the other MDF; it is NOT the .MDF I'm looking to replace.
Directory.CreateDirectory("C:\Random Directory\")
File.Copy("Data/localACETest.mdf", db, True) 'This is the line where I get the error
File.Copy("Data/localACETest_log.ldf", dbLog, True)
success = False
...
EDITS:
I have narrowed the issue down to the method that backs up my data. I'm using the following connection string:
Private Const _sqlDB As String = "Data Source=(localdb)\v11.0;Initial Catalog=localACETest;Integrated Security=True; _
AttachDbFileName=C:\ACE DB\localACETest.mdf"
I open SQL, run a command, and then close it:
Using connection = New SqlConnection(_sqlDB)
connection.Open()
...
connection.close()
Why does this not release the MDF from the process? (When I don't run it, I have no problems)
You are better off sending a command to SQL server telling it to make a backup for you. This SO article has a great (command line) script that you can copy/paste:
SQL Server command line backup statement
Put that into a batch and launch it like this.
System.Diagnostics.Process.Start("C:\Ace Db\MakeADBBackup.bat")
If you would prefer to make your program wait till the backup finishes, read about launching processes: http://support.microsoft.com/kb/305368
If you are REALLY insistent on making a copy of the .mdf (which is not a good idea), then you need to ask the server to stop the SQL service before you make a copy. You could run a batch that says
NET STOP MSSQLSERVER
Assuming that your SQL Server is running under the name "MSSQLSERVER". To check the names of running services, open a command prompt and type-in "NET START". It will give a list of services that are running. One of them will be the "process name" of your SQL Server's running service.
Better still, here is an article (for VB.NET) that shows the source code for starting/stopping SQL Server. http://msdn.microsoft.com/en-us/library/ms162139(v=SQL.90).aspx
I strongly recommend that you try the first approach that I suggested.

SSIS Excel RefreshAll() task SQL job fails when no one logged in

A few months ago, I made a SSIS package that is used to refresh a couple excel worksheets (+few other things)
Now, my college that is still on the project reports this weird behavior.
The SSIS package is scheduled as SQL Agent Job.
It runs hourly from 8am00. At 8am it always fails, his conclusion: at 8am is no one logged on the server.
The second time, at 9am, the job runs OK. (RefreshAll worked) His conclusion: there is always someone logged on the the server via RDP at that moment.
(In fact I don't know about the other runs later on the day)
The task is a VB Script task that calls the Excel Interop dlls. I remember having difficulties to get it working until I installed Excel 2010 x86 on the server. -> Excel is fully and legitimately installed on the server.
My guess and determination at that moment was that it sometimes went wrong somewhere and Excel did not close properly. When I opened taskmgr I found +10 instances of Excel.exe running... This was during development.
My college did an interesting test: scheduled the job every minute and logged on and off a few times to the server. Every time no one was logged on to the server (RDP) the job failed. When logged on, the job ran OK !
Below the code that is used in the 'RefreshAll' script task.
I also used threading.sleep because otherwise I got timeout errors. Found no other way.
Thanks in advance!!
L
Public Sub Main()
Dts.TaskResult = ScriptResults.Success
Dim oApp As New Microsoft.Office.Interop.Excel.Application
oApp.Visible = False
'oApp.UserControl = True
Dim oldCI As System.Globalization.CultureInfo = _
System.Threading.Thread.CurrentThread.CurrentCulture
System.Threading.Thread.CurrentThread.CurrentCulture = _
New System.Globalization.CultureInfo("en-US")
Dim wb As Microsoft.Office.Interop.Excel.Workbook
wb = oApp.Workbooks.Open(Dts.Variables("User::FileNameHandleFull1").Value.ToString)
oApp.DisplayAlerts = False
wb.RefreshAll()
Threading.Thread.Sleep(10000)
wb.Save()
wb.Close()
oApp.DisplayAlerts = True
oApp.Quit()
Runtime.InteropServices.Marshal.ReleaseComObject(oApp)
End Sub
End Class
Excel is a client application and normally it does require to have active user session on a machine it runs on. For a job like this, I would consider other approaches not involving working with excel process, eiter:
store the result in a sql server table, then use linked table from excel sheet to pull the data.
use export as .csv (comma separated values)
use 3rd party controls that write Excel format
they may fix it in next version of Excel?

How to find 64-bit process info using a 32-bit process

I have a 32 bit application that shells a second application that can be 32 or 64-bit depending upon the computer it's running on.
I only want one instance of the second application to run at a time, and I need the first application to prevent the second from being launched more than once.
I want to be able to use GetProcessesByName to obtain the running processes. This seems to work fine. It's when I attempt to obtain the module data to find out what folder the second application was run from that things fall apart.
Does anyone have a suggestion for identifying 64-bit processes and their folder of origin from a 32-bit application?
Thank you,
SH
You can use the WMI API (System.Management namespace) for this, specifically the ManagementObjectSearcher. The example below shows to get the process id and full command line from all running notepad instances.
Imports System.Management
Module Module1
Sub Main()
Dim wmi = New ManagementObjectSearcher("SELECT ProcessId, CommandLine FROM Win32_Process WHERE CommandLine LIKE ""%notepad%""")
Dim result = wmi.Get().OfType(Of ManagementObject)()
For Each r In result
Console.WriteLine("Process ID: {0}, Command Line: {1}" r("ProcessId"), r("CommandLine"))
Next
End Sub
End Module
I think it could be easier if you set a Mutex when launching second app.
In main app you could do this: if Mutex doesn't exist you run second app (which creates Mutex when run and release it when closing), otherwise you skip...
EDITED:
You can't edit second app to insert the creation of a mutex, ok.
But you can do this in main app:
Create a background worker BackgroudWorker wrk
Set a private bool to true: bool running = false
Execute wrk when you want the new app run: if (running) return; running = true;
wrk creates a Process and waits for its end
when wrk ends running = false
Just an idea...
EDITED AGAIN:
If you close first app and reopen it, user is able to run second app again.
So you could do this:
Create a background worker BackgroudWorker wrk
Write a tmp file (on NTFS it can be empty)
Execute wrk when you want the new app run:
if your tmp file exists then exit;
wrk creates a Process and waits for its end
when wrk ends deletes tmp file
With this method, even if user quits your first app, tmp file remains on hdd; so when user runs first app again, second app will not be executed.
Remeber that if user is smart enough to undestand this, he could manully delete file and the trick is done.
Finally: are you sure user cannot run directly second app?

Multiple instances of same access database are open on 1 machine - problem

I'm having issues with a ms access 2007 accdb, using Windows Server 2008 task scheduler for scheduled tasks. The problem is the file that's being opened by the task scheduler is opening/closing properly, but the 'lock' file (.laccdb) remains visible after the database is closed, which is an indicator that the access db thinks it's still open. Each time a new task runs, a new instance of access is being opened. I opened the Schema to show roster of all users in the database and it's showing 3 duplicates of the server name/Admin account. Below is an example of the immediate window in access:
COMPUTER_NAME LOGIN_NAME CONNECTED SUSPECT_STATE
SERVER Admin True Null
SERVER Admin True Null
SERVER Admin True Null
I'm hoping someone else has had this problem and knows 1) How to easily close all the open instances of access and 2) how to prevent this from occuring when running a task. I have "Do not start a new instance" set under the task's 'settings' tab, but this is irrelevant b/c none of the tasks were running simultaneously. Thanks in advance for any assistance.
To close all open Access instances (you can't run this from Access because you can't guarantee that the running instance will be the last reference you retrieve):
Sub CloseAllAccessInstances()
Dim acc As Access.Application
Do
Set acc = GetObject(, "Access.Application")
If IsNull(acc) Then Exit Do
acc.Quit
Loop
End Sub
After you run the above, check the task manager. If you see msaccess.exe, then you most likely have a circular object reference. This will prevent Access from closing. For more information, have a look at http://msdn.microsoft.com/en-us/library/aa716190(VS.60).aspx.

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.