Skip to content

Commit 76f514b

Browse files
committed
Migrate Samples from main repo Distribution
1 parent 4b5f343 commit 76f514b

File tree

102 files changed

+7153
-0
lines changed

Some content is hidden

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

102 files changed

+7153
-0
lines changed

Archive/ApplicationEventsVB.dna

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<DnaLibrary RuntimeVersion="v4.0" Name="Application Events Test" Language="VB" >
2+
<Reference Name="Microsoft.Office.Interop.Excel" />
3+
<Reference Name="Office" />
4+
<![CDATA[
5+
6+
Imports Microsoft.Office.Interop.Excel
7+
Imports Microsoft.Office.Core
8+
Imports ExcelDna.Integration
9+
10+
' This defines a module, where we add a new worksheet function
11+
Public Module MyFunctions
12+
13+
<ExcelFunction(Description:="My first .NET function", Category:="Useful Excel-DNA Functions")>
14+
Public Function dnaHello(name As String) As String
15+
Return "Hello " & name
16+
End Function
17+
18+
<ExcelCommand(MenuName:="Excel-DNA Test Macros", MenuText:="Say Hello") >
19+
Sub SayHello()
20+
MsgBox("Hello from Excel-DNA!", Title := "Excel-DNA Test")
21+
End Sub
22+
End Module
23+
24+
' This Class which implements IExcelAddIn allows us to do some work when the add-in is loaded.
25+
' We get hold of the Application object, and then hook an event and add a new context menu button
26+
Public Class AddIn
27+
Implements IExcelAddIn
28+
29+
WithEvents Application As Application
30+
WithEvents Button As CommandBarButton
31+
32+
Public Sub AutoOpen() Implements IExcelAddIn.AutoOpen
33+
Application = ExcelDnaUtil.Application
34+
35+
' Add Cell context menu
36+
Dim ContextMenu As CommandBar
37+
38+
ContextMenu = Application.CommandBars("Cell")
39+
Button = ContextMenu.Controls.Add(Type := MsoControlType.msoControlButton, Before := ContextMenu.Controls.Count, Temporary := true)
40+
Button.Caption = "Excel-DNA Test Button"
41+
' NOTE: For some reason we MUST set a Tag for the button, otherwise the events don't work
42+
Button.Tag = "Excel-DNA-Test"
43+
End Sub
44+
45+
Public Sub AutoClose() Implements IExcelAddIn.AutoClose
46+
Button.Delete
47+
End Sub
48+
49+
Private Sub Application_SheetSelectionChange(Sh As Object, Target As Range) Handles Application.SheetSelectionChange
50+
Application.StatusBar = "Selection on sheet " + CType(Sh, Worksheet).Name & " is now " & Target.Address
51+
End Sub
52+
53+
Private Sub Button_Click(Ctrl As CommandBarButton, ByRef CancelDefault As Boolean) Handles Button.Click
54+
Application.StatusBar = "Excel-DNA Test Button - Clicked!"
55+
End Sub
56+
End Class
57+
58+
59+
60+
]]>
61+
</DnaLibrary>

Archive/ArrayResizer.dna

