ExcelVBA覚書 On Error エラー発生後のエラー

VBAの例外処理の話。
JavaやC#とかだと、Try-CatchのCatchの中でのエラーについては、Catch内にさらにTry-Catchを入れるという手法を取ると思うのだけれど、VBAになると、少々めんどくさい。いやかなりめんどくさい話になる。

ブイサバ【Excel VBAサバイバル】~とりあえずここに来れば解決できる~『VBA|エラー処理を2回目以降も処理できる方法』

この記事でいくと、VBAの例外処理(On Error文)で気をつけておかなければならないことがあるようだが、
端的に言えば、下の2つのことを考慮するとよいということになる。

  1. エラー処理中のエラーはトラップされないヨ
  2. とはいえ、Resumeステートメントで、仕切り直しできるんだよ

というので実践編。

Sub Sample1   
    On Error Goto ErrLabel1
    *** エラー発生(1) ***
    Exit Sub
ErrLabel1:
    MsgBox "No." & Err.Number & Err.Description , "Error"
    Resume ErrLabel2    '←←←←ココで仕切り直し!!
ErrLabel2:
    On Error Resume Next
    *** エラー発生(2) ***
End Sub

まずは「On Error Goto ErrLabel1」で例外処理へスキップする処理を入れる。
エラー発生(1)の箇所でエラーが発生すると、ErrLabel1ラベルに飛ぶ。
エラーを表示させた後の「Resume ErrLabel2」というところが仕切り直しの箇所。
なので、Errをウォッチすると、「Resume ErrLabel2」の箇所ではエラーNoが設定されているが、ErrLabel2ラベル下の「On Error Resume Next」の行になると、エラーはクリアされている。

よって、ErrLabel2以降で、再度トラップ可能なOn Error文を指定してあげればよい。
(ここではResume
Nextにしているので、エラーがあると次行へ進むようになっている)

因みに、こういうことをやらずにErr.Clearとかしてみたらどうなるのか試したのだが、これだと2つ目のエラーはトラップされなかった。
んじゃぁ、Resumeじゃなくて、Gotoだったら?とやってみたが、この場合はErrにそのままエラー情報が残った状態で、ErrLabel2に飛んでいた。

なので、「Resume ラベル名」
面倒だがこういう手を使わなければならない。

ExcelVBA覚書 AutoExecを走らせないようにAccessファイルを開く

AccessではAutoExecなどという起動時に走らせるマクロがある。
ExcelならばAuto_Openなどというプロシージャで昔は作っていたようだ。(今だとThisWorkbook_Openとかだろうか)

Accessファイルを起動するとき、このマクロを起動させたくなければ、一旦Shiftキーを押しながらファイルを開くのだが、これをVBAで実施したいときどうすればよいのだろうか・・・

Excelファイルを開くときは、

Excel.Application.EnableEvents = False

とすればよいのだが、Access.Applicationにはそのようなプロパティがない。

というので、前にちらっとSendKeyでShiftキーを押して起動しているコードを見たこともあり、同じようなものを作ってみることにした。
ただ、SendKeyはちょっと嫌なのでSendInputというAPIを使った方法にすることにした。(どっちも嫌だけど)

まずはTypeの定義

Private Type KEYBDINPUT
    VK          As Integer
    Scan        As Integer
    Flags       As Long
    Time        As Long
    ExtraInfo   As Long
    Dummy1      As Long
    Dummy2      As Long
End Type

Private Type INPUT_TYPE
    IType           As Long
    KI              As KEYBDINPUT
End Type

WinAPIの定義(64bitの場合PtrSafeをお忘れなく)

Private Declare Function SendInput Lib "user32.dll" (ByVal nInputs As Long, pInputs As INPUT_TYPE, ByVal cbsize As Long) As Long

利用する定数の定義

Private Const VK_SHIFT        As Long = &H10          'Shiftキー
Private Const KEYEVENTF_KEYUP As Integer = &H2        'KeyUp(KeyDownのほうは0)
Private Const KEYEVENTF_EXTENDEDKEY As Integer = &H1  '拡張コード
Private Const INPUT_KEYBOARD As Integer = 1           'KeyboardイベントでSendInputを利用する

