2024年11月27日水曜日

Excel VBA 備忘録 テクニック編

・画面表示を更新せずプログラムを実行する方法
    Rem 画面更新停止
    Application.ScreenUpdating = False
    Rem 画面更新再開
    Application.ScreenUpdating = True

・Me = 実行中のモジュールを示す変数
    MSのドキュメント「Me キーワード」 より抜粋

Meキーワード (keyword) は、暗黙的に宣言された変数のように動作します。 クラス モジュール内のすべてのプロシージャで自動的に使用できます。

クラスに複数のインスタンスが含まれる可能性がある場合、Me を使用して、コードが実行されているクラスの特定のインスタンスを参照できます。 現在実行されているクラスのインスタンスに関する情報を別のモジュール内のプロシージャに渡す場合、Me を使用すると特に便利です。

    例:実行中のWorksheetの名前の取得
        MsgBox Me.Name

 

2024年8月9日金曜日

X68030の電源 SH4 のATX化、バックアップ充電池交換

長年眠っていた X68030 本体と関連グッズを手放すことにし、動作チェックを行っていましたが、電源が故障してしまいました。電源を取り外し、コンデンサなどの部品を順次取り換えてみましたがなかなか手ごわく、復活しません。

いろいろ調べてみるとX680x0の電源SH4のATX化がいくつか見つかり、試してみたところ、おかげさまで起動することができるようになりました。

まずはお礼を兼ねて、丁寧な図を載せてくださったmojiraさんのサイトをご紹介。
作成手順はこちらのサイトをご覧ください。

X68000電源換装
http://mojira68.blog24.fc2.com/blog-entry-1.html

類似の製品がbeep-shopなどで販売されてるようですが、品切れ状態が続いているので私も自作することにしました。

これは以前に満開製作所が作ったATX/SH4変換ケーブルがもとなっているようです。電源自体は対応する電圧どうしを繋ぐだけですが、ATXのPower Onのシグナルが負(GND)に対し、SH4は正(+)状態と反対なため、ロジックICで反転させています。これによりX68030 本体のスイッチで電源ON/OFFが行えます。

X68030 は電源スイッチをOFFにしたあと、フロッピーの状態のチェックなどを行ってから電源が切れます。この間LEDが点滅しますが、これもちゃんと行われます。

手っ取り早く代用品が必要な場合は、SH4とATXで対応する電圧の線を繋ぎ、ATXのPower OnをGNDにつなげば使えるかもしれませんが、乱暴な電源ON/OFFは本体にダメージを与えかねません。ロジックIC(7404)が入手できるなら先人の成功例に倣うのがよいでしょう。

最初、電源ON後にちょっとだけフロッピードライブの動作音がしたあとディスクを読みにいきませんでした。フロッピーディスクドライブのフラットケーブルはSCSIモジュール経由で本体底面に差しますが、右タワー用の二極コネクタを穴を通して渡すときに抜けてしまっていました。動作確認のときはコネクタが全部繋がっているか、確認しましょう。

とりあえずは元の電源のケーブルを利用して作成しましたが、元の電源も修理したかったのでコネクタ類を調達し、作成し直しました。

以下、調達した部品のまとめです。
価格は2024年7月時点で、税抜、税込混在していますので、目安とお考え下さい。

ATX電源
200Wの小ぶりなSFX電源でも動作しました。ただし、私のX68030にはハードディスクがありません。

DELTA ERECTONICS, INC. DPS-200PB
メルカリで中古1,200円で購入。サーバから取り外した電源とのことで、そのためかいささか音が大きい。継続的に使用するにはファンの交換が必要でしょう。

IN WIN POWER MAN IP-P300DF1-0
所持していたので試しました。こちらは300Wで音も静かです。

mojiraさんの記事では20ピンのATX電源ですが、もちろん24ピンでもかまいません。私はフロッピードライブ用の3本を追加の4ピンの方とつなぎました。

ちなみにATX電源には同じ電圧のピンがいくつもありますが、回路別に電流を分散させるのが目的で、根っこは同じところにつながっているようです。

