COM (ocx)の呼び出し方

## ocxのインストール

* 最新の `Windows 10` (20H1 64bit)で確認。
* ocxを使うには すでにIEでも使える状態にあること。
    * (`regsvr32.exe`で登録したが使えなかった。)
* [ [VB6] Registration-Free COM（レジストリ登録を必要としないCOM）の構成手順 ](https://note.com/codeone/n/n09c961546ff4)という方法もある様子

| 結果 | 言語 | version |
|:--:|:--|:--|
| ○ | hta | mshta.exe |
| ○ | ExcelVBA | Excel 2010 |
| ○ | HSP | 3.5 |
| ○ | ruby | rubyinstaller-2.7.1-1-x86.exe (32bit) |
| ☓ | go | go1.14.2.windows-amd64.msi |
| x | go | go1.14.2.windows-386.msi<br> (compile.exeがDefenderに誤検知される) |
| ☓ | php | 7.4.5 (32bit) |
| ☓ | vbs | cscript.exe (32bit) |
| ☓ | VB.NET | vbc.exe (/platform:x86) |
| ☓ | JScript | jsc.exe (/platform:x86) |
| ☓ | python3 | python-3.8.3rc1.exe (32bit) |

## 成功したもの

### ○ hta

```html:ocx.hta
<object ID="Sample" CLASSID="clsid:00000000-0000-0000-0000-000000000000"></object>
<script>
alert(Sample.Version());
</script>
```

### ○ VBA

```vb:Excel
Sub aa()
    Set t = CreateObject("Sample.SampleCtrl.1")
    MsgBox t.Version
End Sub
```

### ○ HSP

```c:ocx.hsp
axobj ocx, "Sample.SampleCtrl.1", 300, 300
mes ocx("Version")
```


### ○ ruby

* 今回、MSYSはインストール不要。

```rb:ocx.rb
require 'win32ole'

ocx = WIN32OLE.new("Sample.SampleCtrl.1")
ocx.ole_activex_initialize
p ocx.Version()
```

```rb:show_methods.rb
# メソッド一覧を表示
require 'win32ole'

ocx = WIN32OLE.new("Sample.SampleCtrl.1")
p ocx.ole_methods
```


----

## 失敗したもの (致命的エラー)

### ☓ go

`go get github.com/go-ole/go-ole`

```go:ocx.go
package main

import (
	ole "github.com/go-ole/go-ole"
	"github.com/go-ole/go-ole/oleutil"
)

func main() {
	ole.CoInitialize(0)
	unknown, _ := oleutil.CreateObject("Sample.SampleCtrl.1")
	ocx, _ := unknown.QueryInterface(ole.IID_IDispatch)
	oleutil.MustCallMethod(ocx, "Version", nil).ToIDispatch()
}
```


### ☓ php

```php:ocx.php
<?php
//$ocx = new COM("{00000000-0000-0000-0000-000000000000}");
$ocx = new COM("Sample.SampleCtrl.1");

# false
var_dump(method_exists($ocx, "Version"));

echo "<pre>";

# 一覧は表示されるが..
com_print_typeinfo($ocx);

# 致命的エラー
//$ocx->Version;
```

### ☓ vbs

```vb:ocx.vbs
Set ocx = CreateObject("Sample.SampleCtrl.1")
MsgBox ocx.Version
```


### ☓ VB.NET

```js:ocx.vb
Public Module HelloWorld
  Public Sub Main()

    Dim ocx As Object
    ocx = CreateObject("Sample.SampleCtrl.1")
    Console.WriteLine(ocx.Version())

  End Sub
End Module
```

```sh
vbc.exe /platform:x86 ocx.vb

ocx.exe
# ハンドルされていない例外: System.Runtime.InteropServices.COMException: 致命的なエラーです。 (HRESULT からの例外:0x8000FFFF (E_UNEXPECTED))
#    場所 Microsoft.VisualBasic.CompilerServices.LateBinding.LateGet(Object o, Type objType, String name, Object[] args, String[] paramnames, Boolean[] CopyBack)
#    場所 Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateGet(Object Instance, Type Type, String MemberName, Object[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean[] CopyBack)
#    場所 HelloWorld.Main() 
```

### ☓ JScript

```js:ocx.js
var ocx = CreateObject("Sample.SampleCtrl.1")
print(ocx.Version())
```

```sh
jsc.exe /platform:x86 ocx.js

ocx.exe
# ハンドルされていない例外: System.Runtime.InteropServices.COMException: 致命的なエラーです。 (HRESULT からの例外:0x8000FFFF (E_UNEXPECTED))
#    場所 Microsoft.JScript.LateBinding.Call(Object[] arguments, Boolean construct, Boolean brackets, VsaEngine engine)
#    場所 JScript 0.Global Code()
#    場所 JScript Main.Main(String[] )
```

### ☓ python3

```go
pip install pywin32
```

```py
import win32com.client
app = win32com.client.Dispatch("Sample.SampleCtrl.1")

# <bound method Version of <COMObject Sample.SampleCtrl.1>>
print (app.Version)

# 致命的エラー
print (app.Version())
```

----

## その他

* ocx は VB6.0 の時代に作られたもの。通常32bit専用。
* IEのアドオンの管理から該当の拡張機能を`有効 → 無効`にしても、hta から利用ができた。この設定は見ていない様子。