ここまでで定義が済んだので、Accessファイル起動処理を書いていく。
SendInputについての情報は以下の通り。

  • SendInputはMouseイベントなどでも利用できるので、Keyboardイベントであることを指定する。
  • Shiftキーを押した→ファイルを起動した・・・とここまでで終わりではなく、Shiftキーを戻す(KeyUp)の処理まで行わないと、ずっとShiftキーが押された状態のままになってしまう。
  • SendInputの最初の引数はイベントの数で今回は1つなので1。例えば、Dキー⇒Oキー⇒Enterキーと押す場合は3。
  • SendInputの第2引数は押下するキーの情報(配列)、第3引数は第2引数のデータ長。
    Dim ac As Object
    set ac = CreateObject("Access.Application")
    Dim it(0) As INPUT_TYPE

    'Shiftキー押下
    With it(0)
        .IType = INPUT_KEYBOARD        
        .KI.Vk = VK_SHIFT             
        .KI.Scan = 0
        .KI.Flags = KEYEVENTF_EXTENDEDKEY Or 0                'DOWN
        .KI.Time = 0
        .KI.ExtraInfo = 0
    End With
    SendInput 1, it(0), Len(it(0))
    
    'Accessファイルを開く
    ac.OpenCurrentDatabase {起動するファイル名}, True, {パスワード}
        
    'Shiftキー押下の戻し
    it(0).KI.Flags = KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP   'UP
    SendInput 1, it(0), Len(it(0))

最終的にAccessを閉じて処理終了

    ac.Quit acQuitSaveNone

フラグを渡すのに「KEYEVENTF_EXTENDEDKEY Or 」というのをつけないと、反映されなかった。
ここに手間取り結構時間がかかったのと、あとはとにかく「こんなことやりたいねん!」って検索しても出てこない、っていうところで時間がかかった。
VBA Access Autoexec 無効 とかキーにしても、Shiftキー押しながら起動すればいいよ!としか出なくて腹立つぅ~~~!!
って思ってしまった。検索能力ってIT技術の1つだなぁ~とつくづく実感。

参考URL
VBレスキュー(花ちゃん) 『3.SendInput 関数を使ってプログラム上からキーボードを操作する(12_Key_03)』

Microsoft Windowアプリ開発『仮想キー コード』

JavaScript覚書 CSVファイルのFile.Type

JavaScriptでファイル選択する処理のなかにファイルタイプまで確認する処理が入っているものがあって、
それが災いして、新しいChromeのバージョン100.**でファイルが選択できなくなってしまった。

MIMEタイプとかいうらしいが、
File.type – Web API | MDN

CSVファイルは、
Chromeのバージョンが99.***までだと「application/vnd.ms-excel」になっていた。
ところが、バージョン100になったとたん、「text/csv」になり、
「application/vnd.ms-excel」でタイプを確認していた箇所は軒並み不具合を起こすこととなった。

ちなみにIE11で同じCSVファイルを選択してみたところ、「application/vnd.ms-excel」になり、
Edgeだと「text/csv」という結果になった。

m.o.b windows での csv アップロード
というサイトではExcelが入っているかどうかで決まるっぽいことを書いてあるのだが、
今回はすべてExcel2019が入っているPCで、同じサイトを確認したので、違うような感じがする。

そして、こんなサイトを見つけた。
Qiita CSVファイルのMIMEタイプが環境によって異なる
「application/octet-stream」って・・・

ただでさえ、バージョン3桁行きました!問題があるのに、こういうのやめてほしいんですけど・・・
(ってか、なんで、MIMEタイプまでチェックしてんだ?)

StringBuilderってどうよ?

StringBuilderの効果ってどうなのか?というところに疑問を持ったので、調べてみることにした。

Javaの文字列結合はStringBuilderでいいのか

結論的には、

・複数ステートメントで
・結合される側の文字列を複数スレッドで共有しない場合は
メモリアロケーションの回数が少ないStringBuilderが一番高速で文字列結合できる

なのだが、どのような処理になっているのでこうなる!というのが書かれていて、非常に参考になった。

スレッドを使ったときは不具合が起きるというのは、以下のページに書いてある。

【Java】+演算子、StringBuilder、StringBufferの違い(実際に測ってみた。)

StringBuilderとStringBufferの使い分けについても書いてあるので、これも参考に。

以下はVB(.NET)のStringBuilderについての記載。

Visual Basic で StringBuilder を使うべき場合とその利点

こちらもJavaと同じような話。(SE2年目でこの記載は凄いなぁ。うちの社員にもこういう人欲しい。)

使い方については、

意外と知られてないStringBuilderに関する初歩的なTips【Java・C#】

なんか、どうでしょう。
インスタンスをコロコロ変えたくないなぁと思っているので、こういうのはありがたい。

が、少し待て!

男(かどうか知らんが)がすなる時間計測といふものを女もしてみむとてするなり・・・