ATXコネクタ
SH4代用電源専用とするなら直接線どうしを接続してしまうこともできますが、そうすると移動するときに本体と外部電源を一緒に運ばなければいけません。やはりコネクタを付けた方がよいでしょう。

ATX電源側がオスなので、メスのコネクタが必要です。
mojiraさんと同じく、ATXオスメス変換ケーブルを購入しました。
Amazonで400円前後で購入できます。

6ピンコネクタ 3.96mmピッチ
同じ形状のものが通販で見つかりました。後述の山本無線でも扱っていました。

若松通商 VHR-6N 40円 (コンタクトピン付き)
共立エレショップ  VHR-6N 16円 (コンタクトピン別)

2ピンコネクタ 3.96mmピッチ
右タワー用の5V電源用。
秋葉原駅前ラジオセンター2Fの山本無線電材店で同じ形状のものが見つかりました。

モレックス 5195-02 50円
コンタクトピン モレックス 5194TL 15円/本

型番が分かるとMarubeni Online Shopで通販でも購入できるのがわかりましたが、その前に試しに似たものを購入しました。一応代用にはなります。ただし、+-を差し間違えないよう気を付けましょう。

若松通商 VHR-2N 26円 (コンタクトピン付き)
共立エレショップ  VHR-2N 11円 (コンタクトピン別売)

3ピンコネクタ 2.5mmピッチ 
コンタクトピンの仕様が異なりますが、サイズ、ピッチが同じものが山本無線電材店にありました。

AMP171822-3 50円 コンタクトピン別売 

試しに購入したものはちょっと小さくお薦めできませんが、とりあえず動作確認は行えました。これも+-を差し間違えないよう気を付けましょう。

共立エレショップ  EHR-3 11円 (コンタクトピン別売)

ロジックIC 7404
汎用の7404を購入しました。

若松通商 M53204P (7404) 64円

------------------------------------------------------

ATX電源で本体の動作が確認電できたところで、SH4電源の修理を再開したところ、どの部品が決め手になったのかわかりませんが、修理に成功しました。

なにぶん素人なもので部品全取り換えまでは行わず、電解コンデンサ、ツェナーダイオードと、問題ありそうな部分だけ取り換えています。

問題部分を探すのに、Kunihiko Ohnakaさんの
X68000シリーズ電源の部品面から見た抵抗配置図https://drive.google.com/file/d/1aXbfzF_zwfEswQ6yfBAbI7jxxhpNHxB6/view
が役立ちました。

「部品実装状態での実測値」を見ながら測定したところ、R37が絶縁状態になっていたのと、R4が怪しい値でした。おかしくなるには理由があるわけで、その周辺の部品を交換しています。どの部品が問題だったかまでは突き止めていませんが、ZD32、D33、D35などを交換しています。

SH4電源修理のためにコンデンサ、抵抗、ダイオード等のセットをメルカリで購入しましたが、それに含まれていなかったものを探しました。

[]内の名称は配線図の部品番号と部品名です。
なお、互換性は私個人の判断ですので、保証の限りではありません。

ツェナーダイオード
[ZD51 HZS15-1L] 
HZ15-1, HZ15-1TA 14.1~14.7 500mW 若松通商 53円

FET
[Q1 2SK643/2SK724/2SK735]
2SK735 若松通商 481円

------------------------------------------------------

ついでながら、ディスプレイケーブルのDsub15ピン2列を3列のRGBケーブルに変換することも試しました。通販で部品と取り寄せるとき、送料の方が部品代より高くついてしまうので、ついでに買うものはないかとディスプレイのコネクタも追加したからです。

RGBケーブルが一本余っていたので、これのコネクタ部分を切り離し、2列のコネクタに接続しました。

X68030はVキーを押しながら起動すると640x480モードになります。線を繋ぎ替えるだけで液晶ディスプレイへ表示することができました。

Dsub15ピン2列のアナログディスプレイケーブルと3列のRGBケーブルのピンアサインの対照は次のようなWebページに載っています。

