├── .editorconfig
├── .gitignore
├── .vscode
└── tasks.json
├── ExcelDna.Utilities.sln
├── ExcelDna.Utilities
├── DataTableEx.cs
├── Enums.cs
├── ExcelDna.Utilities.csproj
├── ExcelReferenceEx.cs
├── Name.cs
├── WorkBook.cs
├── WorkSheet.cs
├── XLApp.cs
├── XLConversion.cs
├── XLDBWrapper.cs
├── XLDate.cs
├── XLObjectMapper.cs
├── XLObjectMapping.cs
└── globals.cs
├── LICENSE
└── README.md
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{cs,vb}]
2 |
3 | # IDE0044: Add readonly modifier
4 | dotnet_diagnostic.IDE0044.severity = silent
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # Tye
65 | .tye/
66 |
67 | # StyleCop
68 | StyleCopReport.xml
69 |
70 | # Files built by Visual Studio
71 | *_i.c
72 | *_p.c
73 | *_h.h
74 | *.ilk
75 | *.meta
76 | *.obj
77 | *.iobj
78 | *.pch
79 | *.pdb
80 | *.ipdb
81 | *.pgc
82 | *.pgd
83 | *.rsp
84 | *.sbr
85 | *.tlb
86 | *.tli
87 | *.tlh
88 | *.tmp
89 | *.tmp_proj
90 | *_wpftmp.csproj
91 | *.log
92 | *.vspscc
93 | *.vssscc
94 | .builds
95 | *.pidb
96 | *.svclog
97 | *.scc
98 |
99 | # Chutzpah Test files
100 | _Chutzpah*
101 |
102 | # Visual C++ cache files
103 | ipch/
104 | *.aps
105 | *.ncb
106 | *.opendb
107 | *.opensdf
108 | *.sdf
109 | *.cachefile
110 | *.VC.db
111 | *.VC.VC.opendb
112 |
113 | # Visual Studio profiler
114 | *.psess
115 | *.vsp
116 | *.vspx
117 | *.sap
118 |
119 | # Visual Studio Trace Files
120 | *.e2e
121 |
122 | # TFS 2012 Local Workspace
123 | $tf/
124 |
125 | # Guidance Automation Toolkit
126 | *.gpState
127 |
128 | # ReSharper is a .NET coding add-in
129 | _ReSharper*/
130 | *.[Rr]e[Ss]harper
131 | *.DotSettings.user
132 |
133 | # TeamCity is a build add-in
134 | _TeamCity*
135 |
136 | # DotCover is a Code Coverage Tool
137 | *.dotCover
138 |
139 | # AxoCover is a Code Coverage Tool
140 | .axoCover/*
141 | !.axoCover/settings.json
142 |
143 | # Coverlet is a free, cross platform Code Coverage Tool
144 | coverage*[.json, .xml, .info]
145 |
146 | # Visual Studio code coverage results
147 | *.coverage
148 | *.coveragexml
149 |
150 | # NCrunch
151 | _NCrunch_*
152 | .*crunch*.local.xml
153 | nCrunchTemp_*
154 |
155 | # MightyMoose
156 | *.mm.*
157 | AutoTest.Net/
158 |
159 | # Web workbench (sass)
160 | .sass-cache/
161 |
162 | # Installshield output folder
163 | [Ee]xpress/
164 |
165 | # DocProject is a documentation generator add-in
166 | DocProject/buildhelp/
167 | DocProject/Help/*.HxT
168 | DocProject/Help/*.HxC
169 | DocProject/Help/*.hhc
170 | DocProject/Help/*.hhk
171 | DocProject/Help/*.hhp
172 | DocProject/Help/Html2
173 | DocProject/Help/html
174 |
175 | # Click-Once directory
176 | publish/
177 |
178 | # Publish Web Output
179 | *.[Pp]ublish.xml
180 | *.azurePubxml
181 | # Note: Comment the next line if you want to checkin your web deploy settings,
182 | # but database connection strings (with potential passwords) will be unencrypted
183 | *.pubxml
184 | *.publishproj
185 |
186 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
187 | # checkin your Azure Web App publish settings, but sensitive information contained
188 | # in these scripts will be unencrypted
189 | PublishScripts/
190 |
191 | # NuGet Packages
192 | *.nupkg
193 | # NuGet Symbol Packages
194 | *.snupkg
195 | # The packages folder can be ignored because of Package Restore
196 | **/[Pp]ackages/*
197 | # except build/, which is used as an MSBuild target.
198 | !**/[Pp]ackages/build/
199 | # Uncomment if necessary however generally it will be regenerated when needed
200 | #!**/[Pp]ackages/repositories.config
201 | # NuGet v3's project.json files produces more ignorable files
202 | *.nuget.props
203 | *.nuget.targets
204 |
205 | # Microsoft Azure Build Output
206 | csx/
207 | *.build.csdef
208 |
209 | # Microsoft Azure Emulator
210 | ecf/
211 | rcf/
212 |
213 | # Windows Store app package directories and files
214 | AppPackages/
215 | BundleArtifacts/
216 | Package.StoreAssociation.xml
217 | _pkginfo.txt
218 | *.appx
219 | *.appxbundle
220 | *.appxupload
221 |
222 | # Visual Studio cache files
223 | # files ending in .cache can be ignored
224 | *.[Cc]ache
225 | # but keep track of directories ending in .cache
226 | !?*.[Cc]ache/
227 |
228 | # Others
229 | ClientBin/
230 | ~$*
231 | *~
232 | *.dbmdl
233 | *.dbproj.schemaview
234 | *.jfm
235 | *.pfx
236 | *.publishsettings
237 | orleans.codegen.cs
238 |
239 | # Including strong name files can present a security risk
240 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
241 | #*.snk
242 |
243 | # Since there are multiple workflows, uncomment next line to ignore bower_components
244 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
245 | #bower_components/
246 |
247 | # RIA/Silverlight projects
248 | Generated_Code/
249 |
250 | # Backup & report files from converting an old project file
251 | # to a newer Visual Studio version. Backup files are not needed,
252 | # because we have git ;-)
253 | _UpgradeReport_Files/
254 | Backup*/
255 | UpgradeLog*.XML
256 | UpgradeLog*.htm
257 | ServiceFabricBackup/
258 | *.rptproj.bak
259 |
260 | # SQL Server files
261 | *.mdf
262 | *.ldf
263 | *.ndf
264 |
265 | # Business Intelligence projects
266 | *.rdl.data
267 | *.bim.layout
268 | *.bim_*.settings
269 | *.rptproj.rsuser
270 | *- [Bb]ackup.rdl
271 | *- [Bb]ackup ([0-9]).rdl
272 | *- [Bb]ackup ([0-9][0-9]).rdl
273 |
274 | # Microsoft Fakes
275 | FakesAssemblies/
276 |
277 | # GhostDoc plugin setting file
278 | *.GhostDoc.xml
279 |
280 | # Node.js Tools for Visual Studio
281 | .ntvs_analysis.dat
282 | node_modules/
283 |
284 | # Visual Studio 6 build log
285 | *.plg
286 |
287 | # Visual Studio 6 workspace options file
288 | *.opt
289 |
290 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
291 | *.vbw
292 |
293 | # Visual Studio LightSwitch build output
294 | **/*.HTMLClient/GeneratedArtifacts
295 | **/*.DesktopClient/GeneratedArtifacts
296 | **/*.DesktopClient/ModelManifest.xml
297 | **/*.Server/GeneratedArtifacts
298 | **/*.Server/ModelManifest.xml
299 | _Pvt_Extensions
300 |
301 | # Paket dependency manager
302 | .paket/paket.exe
303 | paket-files/
304 |
305 | # FAKE - F# Make
306 | .fake/
307 |
308 | # Ionide - VsCode extension for F# Support
309 | .ionide/
310 |
311 | # CodeRush personal settings
312 | .cr/personal
313 |
314 | # Python Tools for Visual Studio (PTVS)
315 | __pycache__/
316 | *.pyc
317 |
318 | # Cake - Uncomment if you are using it
319 | # tools/**
320 | # !tools/packages.config
321 |
322 | # Tabs Studio
323 | *.tss
324 |
325 | # Telerik's JustMock configuration file
326 | *.jmconfig
327 |
328 | # BizTalk build output
329 | *.btp.cs
330 | *.btm.cs
331 | *.odx.cs
332 | *.xsd.cs
333 |
334 | # OpenCover UI analysis results
335 | OpenCover/
336 |
337 | # Azure Stream Analytics local run output
338 | ASALocalRun/
339 |
340 | # MSBuild Binary and Structured Log
341 | *.binlog
342 |
343 | # NVidia Nsight GPU debugger configuration file
344 | *.nvuser
345 |
346 | # MFractors (Xamarin productivity tool) working folder
347 | .mfractor/
348 |
349 | # Local History for Visual Studio
350 | .localhistory/
351 |
352 | # BeatPulse healthcheck temp database
353 | healthchecksdb
354 |
355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
356 | MigrationBackup/
357 |
358 | # Ionide (cross platform F# VS Code tools) working folder
359 | .ionide/
360 |
361 | ##
362 | ## Visual studio for Mac
363 | ##
364 |
365 |
366 | # globs
367 | Makefile.in
368 | *.userprefs
369 | *.usertasks
370 | config.make
371 | config.status
372 | aclocal.m4
373 | install-sh
374 | autom4te.cache/
375 | *.tar.gz
376 | tarballs/
377 | test-results/
378 |
379 | # Mac bundle stuff
380 | *.dmg
381 | *.app
382 |
383 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
384 | # General
385 | .DS_Store
386 | .AppleDouble
387 | .LSOverride
388 |
389 | # Icon must end with two \r
390 | Icon
391 |
392 |
393 | # Thumbnails
394 | ._*
395 |
396 | # Files that might appear in the root of a volume
397 | .DocumentRevisions-V100
398 | .fseventsd
399 | .Spotlight-V100
400 | .TemporaryItems
401 | .Trashes
402 | .VolumeIcon.icns
403 | .com.apple.timemachine.donotpresent
404 |
405 | # Directories potentially created on remote AFP share
406 | .AppleDB
407 | .AppleDesktop
408 | Network Trash Folder
409 | Temporary Items
410 | .apdisk
411 |
412 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
413 | # Windows thumbnail cache files
414 | Thumbs.db
415 | ehthumbs.db
416 | ehthumbs_vista.db
417 |
418 | # Dump file
419 | *.stackdump
420 |
421 | # Folder config file
422 | [Dd]esktop.ini
423 |
424 | # Recycle Bin used on file shares
425 | $RECYCLE.BIN/
426 |
427 | # Windows Installer files
428 | *.cab
429 | *.msi
430 | *.msix
431 | *.msm
432 | *.msp
433 |
434 | # Windows shortcuts
435 | *.lnk
436 |
437 | # JetBrains Rider
438 | .idea/
439 | *.sln.iml
440 |
441 | ##
442 | ## Visual Studio Code
443 | ##
444 | .vscode/*
445 | !.vscode/settings.json
446 | !.vscode/tasks.json
447 | !.vscode/launch.json
448 | !.vscode/extensions.json
449 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/ExcelDna.Utilities.sln",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary;ForceNoAlign"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | }
16 | ]
17 | }
--------------------------------------------------------------------------------
/ExcelDna.Utilities.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.6.30114.105
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExcelDna.Utilities", "ExcelDna.Utilities\ExcelDna.Utilities.csproj", "{FB173F9D-7301-4C0A-A195-47924E9820A8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|x64 = Debug|x64
12 | Debug|x86 = Debug|x86
13 | Release|Any CPU = Release|Any CPU
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Debug|x64.ActiveCfg = Debug|Any CPU
24 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Debug|x64.Build.0 = Debug|Any CPU
25 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Debug|x86.ActiveCfg = Debug|Any CPU
26 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Debug|x86.Build.0 = Debug|Any CPU
27 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Release|Any CPU.Build.0 = Release|Any CPU
29 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Release|x64.ActiveCfg = Release|Any CPU
30 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Release|x64.Build.0 = Release|Any CPU
31 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Release|x86.ActiveCfg = Release|Any CPU
32 | {FB173F9D-7301-4C0A-A195-47924E9820A8}.Release|x86.Build.0 = Release|Any CPU
33 | EndGlobalSection
34 | EndGlobal
35 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/DataTableEx.cs:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2014 Joachim Loebb
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | namespace ExcelDna.Utilities;
26 |
27 | public static class DataTableEx
28 | {
29 |
30 | public static object[,] ToVariant(this DataTable dt, bool header = false)
31 | {
32 | if (dt.Columns.Count == 0) return new object[1, 1] { { 0 } };
33 |
34 | int n = dt.Rows.Count, cols = dt.Columns.Count;
35 | int rows = header ? n + 1 : n;
36 | int start = header ? 1 : 0;
37 |
38 |
39 | object[,] retval = new object[rows, cols];
40 |
41 | if (header)
42 | {
43 | for (int i = 0; i < cols; i++)
44 | retval[0, i] = dt.Columns[i].Caption;
45 | }
46 |
47 | for (int i = 0; i < n; i++)
48 | {
49 | for (int j = 0; j < cols; j++)
50 | retval[start, j] = dt.Rows[i][dt.Columns[j].ColumnName];
51 | start++;
52 | }
53 |
54 | return retval;
55 |
56 | }
57 |
58 | public static string ToString(this DataTable dt, string sep = ",", bool header = false)
59 | {
60 | var sb = new StringBuilder();
61 | if (dt.Rows.Count == 0) return string.Empty;
62 |
63 | int n = dt.Rows.Count, cols = dt.Columns.Count;
64 | int rows = header ? n + 1 : n;
65 | int start = header ? 1 : 0;
66 |
67 |
68 | if (header)
69 | {
70 | for (int i = 0; i < cols; i++)
71 | sb.Append(dt.Columns[i].Caption + sep);
72 | sb.Length -= sep.Length;
73 | sb.AppendLine();
74 | }
75 |
76 | for (int i = 0; i < n; i++)
77 | {
78 | for (int j = 0; j < cols; j++)
79 | sb.Append(dt.Rows[i][dt.Columns[j].ColumnName].ToString() + sep);
80 |
81 | sb.Length -= sep.Length;
82 | sb.AppendLine();
83 | start++;
84 | }
85 | return sb.ToString();
86 | }
87 |
88 | public static void AddRange(this DataTable dt, object vt)
89 | {
90 | if (vt is not object[,] vtdata)
91 | throw new ArgumentException("vt must be an variant array!");
92 |
93 | int n = vtdata.GetLength(0);
94 | int k = vtdata.GetLength(1);
95 |
96 | var cols = dt.Columns;
97 | if (cols.Count != k)
98 | throw new ArgumentException("Number of columns does not match the columns in vt!");
99 |
100 | for (int i = 0; i < n; i++)
101 | {
102 | var row = dt.NewRow();
103 | for (int j = 0; j < k; j++)
104 | {
105 | row[cols[j].ColumnName] = vtdata[i, j].ConvertTo(cols[j].DataType);
106 | }
107 | dt.Rows.Add(row);
108 | }
109 | }
110 |
111 | public static string GetHeader(this DataTable dt, string sep = ",")
112 | {
113 | StringBuilder sb = new();
114 | for (int i = 0; i < dt.Columns.Count; i++)
115 | {
116 | sb.Append(dt.Columns[i].Caption + sep);
117 | }
118 | return sb.ToString(0, sb.Length - sep.Length);
119 | }
120 |
121 | public static DataTable CreateDataTable(this object vt, bool header = true)
122 | {
123 | if (vt is not object[,] vtdata)
124 | throw new ArgumentException("vt must be a 2-dimensional variant array!");
125 |
126 | var dt = new DataTable();
127 |
128 | int n = vtdata.GetLength(0);
129 | int k = vtdata.GetLength(1);
130 | int start = (header) ? 1 : 0;
131 |
132 | if (header)
133 | {
134 | for (int j = 0; j < k; j++)
135 | {
136 | var col = vtdata[0, j].ToString();
137 | dt.Columns.Add(new DataColumn(col, vtdata[1, j].GetType()));
138 | }
139 | }
140 | else
141 | {
142 | for (int j = 0; j < k; j++)
143 | {
144 | var col = "col" + (j + 1).ToString();
145 | dt.Columns.Add(new DataColumn(col, vtdata[0, j].GetType()));
146 | }
147 | }
148 | var cols = dt.Columns;
149 |
150 | for (int i = start; i < n; i++)
151 | {
152 | var row = dt.NewRow();
153 | for (int j = 0; j < k; j++)
154 | {
155 | row[cols[j].ColumnName] = vtdata[i, j];
156 | }
157 | dt.Rows.Add(row);
158 | }
159 | return dt;
160 | }
161 | }
162 |
163 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/Enums.cs:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2014 Joachim Loebb
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 |
26 | namespace ExcelDna.Utilities;
27 |
28 | public enum xlCalculation
29 | {
30 | Automatic = 1,
31 | SemiAutomatic = 2,
32 | Manual = 3,
33 | }
34 |
35 | public enum xlPasteType
36 | {
37 | PasteAll = 1,
38 | PasteFormulas = 2,
39 | PasteValues = 3,
40 | PasteFormats = 4,
41 | PasteNotes = 5
42 | }
43 |
44 | public enum xlPasteAction
45 | {
46 | None = 1,
47 | Add = 2,
48 | Substract = 3,
49 | Multiply = 4,
50 | Divide = 5,
51 | }
52 |
53 | public enum xlUpdateLinks
54 | {
55 | Never = 0,
56 | ExternalOnly = 1,
57 | RemoteOnly = 2,
58 | ExternalAndRemote = 3,
59 | }
60 |
61 | public enum xlBorderStyle
62 | {
63 | NoBorder = 0,
64 | ThinLine = 1,
65 | MediumLine = 2,
66 | DashedLine = 3,
67 | DottedLine = 4,
68 | ThickLine = 5,
69 | Doubleline = 6,
70 | HairLine = 7,
71 | }
72 |
73 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/ExcelDna.Utilities.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | latest
6 | ExcelDna.Utilities
7 | ExcelDna.Utilities
8 | Utilities that add functionality to ExcelDna such as creating a COM like interface to the C API
9 | LICENSE
10 | https://github.com/smartquant/ExcelDna.Utilities
11 | false
12 | Joachim Loebb
13 | Joachim Loebb
14 | Copyright © 2014-2024 Joachim Loebb
15 | $(Version)
16 | $(Verson)
17 | README.md
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/ExcelReferenceEx.cs:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2014 Joachim Loebb
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 |
26 | using ExcelDna.Integration;
27 |
28 |
29 | namespace ExcelDna.Utilities;
30 |
31 | public static partial class ExcelReferenceEx
32 | {
33 | public static T GetValue(this ExcelReference range)
34 | {
35 | return XLConversion.ConvertTo(range.GetValue());
36 | }
37 |
38 | public static T[,] ToMatrix(this ExcelReference range)
39 | {
40 | return range.GetValue().ToMatrix();
41 | }
42 |
43 | public static T[] ToVector(this ExcelReference range)
44 | {
45 | return range.GetValue().ToVector();
46 | }
47 |
48 | public static void DeleteEntireRows(this ExcelReference range)
49 | {
50 | //Shift_num Result
51 |
52 | //1 Shifts cells left
53 | //2 Shifts cells up
54 | //3 Deletes entire row
55 | //4 Deletes entire column
56 |
57 | static void action()
58 | {
59 | XlCall.Excel(XlCall.xlcEditDelete, 3);
60 | }
61 |
62 | XLApp.ActionOnSelectedRange(range, action);
63 | }
64 |
65 | public static void ClearContents(this ExcelReference range)
66 | {
67 | //int n = range.RowLast - range.RowFirst + 1, k = range.ColumnLast - range.ColumnFirst + 1;
68 | //var _empty = new object[n, k];
69 | //range.SetValue(_empty);
70 |
71 | static void action() => XlCall.Excel(XlCall.xlcClear, 3);
72 |
73 | XLApp.ActionOnSelectedRange(range, action);
74 | }
75 |
76 | ///
77 | /// Changes the color formatting of a range
78 | ///
79 | ///
80 | /// 0: default color,number from 1 to 56 corresponding to the 56 area background colors in the Patterns tab of the Format Cells dialog box
81 | /// 0: default color,number from 1 to 56 corresponding to the 56 area foreground colors in the Patterns tab of the Foramt Cells dialog box
82 | /// 0: auto pattern, pattern can be from 1 to 18
83 | public static void FormatColor(this ExcelReference range, int backcolor = 0, int forecolor = 0, int pattern = 0)
84 | {
85 | //Should be called within screenupdating = false
86 |
87 | //change the pattern
88 | //PATTERNS(apattern, afore, aback, newui)
89 | void action() => XlCall.Excel(XlCall.xlcPatterns, pattern, forecolor, backcolor, true);
90 |
91 | XLApp.ActionOnSelectedRange(range, action);
92 | }
93 |
94 | public static void FormatBorder(this ExcelReference range, xlBorderStyle outline = xlBorderStyle.NoBorder,
95 | xlBorderStyle left = xlBorderStyle.NoBorder, xlBorderStyle right = xlBorderStyle.NoBorder,
96 | xlBorderStyle top = xlBorderStyle.NoBorder, xlBorderStyle bottom = xlBorderStyle.NoBorder,
97 | int shade = 0, int outline_color = 0, int left_color = 0, int right_color = 0, int top_color = 0, int bottom_color = 0)
98 | {
99 | //BORDER(outline, left, right, top, bottom, shade, outline_color, left_color, right_color, top_color, bottom_color)
100 |
101 | void action() => XlCall.Excel(XlCall.xlcBorder, (int)left, (int)right, (int)top,
102 | (int)bottom, shade, outline_color, left_color, right_color, top_color, bottom_color);
103 |
104 | XLApp.ActionOnSelectedRange(range, action);
105 | }
106 |
107 | public static void FormatNumber(this ExcelReference range, string format)
108 | {
109 |
110 | void action() => XlCall.Excel(XlCall.xlcFormatNumber, format);
111 |
112 | XLApp.ActionOnSelectedRange(range, action);
113 | }
114 |
115 | public static string SheetRef(this ExcelReference range)
116 | {
117 | return (string)XlCall.Excel(XlCall.xlfGetCell, 62, range);
118 | }
119 |
120 | public static void Select(this ExcelReference range)
121 | {
122 | XlCall.Excel(XlCall.xlcFormulaGoto, range);
123 | XlCall.Excel(XlCall.xlcSelect, range, Type.Missing);
124 | }
125 |
126 | public static void Copy(this ExcelReference fromRange, ExcelReference toRange = null)
127 | {
128 | object to_range = (toRange == null) ? Type.Missing : toRange;
129 | XlCall.Excel(XlCall.xlcCopy, fromRange, to_range);
130 | }
131 |
132 | public static string RefersTo(this ExcelReference range)
133 | {
134 | object result = XlCall.Excel(XlCall.xlfGetCell, 6, range);
135 | return (string)result;
136 | }
137 |
138 | public static ExcelReference Resize(this ExcelReference range, int rows, int cols)
139 | {
140 | rows = (rows < 1) ? 1 : rows;
141 | cols = (cols < 1) ? 1 : cols;
142 | return new ExcelReference(range.RowFirst, range.RowFirst + rows - 1, range.ColumnFirst, range.ColumnFirst + cols - 1, range.SheetId);
143 | }
144 |
145 | public static ExcelReference Offset(this ExcelReference range, int rows, int cols)
146 | {
147 | return new ExcelReference(range.RowFirst + rows, range.RowLast + rows, range.ColumnFirst + cols, range.ColumnLast + cols, range.SheetId);
148 | }
149 |
150 | public static ExcelReference AddHeader(this ExcelReference range)
151 | {
152 | return new ExcelReference(range.RowFirst - 1, range.RowLast, range.ColumnFirst, range.ColumnLast, range.SheetId);
153 | }
154 |
155 | public static List ToList(this ExcelReference range, Func factory = null) where T : class
156 | {
157 | var items = new List();
158 | XLObjectMapper.AddRange(items, range.GetValue(), factory);
159 | return items;
160 | }
161 |
162 | public static DataTable ToDataTable(this ExcelReference range, bool header = true)
163 | {
164 | return DataTableEx.CreateDataTable(range.GetValue(), header);
165 | }
166 |
167 | ///
168 | /// copy a variant matrix into an excel named range and adjust the size of the named range
169 | /// 1.) will copy the formatting of the first row when adding new rows
170 | /// 2.) will copy the formatting of the first row after the named range when removing rows
171 | ///
172 | /// should be object[,] or simple data type
173 | ///
174 | /// This is the local name of the output range (always ex header)
175 | /// if there is a header the named range will start one cell below
176 | /// will not fill the first cell; header will be inside the range if true
177 | public static void Fill(this ExcelReference outRange, object vt, string localName = null, bool header = false, bool ignoreFirstCell = false)
178 | {
179 | var _vt = vt as object[,];
180 | if (_vt == null) _vt = new object[,] { { vt } };
181 |
182 | int name_offset = (header && ignoreFirstCell) ? 1 : 0;
183 | int origin_offset = ((header && !ignoreFirstCell) ? -1 : 0);
184 | int header_offset = (header) ? -1 : 0;
185 | int n = _vt.GetLength(0), k = _vt.GetLength(1);
186 | int m = outRange.RowLast - outRange.RowFirst + 1;
187 |
188 | //formatting
189 | bool localRange = !string.IsNullOrEmpty(localName);
190 | bool format = true;
191 |
192 | ExcelReference formatRange = null, newRange = null;
193 |
194 | if (m == 1 && localRange)
195 | {
196 | formatRange = Name.GetRange(string.Format("'{0}'!{1}", outRange.SheetRef(), localName));
197 | if (formatRange == null)
198 | format = false;
199 | else
200 | m = formatRange.RowLast - formatRange.RowFirst + 1;
201 | }
202 | else if (m == 1)
203 | format = false;
204 |
205 |
206 | bool addRows = n + header_offset > m && format;
207 | bool removeRows = n + header_offset < m && format;
208 |
209 |
210 | int x0 = outRange.RowFirst + origin_offset, y0 = outRange.ColumnFirst; //output origin
211 | int x1 = outRange.RowFirst + name_offset, y1 = outRange.ColumnFirst; //name origin
212 |
213 | bool updating = XLApp.ScreenUpdating;
214 | xlCalculation calcMode = XLApp.Calcuation;
215 |
216 | if (updating) XLApp.ScreenUpdating = false;
217 |
218 | try
219 | {
220 | var fillRange = new ExcelReference(x0, x0 + n - 1, y0, y0 + k - 1, outRange.SheetId);
221 |
222 | if (addRows)
223 | {
224 | formatRange = new ExcelReference(x1, x1, y1, y1 + k - 1, outRange.SheetId); //first row
225 | newRange = new ExcelReference(x1, x1 + n + header_offset - 1, y1, y1 + k - 1, outRange.SheetId);
226 | }
227 | if (removeRows)
228 | {
229 | formatRange = new ExcelReference(x1 + m, x1 + m, y1, y1 + k - 1, outRange.SheetId); //last row + 1
230 | newRange = new ExcelReference(x1 + n + header_offset, x1 + m - 1, y1, y1 + k - 1, outRange.SheetId);
231 | newRange.ClearContents();
232 | }
233 |
234 | //set the range except the first cell
235 | if (ignoreFirstCell && n > 1)
236 | {
237 | //first row
238 | if (k > 1)
239 | {
240 | object[,] first = new object[1, k - 1];
241 | for (int i = 0; i < k - 1; i++)
242 | first[0, i] = _vt[0, i + 1];
243 | fillRange.Offset(0, 1).Resize(1, k - 1).SetValue(first);
244 | }
245 | //all other rows
246 | object[,] rest = new object[n - 1, k];
247 | for (int i = 1; i < n; i++)
248 | for (int j = 0; j < k; j++)
249 | rest[i - 1, j] = _vt[i, j];
250 | fillRange.Offset(1, 0).Resize(n - 1, k).SetValue(rest);
251 | }
252 | else if (!ignoreFirstCell)
253 | fillRange.SetValue(_vt);
254 |
255 |
256 | //set name
257 | if (localRange)
258 | {
259 | Action action = () =>
260 | {
261 | string sheetref = (string)XlCall.Excel(XlCall.xlSheetNm, outRange);
262 | Worksheet sheet = new(sheetref);
263 |
264 | //re-color
265 | if (addRows || removeRows)
266 | {
267 | formatRange.Select();
268 | XLApp.Copy();
269 | newRange.Select();
270 | XLApp.PasteSpecial(xlPasteType.PasteFormats);
271 | }
272 |
273 | string reference = string.Format("='{4}'!R{0}C{2}:R{1}C{3}", x1 + 1, x1 + n + header_offset, y1 + 1, y1 + k, sheetref);
274 |
275 | //DEFINE.NAME(name_text, refers_to, macro_type, shortcut_text, hidden, category, local)
276 | XlCall.Excel(XlCall.xlcDefineName, localName, reference, Type.Missing, Type.Missing, false, Type.Missing, true);
277 | };
278 | XLApp.ActionOnSelectedRange(fillRange, action);
279 | }
280 | }
281 | finally
282 | {
283 | if (updating) XLApp.ScreenUpdating = true;
284 | }
285 |
286 | }
287 |
288 | //TODO: these functions should be able to paste chunks of data say 5000 lines per chunk rather than converting everything in one array
289 |
290 | public static void Fill(this ExcelReference outRange, DataTable dt, string localName = null, bool header = false, bool ignoreFirstCell = false)
291 | {
292 | var vt = dt.ToVariant(header);
293 | Fill(outRange, vt, localName, header, ignoreFirstCell);
294 | }
295 |
296 | public static void Fill(this ExcelReference outRange, IEnumerable items, string localName = null, bool header = false, bool ignoreFirstCell = false) where T : class
297 | {
298 | var vt = items.ToVariant(header);
299 | Fill(outRange, vt, localName, header, ignoreFirstCell);
300 | }
301 | }
302 |
303 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/Name.cs:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2014 Joachim Loebb
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | using ExcelDna.Integration;
26 |
27 | namespace ExcelDna.Utilities;
28 |
29 | public class Name
30 | {
31 | #region fields
32 |
33 | private Worksheet _worksheet;
34 | private Workbook _workbook;
35 | private string _name;
36 |
37 | #endregion
38 |
39 | #region constructors
40 |
41 | ///
42 | /// Name with worksheet scope
43 | ///
44 | ///
45 | ///
46 | internal Name(Worksheet worksheet, string name)
47 | {
48 | _worksheet = worksheet;
49 | _name = name;
50 | }
51 |
52 | ///
53 | /// Name with workbook scope
54 | ///
55 | ///
56 | ///
57 | internal Name(Workbook workbook, string name)
58 | {
59 | _workbook = workbook;
60 | _name = name;
61 | }
62 |
63 | #endregion
64 |
65 | #region properties
66 |
67 | public string NameLocal
68 | {
69 | get { return _name; }
70 | }
71 |
72 | public string NameRef
73 | {
74 | get
75 | {
76 | return (_workbook != null) ? _workbook.Name + "!" + _name :
77 | _worksheet.SheetRef.Contains(" ") ?
78 | string.Format("'{0}'!{1}", _worksheet.SheetRef, _name) :
79 | string.Format("{0}!{1}", _worksheet.SheetRef, _name);
80 | }
81 | }
82 |
83 | public bool IsLocalScope
84 | {
85 | get { return _worksheet != null; }
86 | }
87 |
88 | public bool IsGlobalScope
89 | {
90 | get { return _workbook != null; }
91 | }
92 |
93 | public string RefersTo
94 | {
95 | get
96 | {
97 | return (string)XlCall.Excel(XlCall.xlfGetName, this.NameRef, Type.Missing);
98 | }
99 | }
100 |
101 | #endregion
102 |
103 | #region static methods
104 |
105 | public static ExcelReference GetRange(string nameRef)
106 | {
107 | object result = XlCall.Excel(XlCall.xlfEvaluate, "=" + nameRef);
108 |
109 | return result as ExcelReference;
110 | }
111 |
112 | public static T GetValue(string nameRef)
113 | {
114 | object result = XlCall.Excel(XlCall.xlfEvaluate, "=" + nameRef);
115 |
116 | ExcelReference r = result as ExcelReference;
117 | if (r != null)
118 | return r.GetValue().ConvertTo();
119 | else
120 | return result.ConvertTo();
121 | }
122 |
123 | public static T GetValue(Workbook wb, string name)
124 | {
125 | return GetValue(new Name(wb, name).RefersTo);
126 | }
127 |
128 | public static T GetValue(Worksheet ws, string name)
129 | {
130 | return GetValue(new Name(ws, name).RefersTo);
131 | }
132 |
133 | public static string NameRefersTo(string nameRef)
134 | {
135 | return (string)XlCall.Excel(XlCall.xlfGetName, nameRef, Type.Missing);
136 | }
137 |
138 | #endregion
139 |
140 | #region functions
141 |
142 | public override string ToString()
143 | {
144 | return _name;
145 | }
146 |
147 | #endregion
148 | }
149 |
150 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/WorkBook.cs:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2014 Joachim Loebb
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 | using ExcelDna.Integration;
26 |
27 | namespace ExcelDna.Utilities;
28 |
29 | public class Workbook
30 | {
31 | #region fields
32 |
33 | private string _path;
34 | private string _workbook;
35 |
36 | #endregion
37 |
38 | #region constructor
39 |
40 | public Workbook(string filename)
41 | {
42 | Init(filename);
43 | }
44 |
45 | private void Init(string filename)
46 | {
47 | FileInfo finfo = new(filename);
48 | _path = finfo.DirectoryName + System.IO.Path.DirectorySeparatorChar;
49 | _workbook = finfo.Name;
50 | }
51 |
52 | #endregion
53 |
54 | #region static methods
55 |
56 | public static Workbook CreateNew()
57 | {
58 | XlCall.Excel(XlCall.xlcNew, 5);
59 | var res = XlCall.Excel(XlCall.xlfGetDocument, 88);
60 | return new Workbook((string)res);
61 | }
62 |
63 | public static Workbook ActiveWorkbook()
64 | {
65 | var res = XlCall.Excel(XlCall.xlfGetDocument, 88);
66 | return new Workbook((string)res);
67 | }
68 |
69 | public static Workbook Open(string path, xlUpdateLinks update_links = xlUpdateLinks.Never,
70 | bool read_only = false, string password = null)
71 | {
72 | XlCall.Excel(XlCall.xlcOpen, path, (int)update_links, read_only,
73 | Type.Missing, password, Type.Missing, true, 2,
74 | Type.Missing, true, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
75 | Workbook wb = new(path);
76 | return wb;
77 | }
78 |
79 | #endregion
80 |
81 | #region properties
82 |
83 | public string Path
84 | {
85 | get { return _path; }
86 | }
87 |
88 | public string Name
89 | {
90 | get { return _workbook; }
91 | }
92 |
93 | public bool IsOpen
94 | {
95 | get
96 | {
97 | var res = XlCall.Excel(XlCall.xlfGetDocument, 3, _workbook);
98 | Type t = res.GetType();
99 | return (t != typeof(ExcelError));
100 | }
101 | }
102 |
103 | public bool IsReadonly
104 | {
105 | get
106 | {
107 | var res = XlCall.Excel(XlCall.xlfGetDocument, 5, _workbook);
108 | Type t = res.GetType();
109 | if (t == typeof(ExcelError)) return true;
110 | return (bool)res;
111 | }
112 | }
113 |
114 | #endregion
115 |
116 | #region close save
117 |
118 | public void Activate()
119 | {
120 | XlCall.Excel(XlCall.xlcActivate, this.Name, Type.Missing);
121 | }
122 |
123 | public void Close(bool saveChanges = true, bool routeFile = false)
124 | {
125 | Activate();
126 | XlCall.Excel(XlCall.xlcClose, saveChanges, routeFile);
127 | }
128 |
129 | public string GetPath()
130 | {
131 | _path = (string)XlCall.Excel(XlCall.xlfGetDocument, _workbook, 2);
132 | return _path;
133 | }
134 |
135 | public void SaveAs(string path, string password = null, string write_password = null, bool read_only = false)
136 | {
137 | object pwd = string.IsNullOrEmpty(password) ? Type.Missing : password;
138 | object write_pwd = string.IsNullOrEmpty(write_password) ? Type.Missing : write_password;
139 |
140 | XlCall.Excel(XlCall.xlcSaveAs, path, Type.Missing, pwd, Type.Missing, write_pwd, read_only);
141 | Init(path);
142 | }
143 |
144 | public void Save()
145 | {
146 | Activate();
147 | XlCall.Excel(XlCall.xlcSave);
148 | }
149 |
150 | #endregion
151 |
152 | #region functions
153 |
154 | public Worksheet AddWorksheet()
155 | {
156 | Activate();
157 | XlCall.Excel(XlCall.xlcWorkbookInsert, 1);
158 | return Worksheet.ActiveSheet();
159 | }
160 |
161 | public Worksheet[] Worksheets
162 | {
163 | get
164 | {
165 | object[,] sheetnames =
166 | (object[,])XlCall.Excel(XlCall.xlfGetWorkbook, 1, this.Name);
167 | int n = sheetnames.GetLength(1);
168 | Worksheet[] sheets = new Worksheet[n];
169 |
170 | for (int j = 0; j < n; j++)
171 | {
172 | sheets[j] = new Worksheet(sheetnames[0, j].ToString());
173 | }
174 | return sheets;
175 | }
176 | }
177 |
178 | public string[] SheetRefs
179 | {
180 | get
181 | {
182 | object[,] sheetnames =
183 | (object[,])XlCall.Excel(XlCall.xlfGetWorkbook, 1, this.Name);
184 | int n = sheetnames.GetLength(1);
185 | string[] sheets = new string[n];
186 |
187 | for (int j = 0; j < n; j++)
188 | {
189 | sheets[j] = sheetnames[0, j].ToString();
190 | }
191 | return sheets;
192 | }
193 | }
194 |
195 | public string[] SheetNames
196 | {
197 | get
198 | {
199 | var sheetrefs = this.SheetRefs;
200 | int n = sheetrefs.Length;
201 | string[] result = new string[n];
202 |
203 | for (int i = 0; i < n; i++)
204 | result[i] = Worksheet.ExtractSheetName(sheetrefs[i]);
205 |
206 | return result;
207 | }
208 | }
209 |
210 | ///
211 | /// References a sheet from this workbook, however DOES NOT TEST wheter sheet actually exists for
212 | /// performance reasons
213 | ///
214 | ///
215 | ///
216 | public Worksheet this[string sheetName]
217 | {
218 | get
219 | {
220 | return new Worksheet(this, sheetName);
221 | }
222 | }
223 |
224 | #endregion
225 | }
226 |
227 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/WorkSheet.cs:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2014 Joachim Loebb
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 |
26 | using ExcelDna.Integration;
27 |
28 | namespace ExcelDna.Utilities;
29 |
30 | public class Worksheet
31 | {
32 | #region fields
33 |
34 | private Workbook _workbook;
35 | private string _sheetname;
36 |
37 | #endregion
38 |
39 | #region constructors
40 |
41 | public Worksheet(Workbook wb, string sheet)
42 | {
43 | _workbook = wb;
44 | _sheetname = sheet;
45 | }
46 |
47 | public Worksheet(string sheetRef)
48 | {
49 | int pos = sheetRef.IndexOf(']');
50 | _workbook = new Workbook(sheetRef.Substring(1, pos - 1));
51 | _sheetname = sheetRef.Substring(pos + 1, sheetRef.Length - pos - 1);
52 | }
53 |
54 | #endregion
55 |
56 | #region properties
57 |
58 | public string Name
59 | {
60 | get { return _sheetname; }
61 | set
62 | {
63 | XlCall.Excel(XlCall.xlcWorkbookName, SheetRef, string.Format("[{0}]{1}", _workbook.Name, value));
64 | _sheetname = value;
65 | }
66 | }
67 |
68 | public Workbook Workbook
69 | {
70 | get { return _workbook; }
71 | }
72 |
73 | ///
74 | /// Full sheet reference as [workbook]SheetName
75 | ///
76 | public string SheetRef
77 | {
78 | get { return string.Format("[{0}]{1}", _workbook.Name, _sheetname); }
79 | }
80 |
81 | ///
82 | /// Returns all local names
83 | ///
84 | public Name[] NamesLocal
85 | {
86 | get
87 | {
88 | var sheetRef = this.SheetRef;
89 |
90 | //get all names (local and global) for this sheet
91 | object o = XlCall.Excel(XlCall.xlfNames, sheetRef);
92 |
93 | var list = new List();
94 |
95 | if (o is object[,] names)
96 | {
97 | int n = names.GetLength(1);
98 | for (int i = 0; i < n; i++)
99 | {
100 | string name = (string)names.GetValue(0, i);
101 | string nameRef = string.Format("'{0}'!{1}", this.SheetRef, name);
102 |
103 | //find out whether name is local or not
104 | if ((bool)XlCall.Excel(XlCall.xlfGetName, nameRef, 2))
105 | list.Add(new Name(this, name));
106 |
107 | }
108 | }
109 |
110 | return [.. list];
111 | }
112 | }
113 | ///
114 | /// Returns all names for this worksheet (global and local)
115 | ///
116 | public Name[] Names
117 | {
118 | get
119 | {
120 | var sheetRef = this.SheetRef;
121 |
122 | //get all names (local and global) for this sheet
123 | object o = XlCall.Excel(XlCall.xlfNames, sheetRef);
124 |
125 | if (o is object[,] names)
126 | {
127 | int n = names.GetLength(1);
128 | Name[] res = new Name[n];
129 | for (int i = 0; i < n; i++)
130 | {
131 | string name = (string)names.GetValue(0, i);
132 | string nameRef = string.Format("'{0}'!{1}", this.SheetRef, name);
133 |
134 | //find out whether name is local or not
135 | if ((bool)XlCall.Excel(XlCall.xlfGetName, nameRef, 2))
136 | res[i] = new Name(this, name);
137 | else
138 | res[i] = new Name(this.Workbook, name);
139 | }
140 | return res;
141 | }
142 |
143 | return [];
144 | }
145 | }
146 | #endregion
147 |
148 | #region static methods
149 |
150 | public static Worksheet ActiveSheet()
151 | {
152 | var res = XlCall.Excel(XlCall.xlfGetDocument, 76);
153 | return new Worksheet((string)res);
154 | }
155 |
156 | public static string ExtractSheetName(string sheetRef)
157 | {
158 | int pos = sheetRef.IndexOf(']');
159 | return sheetRef.Substring(pos + 1, sheetRef.Length - pos - 1);
160 | }
161 |
162 | public static string ExtractWorkbookName(string sheetRef)
163 | {
164 | int pos = sheetRef.IndexOf(']');
165 | return sheetRef.Substring(1, pos - 1);
166 | }
167 |
168 | #endregion
169 |
170 | #region functions
171 |
172 | public void Select()
173 | {
174 | this.Workbook.Activate();
175 | XlCall.Excel(XlCall.xlcWorkbookSelect, new object[,] { { this.SheetRef } }, Type.Missing, Type.Missing);
176 | }
177 |
178 | public void SelectAllCells()
179 | {
180 | XlCall.Excel(XlCall.xlcSelect, SheetRef + "!1:1048576", Type.Missing);
181 | }
182 |
183 | public ExcelReference Range(string range)
184 | {
185 | object result = XlCall.Excel(XlCall.xlfEvaluate, string.Format("='{0}'!{1}", this.SheetRef, range));
186 | return result as ExcelReference;
187 | }
188 |
189 | ///
190 | /// Defines the name on the ACTIVE sheet
191 | ///
192 | ///
193 | ///
194 | ///
195 | ///
196 | public Name AddName(string name, string refersto, bool hidden = false, bool local = true)
197 | {
198 | //Check whether this is the active sheet
199 | var ws = Worksheet.ActiveSheet();
200 | if (ws.Name != this.Name) return null;
201 |
202 | //DEFINE.NAME(name_text, refers_to, macro_type, shortcut_text, hidden, category, local)
203 | bool result = (bool)XlCall.Excel(XlCall.xlcDefineName, name, refersto, Type.Missing, Type.Missing, hidden, Type.Missing, local);
204 | if (result) return new Name(this, name);
205 | return null;
206 | }
207 |
208 | public void DeleteAllCells()
209 | {
210 | ExcelDna.Utilities.Name.GetRange(this.SheetRef + "!1:1048576").DeleteEntireRows();
211 | }
212 |
213 | #endregion
214 | }
215 |
--------------------------------------------------------------------------------
/ExcelDna.Utilities/XLApp.cs:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2014 Joachim Loebb
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | */
24 |
25 |
26 | using ExcelDna.Integration;
27 |
28 | namespace ExcelDna.Utilities;
29 |
30 | public static partial class XLApp
31 | {
32 | private static bool _screenupdating = true;
33 | private static Lazy _defaultDateFormat = new(() => GetDefaultDateFormat());
34 |
35 | #region properties
36 |
37 | public static Workbook[] Workbooks
38 | {
39 | get
40 | {
41 | var list = new List();
42 |
43 | object o = XlCall.Excel(XlCall.xlfDocuments);
44 | object[,] docs = o as object[,];
45 |
46 | if (docs != null)
47 | for (int i = 0; i < docs.GetLength(1); i++)
48 | list.Add(new Workbook((string)docs.GetValue(0, i)));
49 |
50 | return list.ToArray();
51 | }
52 | }
53 |
54 | public static string DefaultDateFormat => _defaultDateFormat.Value;
55 |
56 | static string GetDefaultDateFormat()
57 | {
58 | var result = XlCall.Excel(XlCall.xlfGetWorkspace, 37) as object[,];
59 |
60 | int i = 16;
61 | string date_seperator = (string)result[0, i++];
62 | string time_seperator = (string)result[0, i++];
63 | string year_symbol = (string)result[0, i++];
64 | string month_symbol = (string)result[0, i++];
65 | string day_symbol = (string)result[0, i++];
66 | string hour_symbol = (string)result[0, i++];
67 | string minute_symbol = (string)result[0, i++];
68 | string second_symbol = (string)result[0, i++];
69 | //32 Number indicating the date order
70 | //0 = Month-Day-Year
71 | //1 = Day-Month-Year
72 | //2 = Year-Month-Day
73 | double date_order = (double)result[0, 31];
74 |
75 | day_symbol += day_symbol;
76 | month_symbol += month_symbol;
77 | year_symbol = string.Concat(year_symbol, year_symbol, year_symbol, year_symbol);
78 |
79 | if (date_order == 0)
80 | return month_symbol + date_seperator + day_symbol + date_seperator + year_symbol;
81 | else if (date_order == 1)
82 | return day_symbol + date_seperator + month_symbol + date_seperator + year_symbol;
83 | else
84 | return year_symbol + date_seperator + month_symbol + date_seperator + day_symbol;
85 | }
86 |
87 | #endregion
88 |
89 | #region Message bar
90 | ///
91 | /// Similar to excel pass an empty string to reset message bar
92 | ///
93 | ///
94 | public static void MessageBar(string message)
95 | {
96 | bool display = !string.IsNullOrEmpty(message);
97 | XlCall.Excel(XlCall.xlcMessage, display, message);
98 | }
99 |
100 | public static void MessageBar(string message, params object[] obj)
101 | {
102 | MessageBar(string.Format(message, obj));
103 | }
104 |
105 | #endregion
106 |
107 | #region calculation
108 |
109 | public static bool ScreenUpdating
110 | {
111 | set
112 | {
113 | XlCall.Excel(XlCall.xlcEcho, value);
114 | _screenupdating = value;
115 | }
116 | get
117 | {
118 | //return (bool)XlCall.Excel(XlCall.xlfGetWorkspace, 40);;
119 | return _screenupdating;
120 | }
121 | }
122 |
123 | public static xlCalculation Calcuation
124 | {
125 | get
126 | {
127 | var result = XlCall.Excel(XlCall.xlfGetDocument, 14);
128 | return (xlCalculation)(int)(double)result;
129 | }
130 | set
131 | {
132 | //get all calculation settings for the function call OPTIONS.CALCULATION
133 | object[,] result = XlCall.Excel(XlCall.xlfGetDocument, new object[,] { { 14, 15, 16, 17, 18, 19, 20, 33, 43 } }) as object[,];
134 | object[] pars = result.ToVector