VC#(.NET Framework4.8)でやってみた。
<1> Length=0でクリアする
<2> 新たなインスタンスを作る
<3> Clearを使う(C#はClearメソッドがある)

        static void Main(string[] args) {
            var sw = new System.Diagnostics.Stopwatch();

            // <1>
            for (int j = 0; j < 10; j++) {
                sw.Start();
                StringBuilder sb1 = new StringBuilder("");
                for (int i = 0; i < 999999; i++) {
                    sb1.Length = 0;
                    sb1.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"1) {sw.ElapsedMilliseconds}ms");
            }

            // <2>
            for (int j=0;j<10;j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    StringBuilder sb2 = new StringBuilder("");
                    sb2.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"2) {sw.ElapsedMilliseconds}ms");
            }

            // <3>
            StringBuilder sb3 = new StringBuilder("");
            for (int j = 0; j < 10; j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    sb3.Clear();
                    sb3.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"3) {sw.ElapsedMilliseconds}ms");
            }
        }

結果発表!

<1> Length=0でクリアする <2> 新たなインスタンスを作る <3> Clearを使う
1) 693ms 2) 1440ms 3) 583ms
1) 1303ms 2) 1495ms 3) 503ms
1) 2398ms 2) 1455ms 3) 472ms
1) 3421ms 2) 1401ms 3) 514ms
1) 4656ms 2) 784ms 3) 520ms
1) 5780ms 2) 692ms 3) 500ms
1) 6798ms 2) 580ms 3) 498ms
1) 7786ms 2) 599ms 3) 519ms
1) 8868ms 2) 553ms 3) 485ms
1) 9937ms 2) 643ms 3) 469ms

<1> Length=0でクリアだと、処理速度がどんどん上がっていくので、嫌な感じ。
<2> 新たなインスタンスを作るは、<1>より速くて<3>と同等かもしくは遅いレベル。
<3> Clearを使うのが一番コンスタントに速い。

Javaは試していないので申し訳ないのだが、VC#ならば、用意されているClearメソッドを利用したほうがインスタンスを毎度作るよりは速いということになる。

色々調べてみるものだ、うん。
「無知の知」というのは大事だなぁと思う午後のひと時であった・・・

AccessVBA覚書 Public変数が変わらない

Accessは嫌いです。
理由はわかんないから。

オイオイ・・・

って、そんな理由かい!って思う人もいるのだろうけど、わからないというのは
・想定通り動いてくれない
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
という2点からだ。

この間VB6のソースを見ていた時も実は同じようなことがあって、
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
というのは、どうしたらいいのかさっぱりわからないのだ。

そして、VBAをDebug.Printを使って変数値を見ながら実行させてみたらば、Public変数に値を入れているのに値が置き換わっていないことが判明。

で、調べてみたらこんな記事があった。

Public宣言された変数の有効期間 [VBA]

なるへそ。
ってかさ、別に参照設定とかPublic変数を変えたとか、致命的なエラーが出たとかなら、リセットされるのはわかりますよ。
でもね、実行中にリセットする必要ありますか?

何のためのPublic変数なんですか!!!!

と。

で、上述の記事でテーブルに入れるのがいいと書いてあったので、結局その通りいたしました。
Excelでこんなこと起きたことはないんですけどね。
でも起きたことがないだけで、起きることがあるんだと思うとExcelのマクロも作れませんな・・・

大丈夫かMicrosoft。

さようなら Engadget日本版

Engadget日本版のサイトが閉まるそうだ。

はじめてEngadget日本版の記事を見たときは楽しかった。
特にスキだったのはITTOSAIだったかITTOHSAIだったか、とにかくイットウサイというライターさんの記事だった。

だけど、世の中の風潮か、だんだん広告が増えていき、だんだん別サイトへのリンクが並び、はっきり言ってエンガジェットでなくってもいいんだよね~と思うようになった。
もう、Amazonのレビューで良くない?、他のブログでよくない?みたいな。

となると、足は遠のく。
フロントページが広告だらけになったとき、私のエンガジェット愛は終わった。
でも、それでも捨てきれず、Facebookのリンクだけはつけてたけど。

*GBまで***円、だけど低速でだったら上限ないよ!とか、家の光回線だと上限はないこととかで、私たちはほぼ通信料の上限のない世界に生きているといってよい。
そこで本来気にしなければいけないことを気にしなさ過ぎているのではないかということをここで書いておく。

私たちは広告を見るために通信料をはらっているわけではない!

行くページ行くページ、広告がいくつも表示されていて、記事より広告のほうがボリュームがあることのほうが多いのではないだろうか。
しかし、私は広告を見るためにそのページにアクセスするわけではないので、広告の表示に自分の通信料が使われていることに対してはちょっと腹が立つ。
民放テレビであればCMが出るのは当たり前で、当然それを見ようとも思わなくても電気代は払っているので、サイトだって当然といえば当然なのだ。だが、テレビCMは番組より出しゃばったりしない。(たまに出しゃばった通販会社とかあるけど)見ている人間をがっくりさせることは少ない。(動画サイトなぞは、見ようと思った動画のサムネイルをクリックしていきなりCMに入るのでがっくりくる。)
それに、
ネットは災害が起きたときにも、こんな広告を載せ続けて通信を逼迫させつづけるのであろうか。
という疑問もある。