VGAケーブルを作って見た。(2列←→3列 D-SUB15ピン)
http://rdstyle.cocolog-nifty.com/gm/2020/02/post-3324c0.html#google_vignette

VGA端子のピンアサインと形状
https://ameblo.jp/holycater/entry-12467338511.html

既製品のRGBケーブルは製品により配線の具合が異なるようです。私が使ったのものは6,7,8ピンのRGBのGRDがケース、シールド線と接続されており、線としては出ていません。RGB信号線が個別にアルミ箔でシールドされ、その中に細い線が一本はいっており、これがGNDと接続されています。そこで、この細い線を2列コネクタRGB GNDに接続しました。これらはみなGRDとどこかで接続されています。シールド線は2列コネクタのケースに接続しました。これで液晶ディスプレイに表示できました。

私の場合の配線の対応は次のようになりました。

3列             2列
1                1
1GRD          2
2                3
2GRD          4
3                4
3GRD          5
13               14
14               15
シールド        ケース

ただ、解像度が640x480なので横長ディスプレイは使い勝手はよくありません。ブラウン管ディスプレイが壊れたときの緊急対応用に保管しておきます。

------------------------------------------------------

一難去ってまた一難で、フロッピーディクドライブが不調になりました。

「システムを起動できませんでした。リセットして下さい。」
「エラーが発生しました。リセットして下さい。」

などが発生します。ドライブを取り外してグリスを塗ったりしていたので、何か悪さをしてしまったかた、再度チェック。さらに分解するとかえってとりかえしのつかない状態になりそうなので、いったん諦める。

いろいろ調べると、SRAMのバックアップ電池が切れているとこの症状がでるそうでそれを交換したら直ったという記事を見つけました。

SHARPパソコン X68000 EXPERT-HDのバックアップ電池交換http://kanchan707.web.fc2.com/X68KBATT.htm

X68030の底蓋を外してメインボードを取り出し、バッテリーをとりはずします。バッテリーの型はPanasonicのVL-1220/HFK。これとズバリ同じものはがみつからず、端子タイプが異なるVL-1220/VFKをAmazonで購入。ただいま到着を待っています。AliExpressにVL-1220/HFKがあるにはあったのですが、値段も安くなく到着がいつになるかわからなのでやめておきました。

ちなみにML-1220というのもありますが、VLがバナジウムリチウム二次電池に対し、MLはマンガンリチウム二次電池で、仕様を見ると出力電圧はどちらも3Vですが充電電圧が異なります。発火の原因になるといけないので、MLで代用するのはやめた方がよさそうに思います。

さて、バッテリーが届いたのでさっそく交換する。端子タイプが縦型だが、折り曲げるとうまい具合に穴にはいった。

交換後すぐは以前と同じ状態が発生。これで諦めるのはつらいので、再度ドライブを取り外してコネクタをしっかりはめ直してみる。おお、起動した!

バッテリーの交換が功を奏したのか、コネクタの接続が甘かったのか定かではないが、いずれにせよ古いバッテリーは電圧が0.3Vくらいで寿命が尽きていたので、交換が必要だったのは間違いない。



2024年6月2日日曜日

Windows 11 Excel VBA で InternetExplorerが使えなくなったことへの対応

Excel VBAでこれまで使えていた InternetExplorerがWindows 11で使えなくなりました。(と思ったら、また使えるようになっていた。よくわからないが、いずれは使えなくなる前提でコーディングしておいた方がよいでしょう。)

Excelはサポート切れの2010と、ちと古いです。

ちょっと調べると、代替え策としてフォームのWebBrowserを使う方法が出てきます。Navigateでurlのページを表示するだけならこれが良さそうです。ですが、DOMのメソッドを使って操作する場合、使えないメソッドがいくつかあります。たとえば

でエラーが発生します。他にも使えないメソッドがあるかもしれません。

