Skip to content

Commit

Permalink
JuliaFlagFile and JuliaExpressionFile now Private
Browse files Browse the repository at this point in the history
  • Loading branch information
PGS62 committed Dec 2, 2021
1 parent 6aa2dec commit 1d5eb84
Show file tree
Hide file tree
Showing 9 changed files with 280 additions and 249 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "JuliaExcel"
uuid = "661490ff-676f-49f7-9f60-bdb0e4e6656a"
authors = ["Philip Swannell"]
version = "0.2.2"
version = "0.2.3"

[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Expand Down
46 changes: 35 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,19 @@ The process is illustrated in the GIF below. F5 to replay.
## Functions
JuliaExcel makes the following functions available from Excel worksheets and from VBA:


|Name|Description|
|----|-----------|
|[JuliaLaunch](#julialaunch)|Launches a local Julia session which "listens" to the current Excel session and responds to calls to JuliaEval etc..|
|[JuliaInclude](#juliainclude)|Load a Julia source file into the Julia process, to make additional functions available via JuliaEval and JuliaCall.|
|[JuliaEval](#juliaeval)|Evaluate a Julia expression and return the result to an Excel worksheet.|
|[JuliaCall](#juliacall)|Call a named Julia function, passing in data from the worksheet.|
|[JuliaSetVar](#juliasetvar)|Set a global variable in the Julia process.|
|[JuliaEvalVBA](#juliaevalfromvba)|Evaluate a Julia expression and return the result to VBA. Tuned for use from VBA rather than a worksheet.|
|[JuliaCallVBA](#juliacallfromvba)|Call a named Julia function from VBA code. Tuned for use from VBA rather than a worksheet.|
|[JuliaEvalVBA](#juliaevalvba)|Evaluate a Julia expression from VBA . Differs from JuliaCall in handling of 1-dimensional arrays, and strings longer than 32,767 characters. May return data of types that cannot be displayed on a worksheet, such as a dictionary or an array of arrays.|
|[JuliaCallVBA](#juliacallvba)|Call a named Julia function from VBA. Differs from JuliaCall in handling of 1-dimensional arrays, and strings longer than 32,767 characters. May return data of types that cannot be displayed on a worksheet, such as a dictionary or an array of arrays.|
|[JuliaResultFile](#juliaresultfile)|Returns the name of the file to which the results of calls to JuliaCall, JuliaEval etc. are written. The file may be unserialised with `JuliaUnserialiseFile`.|
|[JuliaUnserialiseFile](#juliaunserialisefile)|Unserialises the contents of the JuliaResultsFile.|


## Demo
Here's a quick demonstration of the functions in action.
Expand Down Expand Up @@ -78,19 +82,20 @@ End Sub
#### _JuliaLaunch_
Launches a local Julia session which "listens" to the current Excel session and responds to calls to `JuliaEval` etc..
```vba
Function JuliaLaunch(Optional MinimiseWindow As Boolean, Optional ByVal JuliaExe As String)
Function JuliaLaunch(Optional MinimiseWindow As Boolean, Optional ByVal JuliaExe As String, _
Optional ByVal CommandLineOptions As String)
```

|Argument|Description|
|:-------|:----------|
|`MinimiseWindow`|If TRUE, then the Julia session window is minimised, if FALSE (the default) then the window is sized normally.|
|`JuliaExe`|The location of julia.exe. If omitted, then the function searches for julia.exe, first on the path and then at the default locations for Julia installation on Windows, taking the most recently installed version if more than one is available.|

|`CommandLineOptions`|Command line switches to be set when launching Julia.<br/>Example : `--threads=auto --banner=no`.<br/>https://docs.julialang.org/en/v1/manual/command-line-options/|

#### _JuliaInclude_
Load a Julia source file into the Julia process, to make additional functions available via `JuliaEval` and `JuliaCall`.
```vba
Function JuliaInclude(FileName As String)
Public Function JuliaInclude(FileName As String)
```

|Argument|Description|
Expand All @@ -112,15 +117,14 @@ Function JuliaEval(ByVal JuliaExpression As Variant)
#### _JuliaCall_
Call a named Julia function, passing in data from the worksheet.
```vba
Function JuliaCall(JuliaFunction As String, ParamArray Args())
Public Function JuliaCall(JuliaFunction As String, ParamArray Args())
```

|Argument|Description|
|:-------|:----------|
|`JuliaFunction`|The name of a Julia function that's defined in the Julia session, perhaps as a result of prior calls to `JuliaInclude`.|
|`Args...`|Zero or more arguments. Each argument may be a number, string, Boolean value, empty cell, an array of such values or an Excel range.|


#### _JuliaSetVar_
Set a global variable in the Julia process.
```vba
Expand All @@ -133,7 +137,7 @@ Function JuliaSetVar(VariableName As String, RefersTo As Variant)
|`RefersTo`|An Excel range (from which the .Value2 property is read) or more generally a number, string, Boolean, Empty or array of such types. When called from VBA, nested arrays are supported.|

#### _JuliaEvalVBA_
Evaluate a Julia expression and return the result to VBA. Designed for use from VBA rather than a worksheet and differs from `JuliaEval` in handling of 1-dimensional arrays, nested arrays and strings longer than 32,767 characters.
Evaluate a Julia expression from VBA . Differs from `JuliaCall` in handling of 1-dimensional arrays, and strings longer than 32,767 characters. May return data of types that cannot be displayed on a worksheet, such as a dictionary or an array of arrays.
```vba
Function JuliaEvalVBA(ByVal JuliaExpression As Variant)
```
Expand All @@ -142,17 +146,37 @@ Function JuliaEvalVBA(ByVal JuliaExpression As Variant)
|:-------|:----------|
|`JuliaExpression`|Any valid Julia code, as a string. Can also be a one-column range to evaluate multiple Julia statements.|


#### _JuliaCallVBA_
Call a named Julia function from VBA code. Designed for use from VBA rather than a worksheet and differs from `JuliaCall` in handling of 1-dimensional arrays, nested arrays and strings longer than 32,767 characters.
Call a named Julia function from VBA. Differs from `JuliaCall` in handling of 1-dimensional arrays, and strings longer than 32,767 characters. May return data of types that cannot be displayed on a worksheet, such as a dictionary or an array of arrays.
```vba
Function JuliaCallVBA(JuliaFunction As String, ParamArray Args())
Public Function JuliaCallVBA(JuliaFunction As String, ParamArray Args())
```

|Argument|Description|
|:-------|:----------|
|`JuliaFunction`|The name of a Julia function that's defined in the Julia session, perhaps as a result of prior calls to `JuliaInclude`.|
|`Args...`|Zero or more arguments. Each argument may be a number, string, Boolean value, empty cell, an array of such values or an Excel range.|

#### _JuliaResultFile_
Returns the name of the file to which the results of calls to `JuliaCall`, `JuliaEval` etc. are written. The file may be unserialised with function `JuliaUnserialiseFile`.
```vba
Public Function JuliaResultFile() As String
```

#### _JuliaUnserialiseFile_
Unserialises the contents of the JuliaResultsFile.
```vba
Public Function JuliaUnserialiseFile(Optional ByVal FileName As String, Optional ForWorksheet As Boolean = True)
```

|Argument|Description|
|:-------|:----------|
|`FileName`|The name (including path) of the file to be unserialised. Optional and defaults to the file name returned by JuliaResultsFile.|
|`ForWorksheet`|Pass TRUE (the default) when calling from a worksheet, FALSE when calling from VBA. If FALSE, the function may return data structures that can exist in VBA but cannot be represented on a worksheet, such as a dictionary or an array of arrays.|



## Marshalling
Two question arose during implementation:

Expand Down Expand Up @@ -209,7 +233,7 @@ JuliaExcel has been tested on Excel under Microsoft 365, both 32-bit and 64-bit.

## How JuliaExcel works
The implementation of JuliaExcel is very "low-tech". When `JuliaEval` is called from a worksheet, the following happens:
1) VBA code (in JuliaExcel.xlam) writes the expression to a file in the JuliaExcel sub-folder of the temporary folder.
1) VBA code (in JuliaExcel.xlam) writes the expression to a file in the `@JuliaExcel` sub-folder of the temporary folder.
2) VBA code then uses the Windows API `PostMessage` to send keystrokes `srv_xl()` to the Julia window.
3) That causes the Julia function `srv_xl` (defined in JuliaExcel.jl) to execute. The function reads the expression from file, evaluates it and writes to a result file.
4) The VBA code (in a wait loop since step 1) detects that the result file has been (completely) written, and unserialises its contents.
Expand Down
16 changes: 13 additions & 3 deletions src/JuliaExcel.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module JuliaExcel
export srv_xl, setxlpid
export srv_xl, setxlpid, killflagfile

using Dates, DataFrames
import StringEncodings
Expand Down Expand Up @@ -39,7 +39,17 @@ localtemp() = joinpath(ENV["TEMP"], "@JuliaExcel")
flagfile() = joinpath(localtemp(), "Flag_$(getxlpid()).txt")
resultfile() = joinpath(localtemp(), "Result_$(getxlpid()).txt")
expressionfile() = joinpath(localtemp(), "Expression_$(getxlpid()).txt")

#=If things go wrong then Excel is locked up until either Julia exits or the flag file is
deleted, so make a function availble to do the latter (mainly for use when debuggingh).
=#
function killflagfile()
if isfile(flagfile())
rm(flagfile())
"File $(flagfile()) deleted"
else
"File $(flagfile()) not found"
end
end
"""
read_utf16(filename::String)
Returns the contents of a UTF-16 encoded text file that has a byte option mark.
Expand Down Expand Up @@ -76,7 +86,7 @@ function srv_xl()
write(io, StringEncodings.encode(encodedresult, "UTF-16"))
close(io)

isfile(flagfile()) && rm(flagfile())
killflagfile()
println(truncate(expression))
display(result)
canencode || (println("");@error "Result of type $(typeof(result)) could not be " *
Expand Down
3 changes: 2 additions & 1 deletion vba/JuliaExcel-Documenter.xlsm/AuditSheetComments.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Version Date Time Author Comment
22 01-Dec-2021 18:49 Philip Swannell Cope with funcitons with zero arguments. The code in this workbook is shamefully hacky.
23 02-Dec-2021 17:46 Philip Swannell Refreshed.
22 01-Dec-2021 18:49 Philip Swannell Cope with functions with zero arguments. The code in this workbook is shamefully hacky.
21 17-Nov-2021 12:28 Philip Swannell Function name changes: FromVBA --> VBA
20 15-Nov-2021 17:38 Philip Swannell Have ditched JuliaCall2 and argument PrecedentCell to the other functions.
19 15-Nov-2021 10:23 Philip Swannell Renamed to JuliaExcel-Documenter.
Expand Down
4 changes: 4 additions & 0 deletions vba/JuliaExcel.xlam/AuditSheetComments.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
Version Date Time Author Comment
73 02-Dec-2021 17:26 Philip Swannell Re-ordered methods in modMain.
72 02-Dec-2021 17:16 Philip Swannell Documentation only.
71 02-Dec-2021 17:02 Philip Swannell Changes to code to register functions with intellisense.
70 02-Dec-2021 16:52 Philip Swannell Made functions JuliaFlagFile and JuliaExpressionFile be Private.
69 01-Dec-2021 18:53 Philip Swannell Improved docstrings.
68 01-Dec-2021 15:42 Philip Swannell Changed return from LocalTemp so that files are now saved at C:\Users\<UserName>\AppData\Local\Temp\@JuliaExcel\
67 01-Dec-2021 15:23 Philip Swannell Fix to JuliaUnserialiseFile.
Expand Down
Loading

0 comments on commit 1d5eb84

Please sign in to comment.