こういうことを思うのは私がネットの記事のほとんどが私と同じように自己満足、自己肯定、備忘録といった自分中心的な、自分発のものだと考えているからなのだが、

自己満足して、さらに広告収入まで欲しいとは、少し欲しがりすぎではありませんか???

と思いながら、さようなら~と軽く手を振ってEngadgetとお別れすることにした。(5月に閉まるらしいからまだ先だけど)
まぁ、結局記事の中身だよね。
(って私が広告収入得てたら、お前もか~って言ってもらっていいですよ)

ExcelVBA覚書 CSV読込とSchema.ini

CSVファイルを読み込むときに、ADODBを使って読み込むやり方というのがあって、これには
1,ADODB.Streamを使う
2,ADODB.CommandとADODB.RecordSetのGetStringを使う(SELECT * FROM [{ファイル名}])
という2種類の方法があるというので、サンプルを実行してみたら、
1より2のほうが若干処理が速い。
ただ、2には落とし穴があって、それは
★勝手に型を変えてしまう
★読み込み方によっては正しくすべてのデータが取り込めない
ということだと分かった。

前0がついていようが数値にしよるし、日付は勝手に日付型でシートに出力されてしまうは、設定の仕方によっては思い通りのデータ取込ができなくなってしまう。

ってかさ、こんないい加減なサンプル送ってくんなよ!!
(他のところで実行時エラー起きてるし・・・)

ってなことであったが、どうすれば改善できるのか知らない私。
いろいろやってみて途方に暮れたところでGoogle先生の厄介になってみたら、

Schema.ini使うんです!

みたいな記事発見。で、「ADODB Schema.ini」で検索をかける。
ふむふむ、取り込む列の型とか、文字エンコードとか、このファイルの中で指定してあげればよいのだね!
————-
[{ファイル名}]
ColNameHeader=False
CharacterSet=65001
Format=CSVDelimited
Col1=列1 Text
Col2=列2 Text
Col3=列3 Text
Col4=列4 Text
Col5=列5 Text
—————
{ファイル名}は実際に読み込むファイル名(パスはなしで、ファイル名だけでいい)
ColNameHeader は、ヘッダー有無。(Trueはあり)
Format=CSVDelimited は、CSV形式(カンマ区切り)
CharacterSet=65001 は文字エンコードがUTF-8である。(S-JISなら932)
下に読み取り用のサンプルソースをつけているが、そこでCharacterSetを指定しているので,iniには必要ない。
(どちらかに設定があればOK)
Col1=*** の *** は、列のタイトル、その右のTextが型

【VBA】ADOを使用してテキストファイル(CSV)をDB操作する方法のまとめ

を参照したところ、型は整数はShortやLong、日付はDateと記載されている。
Char型で50文字なら、「Char Width 50」といったように記載されているので、固定長であればこういう記載になるのかと思う。
(試してはいない)

で、このSchema.iniをcsvファイルのあるフォルダパスと同じところに入れておくのだが、

チョイ待ち!!

読み込むcsvファイルが常に同じところに置かれているとは限らんではないか!
ということになった。
そう、読み込むCSVは、ダイアログで選ばせるのだ・・・
となると、csvと同じところにschema.iniを配置させねばファイルの意味がないし、いや、そもそもダイアログで選ぶファイル名もSchema.iniで定義したファイル名と異なっていたら読み込んでくれへんやん!!!

と、また1つ問題が生じてしまった。
ということで、最終的には、

a) 一時保存用のフォルダを作る
b) a)で作ったフォルダにSchema.iniを入れる
c) ダイアログで選択されたCSVファイルを a)で作成したフォルダに固定のファイル名にコピーする
  (固定のファイル名というのが、Schema.iniに定義する{ファイル名}と同じになるように)
d) c)のコピーされたほうのファイルをADODBでSELECTして読み込む
e) 読込が終わったら、c)のコピーされたほうのファイルを削除

として、どの場所にあっても、同じフォーマットで取り込まれるようにしたのだった。
ってなると、ADODB.Streamを使うより時間がかかってしまったので、結局Streamのほうが速い!という結論に至った。