+301
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
<DnaLibrary RuntimeVersion="v4.0" Language="CS">
2+
<![CDATA[
3+
using System;
4+
using System.Collections.Generic;
5+
using ExcelDna.Integration;
6+
7+
namespace AsyncFunctions
8+
{
9+
// This class defines a few test functions that can be used to explore the automatic array resizing.
10+
public static class ResizeTestFunctions
11+
{
12+
// Just returns an array of the given size
13+
public static object[,] MakeArray(int rows, int columns)
14+
{
15+
object[,] result = new object [rows, columns];
16+
for (int i = 0; i < rows; i++)
17+
{
18+
for (int j = 0; j < columns; j++)
19+
{
20+
result[i,j] = i + j;
21+
}
22+
}
23+
24+
return result;
25+
}
26+
27+
public static double[,] MakeArrayDoubles(int rows, int columns)
28+
{
29+
double[,] result = new double[rows, columns];
30+
for (int i = 0; i < rows; i++)
31+
{
32+
for (int j = 0; j < columns; j++)
33+
{
34+
result[i,j] = i + (j/1000.0);
35+
}
36+
}
37+
38+
return result;
39+
}
40+
41+
public static object MakeMixedArrayAndResize(int rows, int columns)
42+
{
43+
object[,] result = new object [rows, columns];
44+
for (int j = 0; j < columns; j++)
45+
{
46+
result[0,j] = "Col " + j;
47+
}
48+
for (int i = 1; i < rows; i++)
49+
{
50+
for (int j = 0; j < columns; j++)
51+
{
52+
result[i,j] = i + (j * 0.1);
53+
}
54+
}
55+
56+
return ArrayResizer.Resize(result);
57+
}
58+
59+
// Makes an array, but automatically resizes the result
60+
public static object MakeArrayAndResize(int rows, int columns, string unused, string unusedtoo)
61+
{
62+
object[,] result = MakeArray(rows, columns);
63+
return ArrayResizer.Resize(result);
64+
65+
// Can also call Resize via Excel - so if the Resize add-in is not part of this code, it should still work
66+
// (though calling direct is better for large arrays - it prevents extra marshaling).
67+
// return XlCall.Excel(XlCall.xlUDF, "Resize", result);
68+
}
69+
70+
public static double[,] MakeArrayAndResizeDoubles(int rows, int columns)
71+
{
72+
double[,] result = MakeArrayDoubles(rows, columns);
73+
return ArrayResizer.ResizeDoubles(result);
74+
}
75+
}
76+
77+
public class ArrayResizer : XlCall
78+
{
79+
// This function will run in the UDF context.
80+
// Needs extra protection to allow multithreaded use.
81+
public static object Resize(object[,] array)
82+
{
83+
var caller = Excel(xlfCaller) as ExcelReference;
84+
if (caller == null)
85+
return array;
86+
87+
int rows = array.GetLength(0);
88+
int columns = array.GetLength(1);
89+
90+
if (rows == 0 || columns == 0)
91+
return array;
92+
93+
if ((caller.RowLast - caller.RowFirst + 1 == rows) &&
94+
(caller.ColumnLast - caller.ColumnFirst + 1 == columns))
95+
{
96+
// Size is already OK - just return result
97+
return array;
98+
}
99+
100+
var rowLast = caller.RowFirst + rows - 1;
101+
var columnLast = caller.ColumnFirst + columns - 1;
102+
103+
// Check for the sheet limits
104+
if (rowLast > ExcelDnaUtil.ExcelLimits.MaxRows - 1 ||
105+
columnLast > ExcelDnaUtil.ExcelLimits.MaxColumns - 1)
106+
{
107+
// Can't resize - goes beyond the end of the sheet - just return #VALUE
108+
// (Can't give message here, or change cells)
109+
return ExcelError.ExcelErrorValue;
110+
}
111+
112+
// TODO: Add some kind of guard for ever-changing result?
113+
ExcelAsyncUtil.QueueAsMacro(() =>
114+
{
115+
// Create a reference of the right size
116+
var target = new ExcelReference(caller.RowFirst, rowLast, caller.ColumnFirst, columnLast, caller.SheetId);
117+
DoResize(target); // Will trigger a recalc by writing formula
118+
});
119+
// Return what we have - to prevent flashing #N/A
120+
return array;
121+
}
122+
123+
public static double[,] ResizeDoubles(double[,] array)
124+
{
125+
var caller = Excel(xlfCaller) as ExcelReference;
126+
if (caller == null)
127+
return array;
128+
129+
int rows = array.GetLength(0);
130+
int columns = array.GetLength(1);
131+
132+
if (rows == 0 || columns == 0)
133+
return array;
134+
135+
if ((caller.RowLast - caller.RowFirst + 1 == rows) &&
136+
(caller.ColumnLast - caller.ColumnFirst + 1 == columns))
137+
{
138+
// Size is already OK - just return result
139+
return array;
140+
}
141+
142+
var rowLast = caller.RowFirst + rows - 1;
143+
var columnLast = caller.ColumnFirst + columns - 1;
144+
145+
if (rowLast > ExcelDnaUtil.ExcelLimits.MaxRows - 1 ||
146+
columnLast > ExcelDnaUtil.ExcelLimits.MaxColumns - 1)
147+
{
148+
// Can't resize - goes beyond the end of the sheet - just return null (for #NUM!)
149+
// (Can't give message here, or change cells)
150+
return null;
151+
}
152+
153+
// TODO: Add guard for ever-changing result?
154+
ExcelAsyncUtil.QueueAsMacro(() =>
155+
{
156+
// Create a reference of the right size
157+
var target = new ExcelReference(caller.RowFirst, rowLast, caller.ColumnFirst, columnLast, caller.SheetId);
158+
DoResize(target); // Will trigger a recalc by writing formula
159+
});
160+
// Return what we have - to prevent flashing #N/A
161+
return array;
162+
}
163+
164+
static void DoResize(ExcelReference target)
165+
{
166+
// Get the current state for reset later
167+
using (new ExcelEchoOffHelper())
168+
using (new ExcelCalculationManualHelper())
169+
{
170+
ExcelReference firstCell = new ExcelReference(target.RowFirst, target.RowFirst, target.ColumnFirst, target.ColumnFirst, target.SheetId);
171+
172+
// Get the formula in the first cell of the target
173+
string formula = (string)Excel(xlfGetCell, 41, firstCell);
174+
bool isFormulaArray = (bool)Excel(xlfGetCell, 49, firstCell);
175+
if (isFormulaArray)
176+
{
177+
// Select the sheet and firstCell - needed because we want to use SelectSpecial.
178+
using (new ExcelSelectionHelper(firstCell))
179+
{
180+
// Extend the selection to the whole array and clear
181+
Excel(xlcSelectSpecial, 6);
182+
ExcelReference oldArray = (ExcelReference)Excel(xlfSelection);
183+
184+
oldArray.SetValue(ExcelEmpty.Value);
185+
}
186+
}
187+
// Get the formula and convert to R1C1 mode
188+
bool isR1C1Mode = (bool)Excel(xlfGetWorkspace, 4);
189+
string formulaR1C1 = formula;
190+
if (!isR1C1Mode)
191+
{
192+
object formulaR1C1Obj;
193+
XlReturn formulaR1C1Return = TryExcel(xlfFormulaConvert, out formulaR1C1Obj, formula, true, false, ExcelMissing.Value, firstCell);
194+
if (formulaR1C1Return != XlReturn.XlReturnSuccess || formulaR1C1Obj is ExcelError)
195+
{
196+
string firstCellAddress = (string)Excel(xlfReftext, firstCell, true);
197+
Excel(xlcAlert, "Cannot resize array formula at " + firstCellAddress + " - formula might be too long when converted to R1C1 format.");
198+
firstCell.SetValue("'" + formula);
199+
return;
200+
}
201+
formulaR1C1 = (string)formulaR1C1Obj;
202+
}
203+
// Must be R1C1-style references
204+
object ignoredResult;
205+
//Debug.Print("Resizing START: " + target.RowLast);
206+
XlReturn formulaArrayReturn = TryExcel(xlcFormulaArray, out ignoredResult, formulaR1C1, target);
207+
//Debug.Print("Resizing FINISH");
208+
209+
// TODO: Find some dummy macro to clear the undo stack
210+
211+
if (formulaArrayReturn != XlReturn.XlReturnSuccess)
212+
{
213+
string firstCellAddress = (string)Excel(xlfReftext, firstCell, true);
214+
Excel(xlcAlert, "Cannot resize array formula at " + firstCellAddress + " - result might overlap another array.");
215+
// Might have failed due to array in the way.
216+
firstCell.SetValue("'" + formula);
217+
}
218+
}
219+
}
220+
}
221+
222+
// RIIA-style helpers to deal with Excel selections
223+
// Don't use if you agree with Eric Lippert here: http://stackoverflow.com/a/1757344/44264
224+
public class ExcelEchoOffHelper : XlCall, IDisposable
225+
{
226+
object oldEcho;
227+
228+
public ExcelEchoOffHelper()
229+
{
230+
oldEcho = Excel(xlfGetWorkspace, 40);
231+
Excel(xlcEcho, false);
232+
}
233+
234+
public void Dispose()
235+
{
236+
Excel(xlcEcho, oldEcho);
237+
}
238+
}
239+
240+
public class ExcelCalculationManualHelper : XlCall, IDisposable
241+
{
242+
object oldCalculationMode;
243+
244+
public ExcelCalculationManualHelper()
245+
{
246+
oldCalculationMode = Excel(xlfGetDocument, 14);
247+
Excel(xlcOptionsCalculation, 3);
248+
}
249+
250+
public void Dispose()
251+
{
252+
Excel(xlcOptionsCalculation, oldCalculationMode);
253+
}
254+
}
255+
256+
// Select an ExcelReference (perhaps on another sheet) allowing changes to be made there.
257+
// On clean-up, resets all the selections and the active sheet.
258+
// Should not be used if the work you are going to do will switch sheets, amke new sheets etc.
259+
public class ExcelSelectionHelper : XlCall, IDisposable
260+
{
261+
object oldSelectionOnActiveSheet;
262+
object oldActiveCellOnActiveSheet;
263+
264+
object oldSelectionOnRefSheet;
265+
object oldActiveCellOnRefSheet;
266+
267+
public ExcelSelectionHelper(ExcelReference refToSelect)
268+
{
269+
// Remember old selection state on the active sheet
270+
oldSelectionOnActiveSheet = Excel(xlfSelection);
271+
oldActiveCellOnActiveSheet = Excel(xlfActiveCell);
272+
273+
// Switch to the sheet we want to select
274+
string refSheet = (string)Excel(xlSheetNm, refToSelect);
275+
Excel(xlcWorkbookSelect, new object[] { refSheet });
276+
277+
// record selection and active cell on the sheet we want to select
278+
oldSelectionOnRefSheet = Excel(xlfSelection);
279+
oldActiveCellOnRefSheet = Excel(xlfActiveCell);
280+
281+
// make the selection
282+
Excel(xlcFormulaGoto, refToSelect);
283+
}
284+
285+
public void Dispose()
286+
{
287+
// Reset the selection on the target sheet
288+
Excel(xlcSelect, oldSelectionOnRefSheet, oldActiveCellOnRefSheet);
289+
290+
// Reset the sheet originally selected
291+
string oldActiveSheet = (string)Excel(xlSheetNm, oldSelectionOnActiveSheet);
292+
Excel(xlcWorkbookSelect, new object[] { oldActiveSheet });
293+
294+
// Reset the selection in the active sheet (some bugs make this change sometimes too)
295+
Excel(xlcSelect, oldSelectionOnActiveSheet, oldActiveCellOnActiveSheet);
296+
}
297+
}
298+
299+
}
300+
]]>
301+
</DnaLibrary>

0 commit comments

Comments
 (0)