Creating MS Word documents with Go OLE binding - go

I've been playing around and learning how to make Word docs programmatically. I know it can easily be done using pywin32. This simple snippet retrieves the default Visual Basic "code" inside the new Word doc.
import win32com.client
word = win32com.client.Dispatch("Word.Application")
word.Visible = True
document = word.Documents.Add()
document.VBProject.Name = "TEST"
wordModule = document.VBProject.VBComponents("ThisDocument") # WORKS
input()
You can then add VB code to wordModule.
I wanted to do the same using Golang. There is a OLE binding for Go, the code is on Github -> https://github.com/go-ole/go-ole
It's a bit less user friendly but I managed to make it work, except that I'm not able to retrieve the default VBComponents.
The default code resides in "ThisDocument" and can be retrieved with the simple python code document.VBProject.VBComponents("ThisDocument") except that, it doesn't work in Go...
You can see in the code below that I tried to get "ThisDocument" using multiple ways, without success. Each time, the error message is panic: Unknown name.
// +build windows
package main
import (
"fmt"
ole "github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
)
func main() {
defer ole.CoUninitialize()
ole.CoInitialize(0)
unknown, _ := oleutil.CreateObject("Word.Application")
word, _ := unknown.QueryInterface(ole.IID_IDispatch)
oleutil.PutProperty(word, "Visible", true)
documents := oleutil.MustGetProperty(word, "Documents").ToIDispatch()
document := oleutil.MustCallMethod(documents, "Add").ToIDispatch()
vbproject := oleutil.MustGetProperty(document, "VBProject").ToIDispatch()
oleutil.PutProperty(vbproject, "Name", "TEST")
// oleutil.MustCallMethod(vbproject, "VBComponents", "ThisDocument").ToIDispatch() --> panic: Unknown name.
// oleutil.MustGetProperty(vbproject, "VBComponents", "ThisDocument").ToIDispatch() --> panic: Unknown name.
// vbcomponents := oleutil.MustGetProperty(vbproject, "VBComponents").ToIDispatch()
// oleutil.MustGetProperty(vbcomponents, "ThisDocument").ToIDispatch() --> panic: Unknown name.
var input string
fmt.Scanln(&input)
oleutil.PutProperty(document, "Saved", true)
oleutil.CallMethod(documents, "Close", false)
oleutil.CallMethod(word, "Quit")
word.Release()
}
Any ideas on why it doesn't work?
Thanks a lot.

Turns out "github.com/go-ole/go-ole" has a bug when using ForEach. VBComponets is a Collection, so you have to iterate as stated by Microsoft doc
Use the VBComponents collection to access, add, or remove components in a project. A component can be a form, module, or class. The VBComponents collection is a standard collection that can be used in a For...Each block.
This line -> https://github.com/go-ole/go-ole/blob/master/oleutil/oleutil.go#L106
should be replace by
newEnum, err := disp.CallMethod("_NewEnum")
Now it works as intended.

Related

How to declare to variables of different datatypes in a single statement in Go [duplicate]

This question already has answers here:
Multiple variables of different types in one line in Go (without short variable declaration syntax)
(2 answers)
Closed 1 year ago.
I want to declare two variables of different datatypes(string and error) in a single statement in Go. I do not want to use the short declaration(:=) operator because I like specifying the type of the variable at declaration.
I am following a Go tutorial from the Go docs. I have a function called greetings.Hello() that I am calling from another module. The greetings.Hello() function looks like this:
package greetings
import (
"errors"
"fmt"
)
func Hello(name string) (string, error) {
// If no name was given, return an error with a message
if name == "" {
return "", errors.New("empty name")
}
// If a name was received, return a value
var message string = fmt.Sprintf("Welcome %v!", name)
return message, nil
}
So as you can see, this function returns two values(a string and an error). So ultimately, I would have to assign the result of this function to two variables in the caller. I am calling the greetings.Hello() function from a module named hello. The main function of the hello module's main package looks like this:
package main
import (
"fmt"
"log"
"creating_modules/greetings"
)
func main() {
log.SetPrefix("greetings: ")
log.SetFlags(0)
var message string, err error = greetings.Hello("")
if err !=nil {
log.Fatal(err)
}
fmt.Println(message)
}
The creating_modules/greetings is the greetings module that contains the function Hello(). Most of the gophers tackle it like this:
message, error := greetings.Hello()
But I want to declare the variables along with their datatypes in a single statement. Also the two variables should be assigned the return values of greetings.Hello(). The above mentioned main function of the hello module returns an error when it is run because of the incorrect assignment, referring to this line:
var message string, err error = greetings.Hello("")
The Go compiler returns this error when this code is run using go run:
.\hello.go:14:20: syntax error: unexpected comma at end of statement
This issue can simply be reproduced by copy-pasting the code above(note that the greetings module is a local module so you will need to set the reference path for go tools using go edit -replace)
Another thing to be noted is that my question is different from this question because that question is about declaring variables with the same data type in a single statement whereas mine is about declaring multiple variables with different data types in a single statement.
P.S i won't be surprised to know that Golang does not have this feature
declare the variables along with their datatypes in a single statement
Not possible
Supporting clause from the language spec under Variable declarations
If a type is present, each variable is given that type. Otherwise, each variable is given the type of the corresponding initialization value in the assignment. If that value is an untyped constant, it is first implicitly converted to its default type;
So something like below could work by not specifying either of the types, but you could very well use short variable declarations using := instead
var message, error = greetings.Hello()
But you can declare the variables explicitly with their type information and use the = assignment.
var message string
var err error
if message, err = greetings.Hello(""); err != nil {
log.Fatal(err)
}