とはいえ、CSVファイルの全データが取得できなかった点も、Schema.ini、Properties(“Extended Properties”)や、GetStringメソッドを見直して何とかとりあえずうまく行くようにはなった。
Officeは2016。

    Dim con As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim rs  As ADODB.Recordset

    Set con = New ADODB.Connection
    With con
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .Properties("Extended Properties") = "Text;CharacterSet=65001;"    '65001=UTF-8 ,932=SJIS
        .Open {csvファイルのあるフォルダパス}
    End With
    Set cmd = New ADODB.Command
    Set cmd.ActiveConnection = con
    cmd.CommandText = "SELECT * FROM [{CSVファイル名}] "
    Set rs = New ADODB.Recordset
    rs.CursorType = adOpenStatic
    rs.Open cmd
    
    Dim dmp As String
    dmp = rs.GetString(adClipString, , ",", vbCrLf, "")  '行はCRLF, 列はカンマで区分するという設定に
    rs.MoveFirst
    Do Until rs.EOF
        '****** 1行分の処理を記載 ***********  
        rs.MoveNext
    Loop
   
  ’どばっとExcelに貼りつけるなら、Range.CopyFromRecordsetメソッドで 
    ' Activesheet.Cells(1,1).CopyFromRecordset rs            みたいな感じ

   rs.Close
    Set rs = Nothing
    Set cmd = Nothing
    con.Close
    Set con = Nothing

GetString メソッド (ADO)

中途半端なサンプルを送りつけられたせいで悩んだが、かえっていい勉強になったわぃ!
ということにしておこう。

NEW YEAR 2022

明けました。おめでとうございます。

仕事始め。
寒い。
行きたくない!けど、会議が・・・

新年早々、人一杯いる。
会社の中にも人がいっぱいいる。
オミクロン株市中感染しはじめてるってのに。

というので、なるべく会社に行かないようにしたいところ。
なのだが、会議が・・・

んでね、思うのですよ。
オミクロン株。軽症で済む人が多いっていうのはいいんですが、後遺症の話までしてほしいんですよね。
・感染者数より、重症者数。
・現時点での病床数とその利用率。
これぐらいは毎日画面に表示させてていいんじゃないの。
それから、後遺症に悩まされて仕事辞めてしまう(辞めさせられてしまう)人も多いので、
・後遺症とその対応方法がどうなっているか。
といのも報じてほしい。
感想コメントとかはいらないんで、必要な情報を流しましょう。
情報は逐次変わっていくものだし、毎日報じたって大した時間ではないでしょうよ。

と、新年早々愚痴りつつ、今年もほどほどにお仕事頑張ります。

VB.NET覚書 バックグラウンドプロセスからExcelが消えない

VB2019で、ライブラリMicrosoft.Office.Interop.Excelを使ってExcel出力を行っている。
Officeは2019だ。
COMオブジェクトなので、ReleaseComObjectでメモリ解放をしているのだが、

だが、処理が終わってもバックグラウンドプロセスからExcelが消えない・・・

リリースしてまっせ!
と思うのだが、何故か残る。

というので調べた。

・Rangeとか変数定義してるところ、リリースしてる?
 全部リリースするのよ!
・リリースはしてても時差があったりするよ!

んーーーーーー、そっか。でも頑張ってBookもSheetもRangeも処理いれたんだけど。

ということで、最後。ReleaseComObjectをぐるぐる回す。

<参照サイト>
ドリリウム『【Interop.Excel】Excelプロセス絶対殺すコード』

このサイトのWhileでReleaseComObjectを回してリリースさせるようにする!っていうのをやってみた。
とりあえず、残らなくなった気がする・・・
気がする。(ちょっと不安やけど)

VB.NET覚書 64bit AccessファイルODBC接続

