lotusscript agent calling another lotusscript agent not working - lotus-domino

1.) On a web form, I have a Notes button (not an HTML input or button tag).....it calls a Lotusscript agent using #Command([RunAgent];"agentname") command ....that works fine
2.) Last line of this calls another Lotusscript agent using "runonserver"
3.) This second agent tries to use "DocumentContext" to identify the current document, but it does not seem to be able to do this, an error I logged indicates this to be the case.
So the question I have is...how could I have a first agent run, and successfully use "DocumentContext" and then call a second agent, and then have THAT agent identify the SAME document as the first one used? This second agent has its own:
Dim s as new notessession
Dim db as notesdatabase
Dim thisdoc as notesdocument
set db = s.currentdatabase
...and then it attempts to set thisdoc with :
set thisdoc = s.DocumentContext
The second agent is used elsewhere as the primary agent (not getting called in a daisy-chain situation) and it all works fine.
Maybe there is a simple solution that I am just not thinking of at the moment. I know I can put two #Command([RunAgent]... commands behind the button, but that has its own challenges, so I am wondering if someone as some slick/clever idea of what I can do.

DocumentContext is a memory construct passed to the agent, so there is no such thing in the database.documentcontext. What you'll have to do is save the DocumentContext as a document and then pass the NoteID (not the UNID) to the second agent. See if this works for you.
https://www.ibm.com/developerworks/lotus/library/ls-Run_and_RunOnServer/index.html