Go Scanner still returns <nil>

first of all: I am totally newbie in golang, so I may not understand well.
I am tasked to write a Go data extractor from one database using "gorp". The problem is with one table, that has custom field "TimeRange".
It is defined as:
type TimeRange struct {
From string
To string
}
Sadly when I try to fetch row I am getting scanner error, so I realised I need a custom scanner.
// Scan - Implement the database/sql scanner interface
func (tr *TimeRange) Scan(value interface{}) error {
tr.From = "mis"
tr.To = "lala"
fmt.Printf("%v\n", *tr)
return nil
}
So I expect to see fixed '{mis lala}' in returned string.
Why I am getting:
var q2 []models.Dashboard
result, err := dbmap.Select(&q2, "select * from dashboard where id=3")
fmt.Printf("q2=%v\n", q2)
prints:
p2=[{{<nil> Tomek b1f6f0ba-f618-00d6-6d24-8410a9219c95}}]
which is:
TimeRange, UserName and UUID
Might be important: using "gorp" for DB managment
the scan function would be called on passed value type to dbmap.Select() so in your case, you need to implement Dashboard as scanner.

How can I access DOM Element properties from Go WebAssembly?

I'm trying to extend the "Hello WebAssembly" example from https://github.com/golang/go/wiki/WebAssembly. As given, the example simply prints a message to the console. I wanted to add some code using syscall/js to replace the body element content.
The attempt below fails to build:
package main
import (
"fmt"
"syscall/js"
)
func main() {
fmt.Println("Hello, WebAssembly!") // original example
// I added
doc := js.Global().Get("document")
body := doc.Call("getElementById", "thebody")
body.innerHTML = "Dynamic Content"
}
When I try to build with $ env GOOS=js GOARCH=wasm go build -o main.wasm
I get :
./wasm.go:14:6: body.innerHTML undefined (type js.Value has no field or method innerHTML)
Not surprising when you think about it, but I don't see an example in the doc at https://godoc.org/syscall/js that explains how to get and set element properties.
To get the value of any property of some JavaScript object, use the Value.Get() method (you actually already used it when you accessed the document object by calling js.Global().Get("document")). Similarly, to set a value of a property, use Value.Set().
The name of the property whose value to get / set is simply a Go string value, "innerHTML" in your case. The value to be set may be many of Go values (e.g. string, integer numbers, floating point numbers, bool, slices, maps etc.), the js.ValueOf() function is used to obtain a js.Value() that will be set ultimately. In your case, you may simply use the Go string value "Dynamic Content".
doc := js.Global().Get("document")
body := doc.Call("getElementById", "thebody")
body.Set("innerHTML", "Dynamic Content")

How do you run a Cypher Query on a Neo4j Database in Go?