客先で使うOfficeが64bitというので、普段は32bit版しか使っていない私は、トラブリューの渦に巻き込まれている。
VB.NET(Framework4.6/4.8)
ODBC接続(64bit)でAccessファイル(*.accdb)に接続
DB接続ライブラリはADODB(6.0)
 という環境を前提にしてメモ。

  1. ODBC接続(64bit)
  2. Office2019の64bit版をインストールしたにも関わらず、ODBCデータソース(64bit)の画面上にはAccess64bit用のODBC接続ドライバは表示されない。
    ネットで調べて何とか探し当てたのが
    Microsoft Access データベース エンジン 2016 再頒布可能コンポーネント
    日本語版でダウンロードしても英語版しか取得できない・・・というお粗末な状態だが、exeを実行することで、accdb形式のファイルに64bit接続ができるようになった。
    ちなみに、ADODBの2.8とかだと動かなかったので、ADODBは6.0に。

  3. VB.netでのコーディング
  4. 正直、Accessファイルじゃなかったら、64bitじゃなかったら、こんなに大変じゃないのかも・・・と思った。
    情報があまりにもない。(というか検索に引っかからないだけなのかもしれないし、検索の仕方がヘタなのかもしれないが、Accessはあっても64bitな情報じゃなかったりする。)

    • OPEN
    • Accessへの接続文字列は 「DSN=***;UID=;PWD=***;」
      DSNはODBC設定した名前。Accessなのでユーザ名は空。PWDはAccessを開くときのパスワードを設定。

      Dim conn As ADOBC.Connection = New ADOBC.Connection
      Dim ConnStr As String = "***"  '(接続文字列を設定)
      conn.ConnectionTimeout = **    '(タイムアウト秒数)
      conn.CursorLocation = ADODB.CursorLocationEnum.adUseClient  '!!!ココめっちゃ重要
      conn.Open(ConnStr)
      

      特に重要なのは、CursorLocationの設定。
      これが「adUseServer」になっていると、トランザクションの開始ができない。
      そもそもDocsを見ると初期設定はadUseClientであると書いてあるのだが、なぜadUseServerになるのだろうか。
      (ODBC設定をするときにシステムDSNでなくユーザーDSNに設定していたらいいのかな、とも思うのだが、複数ユーザで利用されることも考えてシステムDSNの設定は続行。詳細は不明。)
      【参考URL】
      Programer to Programer「Error – Attribute cannot be set now」
      トランザクション開始時に「Attribute cannot set now」のエラーが出た時にネットを探しまくったら出てきた英語のページ。
      このページの最後ぐらいに、

      This is because the RecordSet is already open. That is why we cannot participate in Begin Transaction. To overcome this problem we have to open RecordSet with the CursorLoction property as adUseClient.
      Ex .. RS.CursorLocation = adUseClient

      とあるので、試したところトランザクションが開始できるようになった。

    • CLOSE
    • 切断処理も厄介だった。閉じてもlaccdbファイルが残ってるし!!!!
      ってなって、切断直後、すぐに同じAccessファイルと接続しようとしたらエラーになってしまう現象が発生。
      これもネットで調べて、なんとなく解決させた。

      System.Runtime.InteropServices.Marshal.ReleaseComObject(conn)
      

      解放文の前に
      conn IsNot Nothing とか、System.Runtime.InteropServices.Marshal.IsComObject(conn)
      のIF文をつけておくと確実。

      laccdbのファイルを削除すればいいじゃん!みたいな記事も見たのだが、Killしてもファイル削除できなかったし、Closeしてからガベージコレクションを実行させたら何とかなるんじゃないかと思ってやってみたものの、これもダメだった。

    • 最適化
    • これはADOでなく、DAO3.6を使う。

      Dim dbe As Dao.Engine = New Dao.Engine
      dbe.CompactDatabase("元ファイル","保存ファイル",";pwd=***",Dao.DatabaseTypeEnum.dbVersion120, ";pwd=***")
      

      最適化は最適化したファイルを別名保存することになるので、最適化が済んだら、元ファイルを削除して保存ファイルをRenameする処理が後続処理として発生する。
      ここで重要なのは引数の「Dao.DatabaseTypeEnum.dbVersion120」
      Officeのバージョンによって異なるのだが、2019なのでdbVersion120にしている。
      この引数を設定していなかったときは、処理が動かなかったので、Optionな引数なくせに必須。
      パスワードがなければ、3つ目と5つ目の引数はなし。

そりゃ感染広がるでしょう

ここ何週間かで、数回飲食店で飲食をする機会があった。
飲食店にいると、マスクをつけずにしゃべってるヤツばっかり。
複数人でやってきて、食べながら会話って・・・

「マスク会食」って忘れましたか???

向かい合っている相手は家族かもしれませんが、飛沫は何mか拡散するんですよぉ~
ワクチン打ったからって、感染させないわけじゃないんですよぉ~~~

これじゃぁ、いつまで経っても酒なんか呑めないですね。

と思いながら、孤独のグルメ派な私は、一人で入って、一人で食って、イソイソ帰ってくる日々。
(というより、一緒に行く人がいないだけなのだが。)

2021 クーラーをつけた日

おお、去年は投稿を忘れていたようだ。
確か6月末だったような。

今年は今日。
温度的にはそこまで高くないのだが、やはり湿度が高い。
除湿器をつけているのだが、じめじめ感が消えないのでつけてしまった。

夏本番だなぁ。そろそろ会社に行くかな・・・

Linux覚書 yum update の取り消し

yumのupdateをしたほうがいいよ~、みたいなメッセージが出てたので、updateしたらばWebアプリの調子がおかしくなった。
しまった!、もうイチから入れなおさなあかんかなぁと思っていたが、調べてみるとupdateの巻き戻しができるようなのでやってみた。