これへの解決策として、次のコードのようにDocument.Allを使って全エレメントを取得し、個々にnameやclassNameをチェックする方法が出てきます。

    Dim elm As HtmlElement     For Each elm In WebBrowser1.Document.All I       if elm.GetAttribute("className") = "someName" Then             Debug.Printh elm.InnerText         End If     Next

これは単発で使うには十分かと思いますが、ループで使用するにはいささか重い処理になりそうで、検討の余地ありです。加えてclassには複数の値が設定されることが多く、"="での比較はほとんど場合に不適切でしょう。

ちなみに、「このページのスクリプトでエラーが発生しました」が発生する場合は、navigateを呼ぶ前に次の行を追加します。

    WebBrowser1.Silent = True     

次に見つけたのはMSXML2.XMLHTTPを使う方法です。次のようなコードでXmlDocumentを作ります。

    Dim MyRequest As Object     Set MyRequest = CreateObject("MSXML2.XMLHTTP")     MyRequest.Open "GET", url     MyRequest.send     Do Until MyRequest.readyState = 4: DoEvents: Loop     Set xmldoc = MyRequest.responseXML

これで成功する場合は良さそうですが、これは TLS 1.2 以上には対応していないという問題があるようです。次のようにするとよいという指摘があります。

    Set MyRequest = CreateObject("MSXML2.ServerXMLHTTP")

私は MSXML2.XMLHTTP.6.0 を使いましたが、今のところ問題ありません。

    Set MyRequest = CreateObject("MSXML2.XMLHTTP.6.0")

なお、MSXML2.XMLHTTP.6.0 でエラーが出る場合は参照を追加します。

    ツール⇒参照設定⇒Microsoft XML v6.0追加

    その他、次のライブラリ参照も必要です。
    Microsoft HTML Object Library
    Microsoft VBScript Regular Expressions 5.5

さらに調べた結果、次の方法が見つかりました。これはHTMLをDOMDocumentとして取得し、それからHTMLDocumentを作ります。

次のFunctionを作り、実際に使用しています。

Public Function GetHTMLDoc(url As String)     Dim httpReq As Object     Set httpReq = CreateObject("MSXML2.XMLHTTP.6.0")     httpReq.Open "GET", url, False     httpReq.send (Null)     Do Until httpReq.readyState = 4: DoEvents: Loop     Dim htmlDoc As IHTMLDocument     Set htmlDoc = New HTMLDocument     htmlDoc.Write httpReq.responseText     Set GetHTMLDoc = htmlDoc End Function

この方法はWebページを表示する必要がなく、DOMメソッドで操作するのが目的な場合に適しています。表示を行わないため、処理は高速です。表示も必要な場合は、WebBrowerにHTMLをセットすればよいでしょう。

さて、これで作った HTMLDocument ですが、ちょっと奇妙な動きをします。

htmlDoc.GetElementsByClassName(className)