I've been working on this problem for a few hours, and I haven't had much luck with the community Golang drivers for Neo4j.
I've attempted to run "movies-go-cq" and "neoism" examples. The movies-go-cq example doesn't work for me, it crashes when localhost:8080 is loaded in the browser.
Cypher queries on my Neo4j database with neoism only return empty/blank data. However, when I run the same query in the Neo4j browser at localhost:7474, the expected data is returned.
Here is the Go code I am running with neoism:
package main
import (
"fmt"
"github.com/jmcvetta/neoism"
)
func main() {
// Reference: https://godoc.org/github.com/jmcvetta/neoism
// Connect to the Neo4j server
db, _ := neoism.Connect("http://localhost:7474/db/data")
// Issue a query
res1 := []struct {
A string `json:"path1"` // `json` tag matches column name in query
B string `json:"path2"`
}{}
cq1 := neoism.CypherQuery{
// Use backticks for long statements - Cypher is whitespace indifferent
Statement: `
MATCH path1 = shortestPath( (plant:Plant {Term: "Vaccinium corymbosum"})-[*..5]-(gene:Gene {Description: "adenylate cyclase activating polypeptide 1"}) )
MATCH path2 = shortestPath( (gene)-[*..5]-(disease:Medical_Heading {Term: "Alzheimer Disease"}) )
RETURN path1, path2
`,
Result: &res1,
}
db.Cypher(&cq1)
r := res1[0]
fmt.Println(r.A, r.B)
}
I am considering writing my own API wrapper in Go that uses Neo4j's HTTP RESTful API if I can't get existing Go drivers to work properly; I am new to Golang, and I would be thankful for any advice for debugging Go code or tips for working with Neo4j in Golang. Thank you for your time.
I know what you are facing right now. Some time before I was facing the same issue.
There are 2 possible cases are there:-
1) You should always declare struct variable Capital.
res1 := []struct {
CAPITAL_STR1 string `json:"path1"`
CAPITAL_STR2 string `json:"path2"`
}{}
which you are doing exactly right A and B.
2) You have to paste exact json type (There is mistake)
res1 := []struct {
CAPITAL_STR1 string `json:"path1.distance"`
CAPITAL_STR2 string `json:"path2.distance"`
}{}
For getting exact json format check output json response at your Neo4J in browser. It is available under section code.

How to evaluate external go source code "dynamically"?

I need to parse a Go source code file, find a specific type (by name) and use it in my program.
I already managed to find the type I need using the go/ast package but I don't know how to "load" it into my program so that I can use it.
Question: What's the best way to extract and use a type from an external source code file and use it on runtime?
I can't think of anything except an ugly method to basically copy the file, modify it by injecting a "main" function with my encoding stuff which sends the result to stdOut, execute the it, collect the encoded data from stdout, delete the modified file.
Use case: Analyse go source code and encode the types in a specific format (e.g. json schema)
Edit:
Here is some code. The question is how to encode type allTypes (zero value) and then print it.
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"encoding/json"
)
var src string = `
package mypack
type allTypes struct{
Brands Brands
Colours Colours
}
type Brands struct{
Sony string
Apple string
}
type Colours struct{
Red string
Green string
}
`
type sometype struct{
Nothing int
}
func main() {
// src is the input for which we want to inspect the AST.
// Create the AST by parsing src.
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(fset, "src.go", src, 0)
if err != nil {
panic(err)
}
// Inspect the AST and find our function
var tp ast.TypeSpec
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.TypeSpec:
if x.Name.Name == "allTypes"{
tp = *x
}
}
return true
})
fmt.Printf("We found the type: it is %v", tp)
// Encode the zero value of sometype
x := sometype{}
b, _ := json.Marshal(&x)
fmt.Printf("\n Zero value of someType (json) %s", b)
//Next/Question: How to encode the zero value of "allTypes" ???
}
Also on playground
If I understand you are asking for dynamic type loading ala Java's Class.forName(String className). The short answer is Go doesn't support this.
The correct way, as Nick Johnson pointed out, is to parse the tree using ast, and then "generate" the JSON yourself. You will not be able to "load" the type and use JSON.Marshal. It is also worth noting that any type which supports the json.Marshaler interface may generate custom JSON. You also need to ignore, but mark optional "omitempty" behavior. This really prevents you from using the compile it and hack through "stdout" behavior as well.
If you need to extract type information at runtime, you need to use the reflect package. This is the way Go's encoding/json and other similar packages work.
If you want to operate on the types defined in a Go source file, you can use the go.parser package to read and parse a source file into an AST, then traverse the AST for the elements you want to examine.
It seems there is no way to load the type information extracted from the source code(please correct me if I'm wrong). The only solution is to create/generate a package (main), inject it with all the types extracted from the target source code file, build/compile it, execute it and collect the encoded data from stdout.

Resources