sudo yum history

とコマンドを打って、まず履歴をチェック。

履歴がリストで出てくるので、左端にある番号、update日時からキャンセルする番号を確認。
キャンセルする番号が5ならば、

sudo yum history undo 5

とコマンドを打って実行。
途中最終確認でy/nを聞いてくるので、問題がなければyキーを打つ。

処理が正常に済んだらOK。

Webアプリとサーバを再起動させたら、update前のようにWebアプリがちゃんと動くようになった。
めでたしめでたし・・・

Qiita yumでインストールしたパッケージを取り消す

食欲の秋

阪急オアシスで「きのこと豚肉の中華風焼きそば」を買ってみた。
私好みの味、太めの麺でちょっとカリっと香ばしいところもありおいしかった。

家からちょっと行ったところのお寺に初めて行ってみたのだが、敷地内にカフェがあって入ってみた。
注文した高菜ピラフはあっさり控えめな味でサラダもついて650円。これもうまかった。

なんだか、とっても幸せ・・・

Go To Eat Hyogo

久方ぶりに投稿。
Go To Eat 兵庫版の申し込みが10/14から!というので、さっそくアクセスしてみた。

だけど、12:00頃からアクセスしたのが悪いのか、アクセスでけへん・・・

ノートPCで幾度となくトライアルするがアクセスできない。
しょうがないから試しにスマホでアクセス。

いとも簡単に繋がる。どういうことなん?

まぁつながったからええわ。
で、まず個人情報登録。(こういうの事前に登録させることでけへんのかい!と思いつつ、登録)

現状だと、どの店舗で実施してくれるのかはわからないのと、いろんな人が使えたほうがいいと思うのとで、1冊分(1万円)だけ購入することに。(一応2冊:2万円が上限)

で、あとはハガキが届くから、自分が指定した場所でチケットを買えばよい・・・と
ふむふむ。

欲しい人皆に行きわたるようにしてくれれば、制度的には悪くはないと思うんのだが、なんだか一部の人だけが得して、結局チケットとれないまま終わる人が出てくるような仕組みに思えてならないのは気のせいだろうか。
Go To Travelも、金銭的余裕があって、時間的余裕もあって、てな人のためにある制度だし、金ってそんなところに使うもんなのかなぁ。
(往来を自由にしてもらっていいですよ、って言えば、前述の人たちは給付金なんか出さなくてもウロチョロするんでしょうから。)

と、利用しててなんだけど、ちょいと複雑な気分。

除湿機って素晴らしい

夏も冬もジメジメな日当たりの悪い部屋に住んでいる。
そうすると、青カビが窓やらカーテンやら、床やら、もう嫌がらせのように発生する。
窓に近いところに置いているものは、軒並みカビが生える。
ついでに、ほこりがたまっていると、そこにもカビが・・・

あぁ、何とかしたい。簡単に。

と思って、除湿剤やら炭やら置いているのだが、いまいち効き目がない。
なので、もう諦めて除湿機を買おうと誓って半年、いや1年か経った。

除湿機を買い渋っていた理由は、大きさと音。
大きくて重たいものは動かしにくいが、小さいとタンクも小さくなり、水を捨てる回数を考えると面倒だ。
音も気になる。うるさくて眠れない、みたいなレビューを見るとさすがに買えない。
あと、なんちゃら方式となんちゃら方式と2種類あるとかで、どっちを選ぶかも重要だ。すぐには選べない・・・

半年前にはPanasonicの除湿機を買おうと思って、価格をチラチラ見ていたのだが、やはりいいものは高い。
高くともカビが生えるよりはマシだろうと思って、ポチっとな!しようと思いつつも、やはり高い。

そんなこんなでまた梅雨の季節がやってきた。
もう、このジメジメから、本当に卒業したい!と思って、除湿機をアマゾンで調べた。

あるじゃないか。安価で、タンクの容量もそこそこ、持ち運びが億劫にならない大きさ。
アイリスオーヤマ。

ポチっとな!

やったぞ、初期不良さえなけれ・・・

早速使っております。
洗濯後は風呂場で。他は個室で。寝てるとき以外はフル稼働。
こんなに湿気てんのか!と、今まで湿気取りだけで済まそうとしていた自分の対応の悪さを反省しております。
でも、今でなかったらこの商品は出てなかったので、ちょうどよいときに買えたなぁと思った次第。
今までドライで稼働させていたエアコンも稼働時間を減らせそう。

GoogleChrome画面が真っ黒に

なった・・・
真っ黒。何もできない・・・、けど右上をクリックするとちゃんとChromeが閉じる・・・

で、Windowsを再起動してもうまくいかず。
色々調べて、最終的にはショートカットのリンク先にパラメータを渡して解決。

