Skip to content

Commit 850f04c

Browse files
author
sagi
committed
Consolidate information from all sources
1 parent 380f525 commit 850f04c

File tree

94 files changed

+2466
-58
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+2466
-58
lines changed
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
title: "Offloading UDF computations to a Windows HPC cluster from Excel 2010"
3+
date: 2010-12-09 21:02:00 -0000
4+
authors: govert
5+
tags: [features, .net, excel, exceldna, hpc, xll]
6+
---
7+
Excel 2010 introduced support for offloading UDF computations to a compute cluster. The Excel blog talks about it [http://blogs.msdn.com/b/excel/archive/2010/02/12/offloading-udf-s-to-a-windows-hpc-cluster.aspx][hpc-cluster], and there are some nice pictures on this TechNet article: [http://technet.microsoft.com/en-us/library/ff877825(WS.10).aspx][hpc-services].
8+
9+
Excel-DNA now supports marking functions as cluster-safe, and I have updated the loader to allow add-ins to work under the `XllContainer` on the HPC nodes. There are some issues to be aware of:
10+
11+
* The add-in does not create its own `AppDomain` when running on the compute node. One consequence is that no custom `.xll.config` file is used; configuration entries need to be set in the `XllContainer` configuration setup.
12+
* There are some limitations on the size of array data that can be passed to and from UDF calls - this limit is probably configurable in the WCF service.
13+
* Only the 32-bit host is currently supported.
14+
15+
To test this you will need an Windows HPC Server 2008 R2 cluster with the HPC Services for Excel installed. On the clients you need Excel 2010 with the HPC cluster connector installed. The latest check-in for Excel-DNA with this support is on GitHub: [https://github.com/Excel-DNA/ExcelDna][main-repo].
16+
17+
In the Microsoft HPC SDK there is a sample called ClusterUDF.xll with a few test functions. I have recreated these in C# in the samples file [Distribution\Samples\ClusterSample.dna][cluster-sample] Basically functions just need to be marked as `IsClusterSafe=true` to be pushed to the cluster for computation. For example
18+
19+
```csharp
20+
[ExcelFunction(IsClusterSafe=true)]
21+
public static int DnaCountPrimesC(int nFrom, int nTo)
22+
{
23+
// ...
24+
}
25+
```
26+
27+
As usual, any feedback on this feature - questions or reports on whether you use it - will be most appreciated.
28+
29+
[hpc-cluster]: http://blogs.msdn.com/b/excel/archive/2010/02/12/offloading-udf-s-to-a-windows-hpc-cluster.aspx
30+
[hpc-services]: http://technet.microsoft.com/en-us/library/ff877825(WS.10).aspx
31+
[main-repo]: https://github.com/Excel-DNA/ExcelDna
32+
[cluster-sample]: https://github.com/Excel-DNA/ExcelDna/blob/master/Distribution/Samples/ClusterSample.dna
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
---
2+
title: "Resizing Excel UDF result arrays"
3+
date: 2011-01-30 18:27:00 -0000
4+
authors: govert
5+
tags: [samples, .net, async, excel, exceldna, xll]
6+
---
7+
**Update (21 June 2017): The most up-to-date version of the ArrayResizer utility can be found here**: <https://github.com/Excel-DNA/ExcelDna/blob/master/Distribution/Samples/ArrayResizer.dna>
8+
9+
**Update: To work correctly under Excel 2000/2002/2003, this sample requires at least version 0.29.0.12 of Excel-DNA**.
10+
11+
A common question on the [Excel-DNA group](http://groups.google.com/group/exceldna) is how to automatically resize the results of an array formula. The most well-know appearance of this trick is in the Bloomberg add-in.
12+
13+
**WARNING! This is a bad idea**. Excel does not allow you to modify the sheet from within a user-defined function. Doing this breaks Excel's calculation model.
14+
15+
Anyway, here is my attempt at an Excel-DNA add-in that implements this trick. My approach is to run a macro on a separate thread that will check and if required will expand the formula to an array formula of the right size. This way nothing ugly gets done if the array size is already correct - future recalculations will not run the formula array resizer if the size is still correct.
16+
17+
The code below will register a function call `Resize`. You can either call `Resize` from within your function, or enter something like `=Resize(MyFunction(…))` as the cell formula. The code also registers two sample functions, `MakeArray` and `MakeArrayAndResize` to play with, each take the number of rows and columns for the size of the returned array.
18+
19+
To test this:
20+
21+
1. [Get started with Excel-DNA](/).
22+
2. Copy the code and xml wrapper into a text file called `Resizer.dna` (the xml wrapper is at the end of this post).
23+
3. Copy the `ExcelDna.xll` in the Excel-DNA distribution to `Resizer.xll` (next to the `Resizer.dna`).
24+
4. File->Open the `Resizer.xll` in Excel and enter something like `=MakeArrayAndResize(5,3)` into a cell.
25+
See how it grows.
26+
27+
In the current version, the formula expansion is destructive, so anything in the way will be erased. One case I don't know how to deal with is when there is an array that would be partially overwritten by the expended function result. In the current version Excel will display an error that says "You cannot change part of an array.", and I replace the formula with a text version of it. I'd love to know how you think we should handle this case.
28+
29+
Any questions or comments (can if anyone can get it to work, or not?) can be directed to the [Excel-DNA Google group][excel-dna-group] or to me directly via e-mail. I'm pretty sure there are a few cases where it will break - please let me know if you run into any problems.
30+
31+
I'll try to gather the comments and suggestions for an improved implementation that might go into the next version of Excel-DNA.
32+
33+
Also, if you have any questions about how the implementation works, I'd be happy to write a follow up post that explains a bit more of what I'm doing. But first, let's try to get it working.
34+
35+
Here's the Resizer add-in code:
36+
37+
```csharp
38+
using System;
39+
using System.Collections.Generic;
40+
using System.Reflection;
41+
using System.Runtime.InteropServices;
42+
using System.Threading;
43+
using ExcelDna.Integration;
44+
45+
public static class ResizeTest
46+
{
47+
public static object MakeArray(int rows, int columns)
48+
{
49+
object[,] result = new string[rows, columns];
50+
for (int i = 0; i < rows; i++)
51+
{
52+
for (int j = 0; j < columns; j++)
53+
{
54+
result[i,j] = string.Format("({0},{1})", i, j);
55+
}
56+
}
57+
58+
return result;
59+
}
60+
61+
public static object MakeArrayAndResize(int rows, int columns)
62+
{
63+
object result = MakeArray(rows, columns);
64+
// Call Resize via Excel - so if the Resize add-in is not part of this code, it should still work.
65+
return XlCall.Excel(XlCall.xlUDF, "Resize", result);
66+
}
67+
}
68+
69+
public class Resizer
70+
{
71+
static Queue<ExcelReference> ResizeJobs = new Queue<ExcelReference>();
72+
73+
// This function will run in the UDF context.
74+
// Needs extra protection to allow multithreaded use.
75+
public static object Resize(object[,] array)
76+
{
77+
ExcelReference caller = XlCall.Excel(XlCall.xlfCaller) as ExcelReference;
78+
if (caller == null)
79+
return array;
80+
81+
int rows = array.GetLength(0);
82+
int columns = array.GetLength(1);
83+
84+
if ((caller.RowLast - caller.RowFirst + 1 != rows) ||
85+
(caller.ColumnLast - caller.ColumnFirst + 1 != columns))
86+
{
87+
// Size problem: enqueue job, call async update and return #N/A
88+
// TODO: Add guard for ever-changing result?
89+
EnqueueResize(caller, rows, columns);
90+
AsyncRunMacro("DoResizing");
91+
return ExcelError.ExcelErrorNA;
92+
}
93+
94+
// Size is already OK - just return result
95+
return array;
96+
}
97+
98+
static void EnqueueResize(ExcelReference caller, int rows, int columns)
99+
{
100+
ExcelReference target = new ExcelReference(caller.RowFirst, caller.RowFirst + rows - 1, caller.ColumnFirst, caller.ColumnFirst + columns - 1, caller.SheetId);
101+
ResizeJobs.Enqueue(target);
102+
}
103+
104+
public static void DoResizing()
105+
{
106+
while (ResizeJobs.Count > 0)
107+
{
108+
DoResize(ResizeJobs.Dequeue());
109+
}
110+
}
111+
112+
static void DoResize(ExcelReference target)
113+
{
114+
try
115+
{
116+
// Get the current state for reset later
117+
118+
XlCall.Excel(XlCall.xlcEcho, false);
119+
120+
// Get the formula in the first cell of the target
121+
string formula = (string)XlCall.Excel(XlCall.xlfGetCell, 41, target);
122+
ExcelReference firstCell = new ExcelReference(target.RowFirst, target.RowFirst, target.ColumnFirst, target.ColumnFirst, target.SheetId);
123+
124+
bool isFormulaArray = (bool)XlCall.Excel(XlCall.xlfGetCell, 49, target);
125+
if (isFormulaArray)
126+
{
127+
object oldSelectionOnActiveSheet = XlCall.Excel(XlCall.xlfSelection);
128+
object oldActiveCell = XlCall.Excel(XlCall.xlfActiveCell);
129+
130+
// Remember old selection and select the first cell of the target
131+
string firstCellSheet = (string)XlCall.Excel(XlCall.xlSheetNm, firstCell);
132+
XlCall.Excel(XlCall.xlcWorkbookSelect, new object[] {firstCellSheet});
133+
object oldSelectionOnArraySheet = XlCall.Excel(XlCall.xlfSelection);
134+
XlCall.Excel(XlCall.xlcFormulaGoto, firstCell);
135+
136+
// Extend the selection to the whole array and clear
137+
XlCall.Excel(XlCall.xlcSelectSpecial, 6);
138+
ExcelReference oldArray = (ExcelReference)XlCall.Excel(XlCall.xlfSelection);
139+
140+
oldArray.SetValue(ExcelEmpty.Value);
141+
XlCall.Excel(XlCall.xlcSelect, oldSelectionOnArraySheet);
142+
XlCall.Excel(XlCall.xlcFormulaGoto, oldSelectionOnActiveSheet);
143+
}
144+
// Get the formula and convert to R1C1 mode
145+
bool isR1C1Mode = (bool)XlCall.Excel(XlCall.xlfGetWorkspace, 4);
146+
string formulaR1C1 = formula;
147+
if (!isR1C1Mode)
148+
{
149+
// Set the formula into the whole target
150+
formulaR1C1 = (string)XlCall.Excel(XlCall.xlfFormulaConvert, formula, true, false, ExcelMissing.Value, firstCell);
151+
}
152+
// Must be R1C1-style references
153+
object ignoredResult;
154+
XlCall.XlReturn retval = XlCall.TryExcel(XlCall.xlcFormulaArray, out ignoredResult, formulaR1C1, target);
155+
if (retval != XlCall.XlReturn.XlReturnSuccess)
156+
{
157+
// TODO: Consider what to do now!?
158+
// Might have failed due to array in the way.
159+
firstCell.SetValue("'" + formula);
160+
}
161+
}
162+
finally
163+
{
164+
XlCall.Excel(XlCall.xlcEcho, true);
165+
}
166+
}
167+
168+
// Most of this from the newsgroup: http://groups.google.com/group/exceldna/browse_thread/thread/a72c9b9f49523fc9/4577cd6840c7f195
169+
private static readonly TimeSpan BackoffTime = TimeSpan.FromSeconds(1);
170+
static void AsyncRunMacro(string macroName)
171+
{
172+
// Do this on a new thread....
173+
Thread newThread = new Thread( delegate ()
174+
{
175+
while(true)
176+
{
177+
try
178+
{
179+
RunMacro(macroName);
180+
break;
181+
}
182+
catch(COMException cex)
183+
{
184+
if(IsRetry(cex))
185+
{
186+
Thread.Sleep(BackoffTime);
187+
continue;
188+
}
189+
// TODO: Handle unexpected error
190+
return;
191+
}
192+
catch(Exception ex)
193+
{
194+
// TODO: Handle unexpected error
195+
return;
196+
}
197+
}
198+
});
199+
newThread.Start();
200+
}
201+
202+
static void RunMacro(string macroName)
203+
{
204+
object xlApp;
205+
try
206+
{
207+
object xlApp = ExcelDnaUtil.Application;
208+
xlApp.GetType().InvokeMember("Run", BindingFlags.InvokeMethod, null, xlApp, new object[] {macroName});
209+
}
210+
catch (TargetInvocationException tie)
211+
{
212+
throw tie.InnerException;
213+
}
214+
finally
215+
{
216+
Marshal.ReleaseComObject(xlApp);
217+
}
218+
}
219+
220+
const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
221+
const uint VBA_E_IGNORE = 0x800AC472;
222+
static bool IsRetry(COMException e)
223+
{
224+
uint errorCode = (uint)e.ErrorCode;
225+
switch(errorCode)
226+
{
227+
case RPC_E_SERVERCALL_RETRYLATER:
228+
case VBA_E_IGNORE:
229+
return true;
230+
default:
231+
return false;
232+
}
233+
}
234+
}
235+
```
236+
237+
238+
You can easily make a test add-in for this by wrapping the code into a .dna file with this around:
239+
240+
```xml
241+
<DnaLibrary Language="CS">
242+
<![CDATA[
243+
244+
<!--// Paste all of the above code here //-->
245+
246+
]]>
247+
</DnaLibrary>
248+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: "Financial Analytics Suite (FinAnSu) - made with Excel-DNA"
3+
date: 2011-04-28 22:51:00 -0000
4+
authors: govert
5+
---
6+
I recently noticed a very nice add-in developed by [Bryan McKelvey][bryan-mckelvey] called [FinAnSu][finansu]. The whole add-in is generously available under the MIT open source license, and is a fantastic example of what can be built with Excel-DNA.
7+
8+
[FinAnSu][finansu] uses a ribbon interface to make the various functions and macros easy to find. The RTD server support is used to implement asynchronous data update functions, providing a live quote feed from Bloomberg, Google or Yahoo! And then there is a bunch of useful-looking financial functions. Here's a little preview:
9+
10+
![FinAnSu Quote Animated](./finansu-quote-animated.gif)
11+
12+
Find the project on Google code: [http://code.google.com/p/finansu/][finansu], with detailed documentation on the wiki: [http://code.google.com/p/finansu/wiki/Introduction][finansu-docs].
13+
14+
You can browse through the [source code][finansu-source] online, but to download a copy of the whole project you'll need a [Mercurial client][mercurial-client]. I just installed the one called Mercurial 1.8.2 MSI installer and ran `hg clone https://finansu.googlecode.com/hg/ finansu` from a command prompt.
15+
16+
[bryan-mckelvey]: http://www.brymck.com/
17+
[finansu]: http://code.google.com/p/finansu/
18+
[finansu-quote-img]: /images/finansu-quote-animated.gif "FinAnSu Quote Animated"
19+
[finansu-docs]: http://code.google.com/p/finansu/wiki/Introduction
20+
[finansu-source]: http://code.google.com/p/finansu/source/browse/
21+
[mercurial-client]: http://mercurial.selenic.com/downloads/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
title: "Excel-DNA version 0.29 - RC available"
3+
date: 2011-05-16 13:09:00 -0000
4+
authors: govert
5+
---
6+
I have posted a release candidate of Excel-DNA version 0.29 to the CodePlex site. The download is available at [http://exceldna.codeplex.com/releases/view/66405][release-0-29]. I will wait a week or two for some confirmation that this version works correctly before setting this release to "recommended" status and updating the NuGet package. Any results from your testing with this version would be very helpful.
7+
8+
Excel-DNA version 0.29 adds support for a number of specialized Excel features. The 64-bit version of Excel 2010 is fully supported, registration-free Custom Task Panes can be created under Excel 2007 and later, direct COM server integration can improve integration with legacy VBA code, and macros with parameters are registered. In addition, there are some features to improve the development and debugging workflow, and a few minor bugfixes. The complete change list is included below.
9+
10+
More information about the new features will be posted on the Excel-DNA website in the coming weeks. Any comments or questions are welcome on the Google group - [http://groups.google.com/group/exceldna][excel-dna-group] - or by contacting me directly.
11+
12+
As always, I greatly appreciate any feedback on this version, and on Excel-DNA in general.
13+
14+
-Govert
15+
16+
### Complete change list
17+
18+
* **BREAKING CHANGE!** Changed `SheetId` in the `ExcelReference` type to an `IntPtr` for 64-bit compatibility.
19+
* Changed initialization - only create sandboxed `AppDomain` under .NET 4 (or if explicitly requested with `CreateSandboxedAppDomain="true"` attribute on `DnaLibrary` tag in .dna file).
20+
* Fixed memory leak when getting `SheetId` for `ExcelReference` parameters.
21+
* Fixed Ribbon `RunTagMacro` when no Workbook open.
22+
* Added support for the 64-bit version of Excel 2010 with the .Net 4 runtime.
23+
* Added Cluster-safe function support for Excel 2010 HPC Cluster Connector - mark functions as `IsClusterSafe=true`.
24+
* Added `CustomTaskPane` support and sample.
25+
* Added COM server support for RTD servers and other `ComVisible` classes. Mark `ExternalLibraries` and Projects as `ComServer="true"` in the .dna file. Supports `Regsvr32` registration or by calling `ComServer.DllRegisterServer`. Allows direct RTD and VBA object instantiation. Includes `TypeLib` registration and packing support.
26+
* Added support for macros with parameters.
27+
* Added `ArrayResizer` sample.
28+
* Added C# 4 dynamic type sample.
29+
* Added Path attribute to `SourceItem` tag to allow external source.
30+
* Added `LoadFromBytes` attribute to `ExternalLibrary` tag to prevent locking of .dll.
31+
* Added `/O` output path option to `ExcelDnaPack`.
32+
* Added "before" option to CommandBars xml.
33+
* Added `Int64` support for parameters and return values.
34+
35+
[release-0-29]: http://exceldna.codeplex.com/releases/view/66405
36+
[excel-dna-group]: http://groups.google.com/group/exceldna
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
title: "Excel VBA to VB.NET with Excel-DNA and NetOffice"
3+
date: 2012-01-30 13:29:00 -0000
4+
authors: govert
5+
tags: [samples]
6+
---
7+
Excel-DNA is a great library to help ease the path from Excel VBA to VB.NET. Last year another part of the puzzle fell in place: I discovered [NetOffice][netoffice], a version-independent set of Office interop assemblies put together by Sebastian Lange. By referencing the NetOffice assemblies instead of the official Primary Interop Assemblies (PIA) for Office, an Excel-DNA add-in can target various Excel versions with a single add-in, and also ease distribution of the required interop assemblies, even packing them into the `.xll` add-in itself.
8+
9+
To explore how Excel-DNA and NetOffice can combine to convert a VBA add-in to VB.NET, I picked a small add-in made by [Robert del Vicario][robert-vicario] that does a risk analysis simulation inspired by the [Pallisade @RISK][palisade-risk] add-in. I took [Robert's original RiskGen VBA add-in][riskgen-vba], and created a new Excel-DNA add-in in VB.NET (I used Visual Studio, but the free [SharpDevelop][sharpdevelop] IDE should work fine too). I documented the steps along the way of creating the VB.NET project, making an add-in based on Excel-DNA and using NetOffice to help port the VBA code to VB.NET. The resulting document (RiskGen Port Log.docx) outlining exactly how I ported the add-in, with the new VB.NET-based [RiskGen.NET][riskgen-net] is also on Robert's site.
10+
11+
I'm also looking for some more examples of free/open source VBA add-ins to port to Excel-DNA. The best add-ins will contain a mix of user-defined functions and macros which use the Excel object model. Please post to the Google group or mail me directly if you have any suggestions.
12+
13+
And as always, if you need any support porting your Excel VBA add-ins to .NET using Excel-DNA, I'm happy to help on the [Excel-DNA Google group][excel-dna-group].
14+
15+
[netoffice]: https://github.com/netoffice
16+
[robert-vicario]: http://rwdvc.posterous.com
17+
[palisade-risk]: http://www.palisade.com/risk/
18+
[riskgen-vba]: http://rwdvc.posterous.com/riskgen-test
19+
[riskgen-net]: http://rwdvc.posterous.com/riskgen-in-vbnet
20+
[sharpdevelop]: http://www.icsharpcode.net/OpenSource/SD/Download/#SharpDevelop4x
21+
[excel-dna-group]: http://groups.google.com/group/exceldna

0 commit comments

Comments
 (0)