は動作します。(先頭の"G”は大文字です。)

ですが、個々の HtlmElement には getElementsByClassName を適用できません。

この範囲で十分であれば、従来のIEと同様の方法で利用することができます。

ですが、ある Element の子要素から getElementsByClassName で要素抽出をしたい場合には処理が複雑になります。

そこで、次のようなFunctionを作りました。あるエレメント内の指定のtagNameのものからclassNameを含むものを抽出します。

Public Function GetElementsByClassName(htmlElm As IHTMLElement, tagName As String, className As String)     Dim elm As Object, attr As String, list As Collection     Dim re As New RegExp: re.pattern = "(^| )" & className & "( |$)"     Set list = New Collection     For Each elm In htmlElm.getElementsByTagName(tagName)         If re.test(elm.getAttribute("className")) Then             list.Add elm         End If     Next     Set GetElementsByClassName = list End Function

正規表現はclass属性の最初、または最後か、前後がスペースで区切られているものとマッチします。

    re.pattern = "(^| )" & className & "( |$)" 

戻り値の型はCollectionになります。インデックスを使う場合、配列と異なり先頭の要素のインデックスは 1 になることに注意してください。

加えて、次のようなFunctionも作りました。私の場合、getElementsByClassNameで見つかった最初の要素を使うことが多く、IEを使った処理では次のようなコードでした。

    name = someElm.getElementsByClassName("name")(0).innerText

そこで、Collectionで返さず最初に見つかった要素を返すようにしました。

Public Function GetFirstElementByClassName(htmlElm As IHTMLElement, tagName As String, className As String)     Dim elm As Object, val As String     Dim re As New RegExp: re.pattern = "(^| )" & className & "( |$)"     For Each elm In htmlElm.getElementsByTagName(tagName)         If re.test(elm.getAttribute("className")) Then             Set GetFirstElementByClassName = elm             Exit Function         End If     Next     Set GetFirstElementByClassName = Nothing End Function  

呼び出し方は次のようになります。

    name = GetFirstElementByClassName(someElm, "div",  "name").innerText

戻り値がNothingとなる場合があるなら、次のようなチェックを入れます。

    Set elm = GetFirstElementByClassName(someElm, "div",  "name")     If Not elm Is Nothing Then name = elm.innerText

HtmlDocumentの先頭からclassNameのものを探したい場合は htmlDoc.body または htmlDoc.DocumentElement を htmlElm として渡します。

    divs = GetElementsByClassName(htmlDoc.body, "div",  "someClass")

私の場合はclassNameでエレメントを抽出する場合はtagNameも決まっているのでこの方が都合がよく、かつ処理速度も多少なりとも速くなっているだろうと思います。

もし異なるtagNameのものも含めて抽出したい場合は、たとえばtagNameにvbNullStringを渡し、次のような使い分けをすればよいでしょう。

    Dim elms as IHTMLElementCollection
    If tagName = vbNullString Then
        Set elms = htmlElm.all
    Else
        Set elms = htmlElm.getElementsByTagName(tagName)
    End If

結果的にはWebBrowserによる表示が不要なため、この変更で処理速度は格段に速くなりました。

補足

この例で生成する HtmlDocument にはいくつか制約があります。

・sectionなど非対応のtagがあり、その場合はHTMLUnknownElementとなり、単独のElementとして作られるがDOM構造には含まれず、getElementsByTagName、allなどのメソッド/プロパティーが使用できない。

原因ははっきりしませんが、フリーズすることがありました。速度が速くなりすぎ、Excelの再描画追いつかないためかもしれません。そんなときは再描画の一時中止/再開を試してみてください。  

    Application.ScreenUpdating = False         再描画が発生する処理     Application.ScreenUpdating = True 

 

2024年5月26日日曜日

Mac インストールUSBドライブ作成エラー ...app does not appear to be a valid OS installer application.

Webページ https://support.apple.com/ja-jp/101578 を参照し、
Macbool Air 2011 A3169 用に High Sierra のインストールUSBドライブを作成しようとしたらエラーが発生。

Webページ「ターミナルを使って起動可能なインストーラを作成する」に記載されているHigh Sierra用のコマンドをそのままコピペ(MyVolumeは適宜変更)でターミナルで実行するとエラーが出る。

コマンド
sudo /Applications/Install\ macOS\ High\ Sierra.app/Contents/Resources/createinstallmedia --volume /Volumes/MyVolume

エラー
/Applicaiont/macOS\ High\ Sierra.app does not appear to be a valid OS installer application.

これは日本語環境でAppStoreからインストーラをダウンロードするとインストーラの名前が

Install macOS High Sierra.app

ではなく

Install macOS High Sierraインスール.app

となり、異なっているため。どうも"Install macOS High Sierra.app”という名前をチェックしているようなので、ファイル名を英語表記に合わせて変更しないとダメなようだ。

MyVolumeは実際のターゲットのマウントポイント名に変更するが、実際のマウントポイントが表示名と異なることがある。この場合は見た目は一致していてもマウントポイントが見つからないというエラーが出る。

ディスクユーティリティーでUSBドライブのプロパティーを見て、コマンドのMyVolumeをマウントポイントに一致させる。

あるいはディスクユーティリティーでUSBドライブを消去し、名前を”MyVolume”でフォーマットすればコマンドはそのままでよい。

MyVolumeは createinstallmedia 実行後に既定の名前に変更される。










2024年4月7日日曜日

C# FormアプリでMicrosoftのライブラリだけでheic画像表示

WPFではサポートされてもFormアプリでは使えない機能があります。

Imageのheic対応もそのひとつで、次のようなコードでheicファイルを表示しようとするとメモリ不足のエラーが発生します。

pictureBox1.Image = Image.FromFile(mediaItem.FilePath);

Webでheic表示関連を検索するとMagick.NETを使う例が見つかりますが、Microsoftのライブラリだけで行う方法はまだ見つかりませんでした。Magick.NETは様々なフォーマットを扱える優れたものだと思いますが、dllをアプリに含めると、小さいなアプリでは本体よりMagick.NETの方が大きくなってしまいます。heicサポートの追加だけが目的な場合はあまり好ましくないので、Microsoftのライブラリだけで行う方法をいくつか試してみました。

なお、前提としてWindows 10, 11にHEIF画像拡張をインストールしてあるものとします。HEIF画像拡張がインストールされていない場合はMicrosoft Store から ダウンロードできます。

方法1
BitmapImage
BitmapEncoderを使用する。
今のところ、これが一番良好な結果になっています。
次のようなステップで行います。

System.Windows.Media.Imaging.BitmapImageをファイルから作る。BmpBitmapEncoderでMemoryStreamに書き出す。
MemoryStreamからSystem.Drawing.Imageを作る。
pictureBox1.Imageにセットする。

コードは次のようになります。

            BitmapImage bImage = new BitmapImage();
            bImage.BeginInit();
            bImage.CacheOption = BitmapCacheOption.None;
            bImage.DecodePixelHeight = height;
            bImage.DecodePixelWidth = width;
            bImage.UriSource = new Uri(FilePath, UriKind.Absolute);
            bImage.EndInit();
            using (MemoryStream ms = new MemoryStream())
            {
                BitmapEncoder enc = new BmpBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(bImage));
                enc.Save(ms);
                pictureBox1.Image = Image.FromStream(ms);
            }