Since you're trying to use the same agent from both a button and a RunOnServer call, and that can't work (as per #Duston's answer), your best bet is probably to move the bulk of that agent code into a sub or function in a script library, and then have two agents. One agent gets the document context as you do now, and passes it into the script library code. The other uses agent.paramaterID and getDocumentById and passes that into the script library code.

Related

Change RZ11 Profile parameters programmatically

I was asked by the IT Department to write an ABAP program that switches the profile parameter login/server_logon_restriction from 0 to 1 and back automatically triggered (time etc) on all of our SAP servers.
I am not very familiar in the SAP environment yet and until now I managed to get the wanted parameter by using:
RSAN_SYSTEM_PARAMETERS_GET
and
RSAN_SYSTEM_PARAMETERS_READ
But I cannot find anything to change and save them dynamically. Is this even possible?
Cheers, Nils
login/server_logon_restriction parameter dynamic so you can change it via cl_spfl_profile_parameter=>change_value class method.
You can configure background job for automatically trigger it in t-code SM36.
The method don't save the given value to profile file, so the parameter turn back profile value after system restart.
Current logged-in users can continue to use system. May be you can want to inform them with TH_POPUP function then kick from the system.

ZAP: Execute Script

I try to execute the community script "Extender/HTTP Message Logger.js". I first double click on the script to make it open in the scripting console. However, in the scripting console, the "Execute" button is disabled and I see no other way how to make it run.
What am I missing?
I think you're missing the message beneath the script which says:
Extender scripts add new functionality, including graphical elements
and new API end points.
Enabling a script installs it and disabling a script uninstalls it.
So you just need to enable the script (by right clicking it and selecting 'Enable') and then it will start working.
The actual issue was that I didn't read the script's code carefully: be default the script only logs JSON messages as defined on lines 17 and 43 and following. In order to log all the sent and received HTTP messages, I simply changed the isMessageToLog(log) function to always return true. After redeploying the script (disabling and enabling) it would log all HTTP messages.

Full shell (explorer.exe) running for a RemoteApp on Terminal server

Folks,
I'll been fighting this for a few weeks now. We have a proprietary corporate app running on thin clients in our organization. From this app we can apply VBA scripting behind the scenes to do simple functions. In the past adding buttons to open IE and direct them to certain web sites to enter data, open Calc and etc.
Recently I have been working the code below. It was developed on the Server using a RDP session which launches the full desktop and explorer.exe. What I have noticed that if explorer.exe isn't running then the code bombs at line in the function that reads "For Each oWin In oShApp.Windows " with "Run-time error '429'".
However if I script to start explorer.exe (which is bad because it enables the Start-bar and Task-bar) on the ThinClient which launches the desktop and full capabilities and it runs just fine as the Thin Client users that are logged in.
I have read a little bit about the "Limited Shell" that runs when using a remoteapp and not the full desktop and was wondering if there was anyway around it, without enable the start-menu and taskbar?
See the code below.
Thanks for the help, CreteIT
Private Sub cmdHomePage_Click()
Dim ie As Object
Dim sMatch As String
sMatch = "http://www.companyweb.com"
On Error Resume Next
Set ie = GetIEatURL(sMatch & "*")
On Error GoTo 0
If Not ie Is Nothing Then
ShowWindow ie.hwnd, 9
BringWindowToTop ie.hwnd
Else
Dim strHome
Dim strAPP
strHome = "c:\progra~1\intern~1\iexplore.exe www.companyweb.com"
strAPP = Shell(strHome, vbNormalFocus)
End If
End Sub
Function GetIEatURL(sMatch As String) As Object
Dim ie As Object, oShApp As Object, oWin As Object
Set oShApp = CreateObject("Shell.Application")
For Each oWin In oShApp.Windows
If TypeName(oWin.Document) = "HTMLDocument" Then
Set ie = oWin
If LCase(ie.LocationURL) Like LCase(sMatch) Then
Set GetIEatURL = ie
Exit For
End If
End If
Next
Set oShApp = Nothing
Set oWin = Nothing
End Function
I work on the RemoteApp team at Microsoft. I'm not quite clear whether you're running this script from an actual RemoteApp session or your own setup that has a different shell that replaces explorer.exe (or perhaps no shell at all), but either way the answer is about the same.
The Shell.Application ActiveX object your script is trying to instantiate appears to be implemented by the shell - typically explorer.exe. If that isn't running, the COM runtime won't be able to create an instance of the object, and when you try to activate it you'll get an error.
The obvious solution is to run explorer.exe but, as you observed, that also includes the taskbar and start menu, which you might not want. RemoteApp runs its own shell replacement (rdpshell.exe), but that doesn't implement Shell.Application, so just running your application under RemoteApp won't fix the problem.
There are a few potential solutions I can think of:
If you're not using RemoteApp, you could write your own replacement shell that does implement Shell.Application. This is quite a lot of work and there might not be a lot of documentation around on how to do it properly. If you already have a replacement shell, you might be able to extend it to implement Shell.Application.
You could use a different method to enumerate windows. Unfortunately this probably means Win32 (via the EnumWindows function), which isn't directly accessible from VB scripts; you might have to create an ActiveX object that implements the behavior you want, and invoke it from the script.
Similar to option 2 but more heavyweight - you could make that ActiveX object implement the whole Shell.Application interface - even though it isn't actually the shell - and register it on the remote machine. I can't guarantee you won't run into problems if you do this though; it isn't something I've tried before.
None of these solutions are ideal, unfortunately, but hopefully something lets you do what you need to.

Is it possible to write a plugin for Glimpse's existing SQL tab?

Is it possible to write a plugin for Glimpse's existing SQL tab?
I'm trying to log my SQL queries and the currently available extensions don't support our in-house SQL libary. I have written a custom plugin which logs what I want, but it has limited functionality and it doesn't integrate with the existing SQL tab.
Currently, I'm logging to my custom plugin using a single helper method inside my DAL's base class. This function looks takes the SqlCommand and Duration in order to show data on my custom tab:
// simplified example:
Stopwatch sw = Stopwatch.StartNew();
sqlCommand.Connection = sqlConnection;
sqlConnection.Open();
object result = sqlCommand.ExecuteScalar();
sqlConnection.Close();
sw.Stop();
long duration = sw.ElapsedMilliseconds;
LogSqlActivity(sqlCommand, null, duration);
This works well on my 'custom' tab but unfortunately means I don't get metrics shown on Glimpse's HUD:
Is there a way I can provide Glimpse directly with the info it needs (in terms of method names, and parameters) so it displays natively on the SQL tab?
The following advise is based on the fact that you can't use DbProviderFactory and you can't use a proxied SqlCommand, etc.
The data that appears in the "out-of-the-box" SQL tab is based on messages of given types been published through our internal Message Broker (see below on information on this). Because of the above limitations in your case, to get things lighting up correctly (i.e. your data showing up in HUD and the SQL tab), you will need to simulate the work that we do under the covers when we publish these messages. This shouldn't be that difficult and once done, should just work moving forward.
If you have a look at the various proxies we have here you will be above to see what messages we publish in what circumstances. Here are some highlights:
DbCommand
Log command start - here
Log command error - here
Log command end - here
DbConnection:
Log connection open - here
Log connection closed - here
DbTransaction
Log Started - here
Log committed - here
Log rollback - here
Other
Command row count here - Glimpses calculates this at the DbDataReader level but you could do it elsewhere as well
Now that you have an idea of what messages we are expecting and how we generate them, as long as you pass in the right data when you publish those messages, everything should just light up - if you are interested here is the code that looks for the messages that you will be publishing.
Message Broker: If you at the GlimpseConfiguration here you will see how to access the Broker. This can be done statically if needed (as we do here). From here you can publish the messages you need.
Helpers: For generating some of the above messages, you can use the helpers inside the Support class here. I would have shifted all the code for publishing the actual messages to this class, but I didn't think there would be too many people doing what you are doing.
Update 1
Starting point: With the above approach you shouldn't need to write your own plugin. You should just be able to access the broker GlimpseConfiguration.GetConfiguredMessageBroker() (make sure you check if its null, which it is if Glimpse is turned off, etc) and publish your messages.
I would imagine that you would put the inspection that leverages the broker and published the messages, where ever you have knowledge of the information that needs to be collected (i.e. inside your custom lib). Normally this would require references inside your lib to glimpse (which you may not want), so to protect against this, from your lib, you would call a proxy (which could be another VS proj) that has the glimpse dependency. Hence your ado lib only has references to your own code.
To get your toes wet, try just publishing a couple of fake connection and command messages. Assuming the broker you get from GlimpseConfiguration.GetConfiguredMessageBroker() isn't null, these should just show up. Then you can work towards getting real data into it from your lib.
Update 2
Obsolete Broker Access
Its marked as obsolete because its going to change in v2. You will still be able to do what you need to do, but the way of accessing the broker has changed. For what you currently need to do this is ok.
Sometimes null
As you have found this is really dependent on where in the page lifecycle you are currently at. To get around this, I would probably change my original recommendation a little.
In the code where you are currently creating messages and pushing them to the message bus, try putting them into HttpContext.Current.Items. If you haven't used it before, this is a store which asp.net provides out of the box which lasts the lifetime of a given request. You could have a list that you put in there, still create the message objects that you are doing, but put them into that list instead of pushing them through the broker.
Then, create a HttpModule (its really simple to do) which taps into the PostLogRequest event. Within this handler, you would pull the list out of the context, iterate through it and push the message into the message broker (accessing the same way you have been).

Write to file as Different User

I am trying to write to a file that my local user account does not have access to, how can I open and write to the file as an administrator?
You need to launch another process that has admin rights. To do that call ShellExecute with 'runas' as the second parameter (this will open a User Account Control dialog). That executable may be separate or may be the same one that is calling ShellExecute.
You might want to look at PSEXEC from Microsoft, it allows you to execute files in elevated mode, and as a different user if desired.
You didn't say how the file is opened for writing, but PSEXEC can be used in conjunction in batch/vbs file to execute another batch/vbs/exe.
A good wrapper class for impersonation in a using block is what I have used with success before:
using (new Impersonation(domain, username, password))
{
// <code that executes under different user context>
}
The Using statement is great for code readability as seen in this example and to ensure that the object used is properly disposed when the final } character is reached (running out of scope). Apparently there is no guarantee of garbage collection though (see first answer).
Two different sources for such a wrapper class:
This stackoverflow solution features good readability and usability.
Here is similar code from CodeProject: A small C# Class for impersonating a User.
See MSDN for more on the Using statement.