Currently, I have a spreadsheet which uses an external program to do calculations (let's say it's an aerodynamic calculation tool). In Excel VBA, I update the inputs to the program via a UDF at the spreadsheet level ( =input("var1",1.234)).
Then, using VBA, I write the input file, run the external .exe, and read the output file. Outputs are again reported to the spreadsheet level via a UDF (=output("var2"))
I would like to use the Excel Solver function to make an optimization of the spreadsheet. Here, I would like it to change the input values ( via the =input() function) to get the optimum in the outputs (via the =output() function). The solver should be able to change the inputs, wait for the new calculation to be made (via the external .exe) and then resume when it gets the outputs.
So far I've found no reliable way to make it work. The Excel solver does not know that it needs to wait for the .exe to finish, even when I embed the shell(.exe) command in the input UDF....the solver still plows through as if nothing was happening.
Expectedly, it comes up with bunk since the output is out of sync with the input. I've pried open the SOLVER.XLAM (...ahemm..) to find a way to insert a wait statement, but that wasn't much help; the interface ends where the VBA interfaces with the SOLVER.dll, which places hooks into Excel to run the Excel calculation directly from the .dll ...so no help to me.
So far I'm stumped. Nobody seems to have encountered this before. I've tried looking into OpenSolver.org version, but they also end at some mysterious .dll or .exe interface. Any ideas?
(BTW: I have no access to the external program code, if you're wondering.... an .exe and some text files is all I get).
OpenSolver should work if you use the NOMAD solver, which does all calculations directly inside the spreadsheet. See http://opensolver.org/non-linear-nomad-integration/ for more information.
Related
I have a large userform in a project that is causing some issues when it is loaded into memory. There isn't anything exotic happening in the Userform_Initialize event (just populating combo boxes and setting default properties).
Everything was working just fine a few weeks ago when the userform wasn't as big (measured in KB). Initially, I thought the workbook was corrupted and proceeded to export every userform, module and class, re-import into a new workbook, and subsequently compiling the project as I've always done. This did not fix the issue. Interestingly enough, when I put a Stop at the top of the initialize event, and step through the code, everything works fine.
Main Idea
This got me thinking that the possible cause of the issue is the fact that the userform is very large, thus the process of loading the userform into memory is taking longer than the typical load. Essentially, the vb editor is continuing to execute the code in the initialize event, attempting to access controls that may not be in memory yet.
I have done some crude analysis to get a pretty good idea of just how large the userform in question is. The userform was exported and re-imported into a blank workbook. The workbook without the userform was around 30 KB, and with the userform, the workbook was over 350 KB, so we can conclude that the userform is around 320 KB.
It is important to note that I have extensive error handling in my project, however, I'm unable to identify this particular error as it is occurring in the initialize event (Error handling is impossible inside this particular event [Bovey, Professional Excel Development, pg 489]).
Question : With the exception of a time delay (e.g. Application.Wait or Sleep via Windows API), is there another approach to avoid crashing?
UPDATE
It turns out that delaying the application didn't work reliably either. I have actually removed the entire Initialize event to no avail as well. One thing that I forgot to mention in my original post, was that I was abusing the Debug -->> Compile VBA Project feature. See my answer below.
After dealing with this for quite some time, a colleague of mine simply commented one random line of code (not in the UserForm_Initialize, just in some random module), saved the file, and reopened it with no issues. We then discovered that the issue was not in the code, but rather with Debug -->> Compile VBA Project. For the most part, I use Debug -->> Compile VBA Project, about once every hour as I'm coding. I then save that file and continue developing on that very same compiled file. When it is all said and done, I probably run Debug -->> Compile VBA Project about 100 times over the course of two weeks. I then found this comment from Chip Pearson on this website:
VBA code is never stored as the plain text that you type in to the
editor. Input is immediately converted to platform- and
version-independent byte codes called OpCodes. These OpCodes are
converted by the editor to the text you see on the screen. When you
compile the project, the compiler translates these OpCodes to
platform- and version-specific codes called ExCodes. When you run the
code, the runtime reads the ExCodes and executes actual machine code
on behalf of the project based on the ExCodes. This whole process is
similar in principle to how Java and the Java Virtual Machine work.
If you were to export all your VBA code to text files and then remove
all the modules and then re-import the code from the text files back
into VBA (which is exactly what Rob Bovey's Code Cleaner does), you'll
see a decrease in file size. This is because the ExCodes were purged
and have not yet been recreated. Then, if you compile the project, the
file size will increase because now it stores the ExCodes in addition
to the OpCodes.
You really never need to compile the code. VBA will automatically do
it when necessary. However, the Compile command also does syntax
checking, which is its only real practical purpose.
And this is from Rob Bovey himself found here (You will also find Rob Bovey's Code Cleaner at that website):
During the process of creating VBA programs a lot of junk code builds up in your files. If you don't clean your files periodically you will begin to experience strange problems caused by this extra baggage. Cleaning a project involves exporting the contents of all its VBComponents to text files, deleting the components and then importing the components back from the text files.
I then did just as I did above in the original question. I exported all modules, re-imported them into a fresh excel workbook, added the relevant libraries, and DID NOT (as I was before) run Debug -->> Compile VBA Project. I haven't had any issues since.
I have a excel file with macros. It's used like template for our program. Program opens this file, call macros and put data there as parametrs. The question is how can I debug this macros when it's called from the app? For example, in Visual Studio I can use "Attach to process", maybe there is something like this in VBA?
I have a few different ways to perform debugging in Excel, and none of them are perfect or very sophisticated.
Use debug.print throughout your code to print to the Immediate window to see how the program is executing. This is useful in two scenarios - if you want to see generally how far along your program executed, or where it is in the process of executing, or alternatively, you can go in and add more detail using debug.print if your program is getting snagged somewhere specifically, and you want to see what is happening as the program is executing.
Create an array, enter log information into the array as the program executes, and print the array at the completion of the program execution. This is imperfect because it is not really useful in conditions where the program execution does not complete successfully, but it is useful in scenarios where you want to get some statistics about how the program ran as part of an autopsy.
Add Code Breaks in to the program so that you can see how the program is executing as it is run. Use the Immediate window to check on the values of variables in the program.
Again, none of these are perfect.
When using the magic function %edit from QtConsole with IPython, the call does not block, and does not execute the saved code. It does however save a temporary file...
I think this is intended behavior due to GUI editors and uncertainty, and whatever that reason is for not being able to communicate with subprocess (pyZMQ?).
What do you suggest as the best way to mix %edit/%run magics?
I would not mind calling two different commands (one to edit, and one after I have saved and execution is safe). But those commands need a way to synchronize this target file location, or someone to persist storage, and probably need some crude form of predicatably generating filenames such that you can edit more than one file at a time, and execute in arbitrarily. Session persistence is not a must.
Would writing my own magic do any good? Hope we can %edit macros soon, that would do well enough to make it work.
you shoudl be able to do %edit filename.py and %run filename.py. The non blocking behavior is expected, and IIRC due to technical reason. Not unsurmountable but difficult.
You could define your own magic if you wish, improvement are welcomed.
Hope we can %edit macros soon, that would do well enough to make it work.
For that too, PR are welcomed. I guess as a workaround/option you can %load macro which would put macro on input n+1 , edit it and redefine it, that might be a good extension for a cell magic %%macro macroname
If you have some executable code on your input (from QtConsole), you can type
%edit 1-5
This fires the editor, creates a temporarily file (automatically managed), and loads your input lines. This is nearly enough, now how to retrieve the name of that temp file pragmatically?
I see the print statement on Stdout, but its not visible to QtConsole AFAIK. Could maybe redirect stdout to catch that line, but that may not be an option anyway if your doing something else with stdout.
If I could retrieve the full pathname that was just created, this would be cake. Store it where some magics will know how to find it. Then issue a followup command when ready,pops the name off the stack, loads it into a macro, and run. All this with 2 input commands and no names to remember (unless you want to find and use that macro again, but for 1 shot stuff...)
How do I catch or retrieve the path of that temporary file?
During the development of some Excel vba code, in about every other iteration where I go in, add some code and then save the file, the next time I open it, I get a "File not Found" error. The macro is set to automatically run the code upon opening the file.
To fix it, I copied all the code - modules and classes plus the startup code - to a fresh blank excel file. I save the excel macro file and it runs fine.
This happens for both Excel 2003 and 2007. What is happening here?
My psycho powers tell me you are relying on relative paths while changing the current directory.
I'm seeing a similar phenomenon, though I'm not sure the cause is the same.
Yesterday, every time I added a Workbook_Open procedure to my workbook, saved it and reopened it, I got the "File not found" error (no particular file specified). followed by "We found a problem with some content in [workbook name]. Do you want us to try to recover as much as we can?". If I said Yes to recovering, I found that all the VBA code was gone from the workbook.
It turned out that this was caused by my virus checker (BitDefender), which considered my code to be malware and was removing code from the workbook. I tried it on a PC with a different virus checker (BullGuard) and it did something similar. At least BullGuard had the decency to tell me it was modifying my file. BitDefender didn't give me any clue at all!
On a general point, as someone who does VBA work for many different clients, I'm finding more and more problems with virus checkers getting in my way.
Not sure if you have solved your problem.
One possibility is that one of your module is too long.
VBA is a compiled size limit for 64kb. It is "supposed" to warn you if you exceed that, but often it fails.
Find out the longest Module that you have, move some function out to another module and see if it helps.
I have this often.
I am making a primitive database in Excel and need a routine to run in the background constantly. I will be able to fill in the actual actions it needs to do, but I don't know how to make something run independent of a key press or some sort of Macro. If someone can give me an example of code that runs independently which I can simply fill with contents, that would be much appreciated.
Try this http://www.ozgrid.com/Excel/run-macro-on-time.htm
I haven't worked with VBA for quite some time now, but you would have to create a thread in VBA, maybe by COM-Threading, but I am not too sure if Excel is threadsafe or if you even can use Threads of some kind in Excel. Another alternative would be a Timer. If it is not implemented in VBA and I don't remember it to be, you would have to create the Timer yourself and react to the Windows Message yourself, if you can do that in VBA.
All in all I think this uses case might be to big for an Excel VBA Macro. If I were you I would consider doing this in a different way.