ひとつの静止画を扱うなら、これで十分でしょう。イメージのサイズを設定できるので、メモリ消費も必要最低限に抑えられ、スピードもこれ以上早くするのは難しいでしょう。

また、書き出し先をファイルにすればフォーマット変換にも使えます。

System.Windows.Media.Imagingのための参照追加 は次のとおりです。

プロジェクトの参照右クリック⇒参照の追加⇒アッセンブリ
PresentationCoreをチェック⇒OK

方法2
BitmapDecoder
BitmapEncoderを使用する。

BitmapDecoderの使い方はよくわかっていませんが、複数のFrameを持ち、Animationなども扱えます。複雑な画像表示を行えるようですが、ひとつの静止画だけを扱うなら方法1で十分そうです。もしかしたら有用かもしれないので紹介しておきます。

ステップは方法1のBitmapImageがSystem.Windows.Media.Imaging.BitmapDecoderに置き換わっただけです。

コードは次のようになります。

            BitmapDecoder uriBitmap = BitmapDecoder.Create(
                new Uri(FilePath, UriKind.Absolute),
      BitmapCreateOptions.None,
                BitmapCacheOption.Default);
            using (MemoryStream ms = new MemoryStream())
           {
               BitmapEncoder enc = new BmpBitmapEncoder();
               enc.Frames.Add(uriBitmap.Frames[0]);
               enc.Save(ms);
               pictureBox1.Image = Image.FromStream(ms);
           }

調べた限りでは、この流れでは画像サイズを指定できません。そのため、高解像度画像ではメモリ消費が多くなり、スピードも少し遅くなります。

方法3
 AxWMPLib.AxWindowsMediaPlayerを使用する。

MediaPlayerは静止画も表示でき、HEIF 画像拡張インストールされていればheicフォーマットも表示できます。ちなみにHEVCビデオも再生できます。静止画を扱う場合は uiMode="none"が良いでしょう。

