I have two processes that operate on a single Excel file.
The first process creates the Excel instance and opens/creates and activates a workbook and worksheet. The second process makes entries to the spreadsheet. The first process passes the Excel handle as an output parameter to the second process but, when the second process attempts to interact with the workbook, a "Given key not in dictionary" error occurs.
I speculate that the handle is just a means for a process to distinguish between Excel instances to which it is connected and the second process needs to connect to the Excel instance opened by the first process. The Excel VBO contains Attach and Attach Worksheet pages that may provide this functionality, but I cannot find any instructions or documentation for the Excel VBO. There may be more than one Excel instance open and I'm not sure how to refer to the correct instance.
Is my assumption that I need to connect the second process to the Excel instance opened by the first process correct? If so, how do I do this? If not, can anyone tell me what causes the dictionary error and how I can address it?
handles are kept track of internally in memory by a particular instance of the MS Excel VBO. They are not shared between instances of the VBO.
Given the above, and assuming your code is set up exactly as you've described (two distinct processes), this is expected behavior: the instance of the MS Excel VBO that holds the handle for the instance of Excel you're attempting to interact with is purged from memory at the end of the process.
Regarding the "Attach" functionality and associated documentation: most all out-of-the-box VBOs do have documentation available, and is always accessible by clicking the "i" button as emphasized in my screenshot below:
Clicking this pops an Internet Explorer window with the documentation for the particular object you have set in the "Business Object" field of this window. In this case, the MS Excel VBO action "Attach" has the following description:
1.3 Attach
Back-compatible link to 'Open Instance'. This opens the first running
instance of Excel found and links to it in this object. Returns:
- handle : Number : An integer with which the instance opened can be
identified.
- Enable Events : Flag : Indicates that events should be
enabled / disabled on the attached instance - defaulted to True
In your particular use case, this may be a viable action. In most cases/designs (esp. including considerations for resiliency), it should be considered that the automated solution may inadvertently attach to another Excel instance (if one is present). As such, you might want to consider re-factoring your process design to create and interact with the Excel instance within the same Blue Prism process. If you need logical separation of the code that launches Excel & handles the processing, you might consider using individual Pages and page references as opposed to separate processes altogether.
The last point above lends nicely to your assumption regarding the use of handle. At the risk of being redundant: your assumption itself is correct, but you might want to consider a slight re-design to your processes. It's unlikely that the optimal design of a given Blue Prism process would open an instance of Excel in one process, and not interact with it until another process.
Related
I've written a number of programs that monitor devices and records data. The programs are continuously running. I'm usually monitoring several devices using separate workbooks that are independent from each other. However, if one program gets an error, all of VBA stops, including those other programs.
Is there a way to have separate instances of VBA? So if one faults the others can still run? Thanks.
If you want an error in one workbook not to affect running code in another, you can use separate instances of Excel to run each macro.
To start a new instance, hold down the Alt key while opening Excel - it will ask you if you mean to start a new instance. Or you can create a new instance from VBA using CreateObject()
I have developed an Accounts and Inventory System in Excel, All Data Entry, Edit, Delete is through VBA Forms. Every thing worked fine till the The biggest problem arrived, which is now my company ask me to operate same excel software from different PCs at runtime. I know the work book behaves read only when opened to another location at a time. Another idea is shared workbook but it also limits data ENTRY from win form.
Your best option (unless you move to Access) is a master and clients.
The master will be a store of all data, and the clients will be local to each person, a trigger will need to exist in the clients (say on form open and close) to send their content into the master. Depending on what your workbook does you may need to build mechanism like caching, syncing, and error handling.
I have a user requirement that I have been battling with for a while with no success. I need to write an add-in that can read around 100 formula-driven cells (of a specific spreadsheet) once every couple of minutes, and send to a web service.
I'm more than happy to use Excel-DNA or VSTO, but everything I've tried so far causes the user interface to hang for an instant. Would this always be the case if the data is being read from the active spreadsheet (even from a different thread) ?
Reading the sheet from a different thread is likely to have a worse effect than reading from the Excel main thread (say in an event or something). This is due to the COM threading switch that is required for the cross-thread calls. In the end, all the COM calls have to do their work on the main thread anyway.
You might have more success by hooking some of the Excel events, as a start the Workbook.SheetChange event, then checking whether the changes affect your watched Range(s) and updating an internal data structure with the new data.
You can then update the back-end periodically (or only when watched cells have change) from a background thread.
You need to run a secondary thread to post the data to the web service to prevent any UI freeze.
Right now my FMX project is totally based on Livebinding to connect the datasources to my editors on the form.
It works nice, besides to be slow and do not use paging loading (TLisView).
However, I have many different datasources and the amount of data can be huge and connections eventually slow.
My idea is to keep the user interface responsive and let threads in the background make the data load opening the datasources and put them it the right state. After that assigning the datasource to the controls on the form.
I have played with that with LiveBinding but I cannot mix the main thread with background ones. Some problems happened.
Having to load each field record to each control manually seems to be extremely unproductive. I have almost all the controls that I use already wrapped, I made my own controls based on the FMX ones, so I can have the possibility to add more functions.
I was wondering if there is something already done. Any class or library that I could use to map the source and targets and that I can have the control to activate when it is needed, since I can have many datasources in loading state by a thread.
This is not really a livebinding question.
Also without livebindings, when you retrieve data in a thread you have to respect the thread context. When getting a dataset from a connection, this dataset is also bound to that connection and the connection is bound to the thread context.
The solution is to copy the dataset into a clientdataset and hand over that CDS to the UI thread. Now you can bind that CDS wherever you like. Remember, that there is no connection between the CDS and the data connection. You have to take care yourself writing back the changes.
Don't know if this is relevant still. I use livebinding frequently with load time for the underlying data using treads, utilizing the TTask.Run and Thread.Queue. The important point is to have the LiveBinding AutoActivate = FALSE (i.e. TLinkGridToDataBindSource or other livebinding).
Request is done in TThread.Run with Execute of query, and LiveBinding property "Active" set to True in a TThread.Queue [inside the TThread.Run]. The Livebinding is updating UI and must occur in the main thread.
Subsequent update/request is done the same way, setting active to false first.
I built a package in SSIS that uses a script task to open an Excel file, format, and refresh some data in Excel. I would like to have Excel visible when the script task is running to see if Excel gets hung up which occurs all the time. Is this possible? I am converting a process that is calling Excel via a shell script to using SSIS to call Excel instead. I guess a second question is, is that a bad idea?
Why this is a bad idea
Generally speaking, administrators are tasked with maximizing the amount of "uptime" a server or service on the server has. The more software that gets installed on the machine, the greater the odds of service interruptions and outages due to patching. To be able to manipulate Excel in the mechanism you described, you're going to force the installation of MS Office on that machine. That will cost you a software license and the amount of patching required is going to blow holes in whatever SLAs those admins might be required to adhere to.
Memory leaks. Along with the whole patching bit, in the past at least, there were issues with programmatically manipulating Excel and it basically boiled down to it was easy to end up with memory leaks (I gotta make you understand. Allocated memory but never given it up, never let the allocated memory go down). Over time, the compounded effect is that running this package will result in less and less system memory available and the only way to reclaim it is through a reboot, which gets back to SLAs.
The reason you want to see what Excel is doing is so that you can monitor execution because it "gets hung up which occurs all the time". That doesn't sound like a stable process. Again, no admin is going to want an unstable process running on the servers. Something is not right in the cycle of events. Whether it's your code that opens Excel, the macros it runs, etc, something in there is awry and that's why you need to inspect the process. This is akin to putting a bandaid on a shotgun wound. Stop shooting yourself and you won't require bandages.
The task that you're attempting to perform is "open an Excel file, format, and refresh some data in Excel" SSIS can natively push data into Excel. If you preformat the file, develop your SSIS to write to the formatted file and just copy it off, that should work. It's not graceful but it works. There are better methods of providing formatted data but without knowing your infrastructure, I don't know if SSRS, SharePoint, Excel Services, Power Pivot, etc are viable options.
Why you won't be able to see Excel
Generally speaking, the account that runs SQL Agent is probably going to be fairly powerful. To prevent things like a shatter attack, from Windows 2008+ services are restricted in what they can do. For the service account to be able to interact with the desktop, you have to move it into the user tier of apps which might not be a good thing if you, or your DBA/admins, are risk adverse.
For more information, please to enjoy the following links
InteractWithDesktop
http://lostechies.com/keithdahlby/2011/08/13/allowing-a-windows-service-to-interact-with-desktop-without-localsystem/
https://serverfault.com/questions/576144/allow-service-to-interact-with-desktop
https://superuser.com/questions/415204/how-do-i-allow-interactive-services-in-windows-7
That said, if all of the stars are aligned and you accept the risk, of Allow Service to Interact with the Desktop, the answer is exactly as Sam indicated. In your unshown code, you need to set the Visible property to true.
As you go off and allow interactivity with the desktop and someone leaves some "testing" code in the package that gets deployed to production with MessageBox.Show("Click OK to continue"); be aware that if nobody notices this dialog box sitting there, you'll have a job waiting to complete for a very long time.
Regarding your first question, I understand that you want to debug your script task.
You can make Excel visible by adding the following line of code in your script task (assuming C# is the coding language):
// Create your Excel app
var excelApp = new Excel.Application();
// Make the Excel window visible to spot any issues
excelApp.Visible = true;
Don't forget to remove/comment that line after debugging.
Regarding your second question, I don't that this is a bad idea if you properly handle how Excel is opened and closed, in order to avoid memory issues.