“C:\Program Files (x86)\Google\Chrome\Application\chrome.exe” -disable-gpu

この「-disable-gpu」をつけることでとりあえずはなんとか普通に表示されるようになった。

ORACLE覚書 階層データを引数として渡す

サマリ1
 |– 明細1-1
 |– 明細1-2
サマリ2
 |– 明細2-1

のような、階層のあるデータを引数で渡したいと思って、調べてみたらオブジェクト型なるものを発見。

で、実際にどうやって実装すればいいのか、また調べて実行。

<手順>
1, まずはCREATE TYPEでもって、任意のオブジェクト型を作ってみる。

・明細データの型を作る。(Javaでいうと、データクラスみたいなもの)

CREATE TYPE DTL_TYPE AS OBJECT (
   DTL_ID   VARCHAR2(5)
   DTL_NAME VARCHAR2(10)
);

・次に作った明細(DTL_TYPE)のテーブルを型にする。(JavaでいうとList<明細>みたいなもの)

CREATE TYPE DTLTAB_TYPE AS TABLE OF DTL_TYPE;

・明細が済んだら次はサマリも同じように型を作る。

CREATE TYPE SUM_TYPE AS OBJECT (
  SUM_ID   VARCHAR2(5)
 ,SUM_NAME VARCHAR2(20)
 ,DTL      DTLTAB_TYPE
);
CREATE TYPE SUMTAB_TYPE AS TABLE OF SUM_TYPE;

2, 試しに作ったオブジェクト型を引数に、関数を作ってみる

---------------------------------------
-- 明細データをカンマ区切りで取得
---------------------------------------
CREATE OR REPLACE FUNCTION OTAMESHI_FUNC(
  PARAM IN SUMTAB_TYPE 
) 
RETURN VARCHAR
IS
  TEMP    VARCHAR(1000);
BEGIN
  -- サマリをぐるぐる回す
  DECLARE
  CURSOR CURSUM IS SELECT SUM_ID, SUM_NAME, DTL FROM TABLE(CAST(PARAM AS SUMTAB_TYPE));
  CURSUM_ROW CURSUM%ROWTYPE;
  BEGIN
    OPEN CURSUM;
    LOOP
      FETCH CURSUM INTO CURSUM_ROW;
      EXIT WHEN CURSUM%NOTFOUND;

      TEMP := TEMP || ',<<' || CUR_ROW2.SUM_ID || ':' || CUR_ROW2.SUM_ID || '>>';
      
      -- 明細をぐるぐる回す
      DECLARE
      CURSOR CUR IS SELECT DTL_ID, DTL_NAME  FROM TABLE(CAST(CURSUM_ROW.DTL AS DTLTAB_TYPE));
      CUR_ROW CUR%ROWTYPE;
      BEGIN
        OPEN CUR;
        LOOP
          FETCH CUR INTO CUR_ROW;
          EXIT WHEN CUR%NOTFOUND;

          TEMP := TEMP || ',' || CUR.DTL_ID || ':' || CUR.DTL_ID;

        END LOOP;
      END;


    END LOOP;
  END;

  -- TEMPに入れたデータを返す
  RETURN TEMP;
EXCEPTION
  WHEN OTHERS THEN
    RETURN 'エラーです.';
END;

3, 作った関数を呼び出してみる

SELECT
  OTAMESHI_FUNC(
      SUMTAB_TYPE(
        SUM_TYPE('01'
               , 'まさか'
               , DTLTAB_TYPE(
                             DTL_TYPE('A1','やさか')
                            ) 
               )
       ,SUM_TYPE('02'
               , 'どうか'
               , DTLTAB_TYPE(
                             DTL_TYPE('D1','ぎんか')
                            ,DTL_TYPE('B1','きんか')
                            ) 
               )
     )
  )
FROM DUAL

できるのは解ったのだが、う~ん、どうなんだろう。

Alexa覚書 Display表示

Displayを使ってみたくなってスキルを改修して申請したのだが、審査でNGになってしまった。

う~ん、Display表示の要素を足しただけなのになぁ・・・と思っていたら、ただ足しただけではダメっぽかった。
すいません、リファレンス読んでません。

Alexa Skills Kit Displayインターフェースのリファレンス

Qiita『Alexa ディスプレイ端末対応時にセッションをクローズする時の注意点』

審査でNGになってわかったのは、

・スキルの継続・終了とセッションの維持・破棄を明示的に合わせておくこと。
・セッションを維持させる場合は、維持させることがわかるような発話をすること。 (例えば、「ほかにないですか?」とか「もう一度教えて」とか)

で、何とか審査はパス。
お手数おかけしました。