メリットとしては、まずは静止画も動画も同じインタフェイスで扱えることです。また、対応していないフォーマットや壊れたファイルのエラー対応もMediaPlayerまかせにできます。

これまでのFormアプリと同じ要領で使え、次の要領でコントロールにファイルのパスを設定するだけなので、お手軽といえます。

(AxWMPLib.AxWindowsMediaPlayer)player.URL = filePath;

VisualStudioでMediaPlayerを使う方法は次のリンクを参照してください。
Microsoft Visual Studio で Windows メディア プレーヤー コントロールを使用する
https://draft.blogger.com/blog/post/edit/6538117324271148932/209217070553378409#

デメリットとしては、方法1,2に比べると遅いこと、メモリ消費量も特に高解像度のheicの場合は多くなります。

HEIFコーディックの有無チェック 
Magick.NETと違い、HEIFコーディックがないとエラーになります。
以下の要領でHEIFコーディックの有無がチェックできます。 

bool HeifDllExists = Registry.GetValue(@"HKEY_CLASSES_ROOT\CLSID\{E9A4A80A-44FE-4DE4-8971-7150B10A5199}\InprocServer32", null, null) != null;

参照:HEIF Format Overview
https://learn.microsoft.com/ja-jp/previous-versions/windows/desktop/legacy/mt846532(v=vs.85)




2024年2月25日日曜日

Excel VBA 備忘録 基礎知識編

ときどきExcelのVBAを書きますが、普段使わない言語だとなにかとつまづきます。
自分自身のための備忘録ですが、きっと初心者ならだれもつまづくところだと思います。

VariantとObject
    Variant
     すべての変数。
     Integerなどの値のみを持つプリミティブなデータ型とオブジェクト型のどちらも代入可能。
       配列もプリミティブなデータ型なのでVariantで宣言した変数にしか代入できない。    
    Object
     データとプロパティー、メソッドがカプセル化されたもの。
       オブジェクト型のみ代入可能。
       これにプリミティブなデータを代入すると「オブジェクトが必要です」エラーとなる。

Null, Nothing, Empty, vbNullString の違い
 Null             Variant型変数内に有効な値が入っていない状態
 Nothing       Objectとして空の状態
 Empty         Variant型として空の状態
   vbNullString 値が0のString 

代入時にSetが必要な場合、不要な場合
   Setが必要な場合
        Objectに代入する場合で、値だけでなくObjectのプロパティーの設定が行われる。
 Setが不要な場合
     Integerなどのデータ型に値のみ代入する場合。

Sub呼び出しでCallが必要な場合
 引数を()でくくる場合。

コンパイルエラー:プロパティーの使い方が不正です
    Setを付けずにObjectへ代入しようとした場合。

コンパイルエラー:型が一致しません
 Objectで宣言した変数ににIntegerなどの値をSetしようとした場合。
  Dim o as Object: Set o = 1

コンパイルエラー:オブジェクトが必要です
   Variantで宣言した変数に値をSetしようした場合。
  Dim v as Variant: Set v = 1
 Stringで宣言した変数にSetで文字列を代入しようとした場合。
  Dim s as String: Set s = "str"

コンパイルエラー:ユーザ定義型は定義されていません
    Dimや引数の型宣言で規定のデータ型にもユーザ定義型にもない名前が使われている場合。
    だいたいは書き間違え

実行時エラーオブジェクトが必要です
    値がNothingのオブジェクトのプロパティーにアクセスした場合。
    Objectで宣言した変数にプリミティブなデータを代入しようとした場合。
    Objectで宣言した変数にプリミティブなデータを代入しようとした場合。

実行時エラー:オブジェクト変数またはWithブロック変数が設定されていません。
    Objectで宣言した変数にSetをつけずにオブジェクト、または値を代入しようとした場合。
     Dim o as Object: o = "a" 
     Dim o as Object: o = 1 

実行時エラー 400