VBS ADO CSV のText Driver の64 bit Windows と32 Bit Windowsの違いと対応策


この記事自体はここからの続きです。
https://qiita.com/Q11Q/items/b4ce72054898de2a6534
これは64bit版Windowsを基本として32bit版の違いを記述します。しかしこれはとても混乱します。なので、次のようにします。

#この記事ではSystem32版、SysWOW64版と表記します
SysWOW64とは64Bit版では32bitであり64bit版のSystem32は本当は64bitになっていますが、もうここでやめます。
この記事では表記を以下のようにします。
32bit版はSystem32だけ読めばいいのでビット数など考える必要がないからです。
32bit版ではSYSWOW64は無視してください。
64bit版の場合はSystem32かSysWOW64かだけ考えてください。しかしわからないときは64bit版の方もSystem32でだけみてください。
そしてそれで動くのか動かないのか、そこだけが今回のテーマです。
なお、すごくざっくりいうとWindows7は32Bit版、Windows 10は64bit版です。でもSystem32かSYSWOW64かで言ったら、どっちもSystem32なんです。
Windows8？知らない子ですね。とりあえずSystem32を見ましょう。VISTAも同じです。
[インストールされているWindows 8 / 8.1が32ビットか64ビットか確認する方法](https://121ware.com/qasearch/1007/app/servlet/relatedqa?QID=015558)
[64bit OSの利用率 シス蔵 2017/05/25](https://syszo.com/items/yq0rvxy9Q8)
[64ビットWindowsには、なぜ32ビットと64ビットのODBCが存在するのか？](https://www.idearu.info/article/data/ds1034)
というかここでもあるけどこの64/32のODBCの違いが32bitから64bitに移行できないことを生んでいるのでマイクロソフトが馬鹿だからです。だいたいあのアホの集団の御託ばかり取り上げる人ってなんなの？どういおうと64bitと32bitの移行に完全に失敗しているのでAccessが売れないし、Accessの代わりにExcelが売れているし使われるし、今回のサンプルが世界中どこを探してもないわけです。まあAccessを廃止するつもりなのかも知れないですが、それ以前に前回のとおり解説が間違っているので擁護のしようがない。この方法が忘れ去られかけていたとしてもやむを得ないと思います。本当はRを入れなくても無料でWindowsはデータベースは作ることができるのです。この方法が普及していれば世界中のデータベースの記事は有意にADOが多かったと思います。
でも、今回はこのレガシーシステムとの付き合い方にも役立つでしょう。テキストのインポート、エクスポートについてはこれで決着がついたといえます。公開されている記事ベースでは世界中どこを探してもありません（あったら書いていない）。この発展形として64ビットと32ビットで接続文字を変えてデータベースがVBA、VBSで開けることになります。ただし前回でも言ったようにADOはファイルサイズが1gbが目安で、フィールド名に制約があり、データ型、表記も厳密です。そういうのをクリアした上で今回の記事になります。また今回の技が通じない場合でもADO.12を使う技もありますし、Excelで取り込むこともできます。DBQでやるのはかなり難しいです。ここでもできない、わからない、うまくいかないときは、まずデータ型、内容を確認してください。そしてどうしてもだめなときは他の方法も検討しましょう。
ここに来るまでに参照、引用させて頂いた方々に感謝します。マイクロソフトを除いて。
それでは本題です。まず改めてcsvファイルを登録するバッチファイルから説明していきます。

#Microsoft Access Text Driver
これでcsvファイルを登録します
batファイルを作りました
csvファイルが c:\csvtest\にあるlog_master1.csvとします。またカレントフォルダにLogが作成されます。
なお、ODBCアドミニストレータに登録したものはすべて削除してください。
ファイルを削除してODBCアドミニストレータから削除しようとするとけっこう大変です。

```shell
cd /d c:\
cd /d csvtest
cd /d %~dp0
set WORK_DIR=%~dp0
%Systemroot%\system32\odbcconf /Ld %WORK_DIR%log_test.txt /A {CONFIGDSN "Microsoft Access Text Driver (*.txt, *.csv)" "DSN=log_master1.csv;DBQ=C:\csvtest\log_master1.csv"}
```

##ODBCを比較する
上記のBatファイル若しくは手動で登録するとSysWow64版の`%Systemroot%\SysWOW64\odbcad32.exe`でも表示されます
右側がSystem32版左側がSyswow64版です
64bitのため左は64bit右は32Bitと記載されます。
ここでlog_master1.csvがどちらも64bitと記載されているのがポイントです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/717496eb-c688-b28f-47bc-e17e9f122868.png)
次にこのMicrosofot Access Text DriverをSytem32版より削除します。SysWow64版ではできません。

#Microsoft Text Driver

##SYSWOW64のバッチ
登録します。

```sh
cd /d c:\
cd /d csvtest
cd /d %~dp0
set WORK_DIR=%~dp0
%Systemroot%\syswow64\odbcconf /Ld %WORK_DIR%log_test.txt /A {CONFIGDSN "Microsoft Text Driver (*.txt; *.csv)" "DSN=log_master1.csv;DBQ=C:\csvtest\log_master1.csv"}
```

###32Bit版Windows
`C:\Windows\System32\odbcad32.exe`
`C:\Windows\SysWOW64\odbcad32.exe`
アドレス欄に入れて開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/2b37a265-a213-5342-1c03-6c8bd4ce45b6.png)

このようにMicrosoft Text Driverで登録すると64bitWindowsではSystem32版で32bitと表記されます。

#CScript64/32でVBSを起動した結果の違い

|ドライバー|起動するCscript|結果|
|:-------|:-------------|:---:|
|Access Text Driver|System32|成功|
|Access Text Driver|SysWOW64|成功|
|Text Driver|System32|<font color = "RED">エラー</font>|
|Text Driver|SysWOW64|成功|

この表の意味を解説します

##VBSのコード
###Access Text Driverの場合は

```vb
objADO.Open "Provider=MSDASQL;Driver={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
```

###Text Driverの場合は

```vb
objADO.Open "Provider=MSDASQL;Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
```

##Cscriptの表記
###System32版
`%Systemroot%\System32\Cscript.exe`

###SysWOW64版
`%Systemroot%\SysWOW64\Cscript.exe`

#得られる結論
##後方互換を重視する場合にはTextDriverでSysWOW64で起動することにしてコードを書く
Text Driverは32bit版しかありません。
他方、Access Text Driverはインストールする必要があります。以前は64/32で併存させるには裏技が必要でした。
このため、Windows7 Vistaの32bit版はTextDriverで動いており、後方互換を重視すると、Text Driverを使うことになります。
これを使った場合にはこの指定して起動するか、あるいは強制的に32bit版で再起動する技を使うか、Task Schedulerを使うかになります。
##64/32両用の場合にはMicrosoft Access TextDriverを使い、既存のコードは書き換える。
現在のドライバーは64/32が自動的に入るようです。
このため以前のような併存させる裏技が必要がないと考えられます。
WIn7 32 Bitであったとしても、Access 2010 再頒布コンポーネントをダウンロード及びインストールできる限りは、64/32併存が可能になるため、Access Text Driverを使うほうがバグが出ないということになります。
問題なのはこのAccess Text Driverを使う方法があまり知られておらず、csvとAdoで検索するとMicrosoft Text Driverの例しかないということがよくあるということです。

##ここからがプロの技術です
現在のところ、起動の差はありますが、機能の差は見当たりません。
そこで、これが両方書いてどちらかが動けばよいと考えられます。
そこで、このサンプルから発展させ、
https://qiita.com/Q11Q/items/e38ae23295f5a5c308db
次のようなフローにします
まず64bit版かどうかを確認します
amd64なら64bit版です
日本のデスクトップ版のWIndows10はほぼAMD64なので、99%はこれで行けると思います。
タブレット等は違うそうですが、そもそもタブレットでこんなことはできないし、やらないでしょう。
つまりVBAやJSCRIPTの条件付き編纂命令（Const Directive）のVBSCRIPTがこれです。
AMD64ならWindows64bit版なので、この場合にはAccess Text Driverのみとなります。
次に32Bit版の判定をします
一度Access Text DriverでOpenを試みて失敗した場合はText Driverで開きます


```vb
On Error Resume Next
IF LCase(CreateObject("WScript.Shell").Environment("Process").Item("PROCESSOR_ARCHITECTURE"))="amd64" Then
objADO.Open "Provider=MSDASQL;Driver={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
Else
'32 bit Microsoft Text Driver
objADO.Open "Provider=MSDASQL;Driver={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
If err.number <> 0 then 
Err.Clear
objADO.Open "Provider=MSDASQL;Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
End If
End If
```


#64/32テキストドライバー両用VBSCRIPT
https://qiita.com/Q11Q/items/b4ce72054898de2a6534
この前提で実際にサンプルからどう動くかを整理します。
##Driverのダウンロードとインストール
事前にAccess 2010 再頒布可能コンポーネント
https://www.microsoft.com/ja-jp/download/details.aspx?id=13255
Microsoft Access 2016 Database Engine(英語版のみ、2016は両方入れなくてよい）
https://www.microsoft.com/en-us/download/confirmation.aspx?id=54920
を入れます


##フォルダの構成

```c
C:\csvtest
    OpenCmdAndCurrentExecute.bat ***なんども実験すると開くのすら面倒になってきた
    OpenCmdAndCurrentExecuteSYSWOW.bat ***今回の重要なバッチ。SYSWOW64で開く
    log_master1.csv *** データベース、今回はUTF-8BOMなし
    schema.ini *** ANSIで作る
    SETSYSWOWTxtDrv.bat *** 64 bit版でMicrosoft Text Driverにファイルをセットする場合のバッチ
    SETDSNSYS32AcDrv.bat *** 64/32 bit版でMicrosoft Access Text Driverにファイルをセットする場合のバッチ
    filename.vbs *** vbscript
    time_master.csv *** 計算結果のcsv utf-8 BOMなし VBSの起動時に削除される
    time_master1.csv ***データをそのまま出力したcsv utf-8 BOMなし VBSの起動時に削除される
```

###batファイルでDSNにセット

####Access Text Driver版

```shell:SETDSNSYS32AcDrv.bat
cd /d c:\
cd /d csvtest
cd /d %~dp0
set WORK_DIR=%~dp0
%Systemroot%\system32\odbcconf /Ld %WORK_DIR%log_test.txt /A {CONFIGDSN "Microsoft Access Text Driver (*.txt, *.csv)" "DSN=log_master1.csv;DBQ=C:\csvtest\log_master1.csv"}
```

こちらを推奨します。
####実験用TextDriver版
CSVファイルが同名のため、Microsoft Access Text Driver(System32)かMicrosoft Text Driver(SysWOW64)のどちらか一つしか登録できません。
`SETDSNTextDrvSysWow.bat`の例です。バッチファイルの文字コードはANSI UTF-16LEを推奨しています

```shell:SETDSNTextDrvSysWow.bat
@echo off
cd /d c:\
cd /d csvtest
cd /d %~dp0
set WORK_DIR=%~dp0
%Systemroot%\syswow64\odbcconf /Ld %WORK_DIR%log_test.txt /A {CONFIGDSN "Microsoft Text Driver (*.txt; *.csv)" "DSN=log_master1.csv;DBQ=C:\csvtest\log_master1.csv"}
@echo On
```
####32bit版Microsoft Text Driver用
一方、32bitならSYSWOWではないため

```shell:SETDSNTextDrv32bitWindows.bat
@echo off
cd /d c:\
cd /d csvtest
cd /d %~dp0
set WORK_DIR=%~dp0
%Systemroot%\system32\odbcconf /Ld %WORK_DIR%log_test.txt /A {CONFIGDSN "Microsoft Text Driver (*.txt; *.csv)" "DSN=log_master1.csv;DBQ=C:\csvtest\log_master1.csv"}
@echo On
```

しかし、これは一般的なWindows10が64bit版なので基本的に使えません。Windows 7 32 bitなどが想定されているものです。

###log_master1.csv(utf-8)
このcsvファイルはUTF-8で保存します。
またBOMはついてもなしでも構いません。

```c:log_master1.csv
"コンピューター名","日時","操作種別","期間","端末機No","端末機名"
"PC1","2019/02/06 09:56","終了","00:00:05","01","吉田1"
"PC1","2019/02/06 09:56","開始","00:00:05","01","吉田1"
"PC1","2019/02/06 09:41","終了","00:02:23","01","吉田1"
"PC1","2019/02/06 09:39","開始","00:02:23","01","吉田1"
"PC1","2019/02/06 09:23","終了","00:05:08","01","吉田1"
"PC1","2019/02/06 09:18","開始","00:05:08","01","吉田1"
"PC2","2019/02/06 15:18","終了","02:19:53","15","田中2"
"PC2","2019/02/06 12:58","開始","02:19:53","15","田中2"
"PC2","2019/02/06 12:06","終了","00:00:44","15","田中2"
"PC2","2019/02/06 12:05","開始","00:00:44","15","田中2"
"PC2","2019/02/06 12:01","終了","01:27:49","15","田中2"
"PC2","2019/02/06 10:33","開始","01:27:49","15","田中2"
"PC1","2019/02/08 09:56","終了","01:00:05","01","吉田1"
"PC1","2019/02/08 09:56","開始","10:00:05","01","吉田1"
"PC1","2019/02/08 09:41","終了","01:02:23","01","吉田1"
"PC1","2019/02/08 09:39","開始","01:02:23","01","吉田1"
"PC1","2019/02/08 09:23","終了","01:05:08","01","吉田1"
"PC1","2019/02/08 09:18","開始","01:05:08","01","吉田1"
"PC2","2019/02/08 15:18","終了","02:19:53","15","田中2"
"PC2","2019/02/08 12:58","開始","02:19:53","15","田中2"
"PC2","2019/02/08 12:06","終了","01:00:44","15","田中2"
"PC2","2019/02/08 12:05","開始","01:00:44","15","田中2"
"PC2","2019/02/08 12:01","終了","01:27:49","15","田中2"
"PC2","2019/02/08 10:33","開始","01:27:49","15","田中2"
```

###Schema.ini
Schema.ini vbsはすべてANSI形式テキストファイルです。

```scheme:schema.ini
[log_master1.csv]
ColNameHeader=True
Format=CSVDelimited
CharacterSet=65001
MaxScanRows=2
textdelimiter="
Col1="コンピューター名" Char Width 10
Col2="日時" Date
Col3="操作種別"  TEXT Width 10
Col4="期間" Date
Col5="端末機No" Integer
Col6="端末機名" Char Width 10

[Export:time_master.csv]
ColNameHeader=True
CharacterSet=65001
Format=CSVDelimited
Col1=コンピューター名 Char Width 255
Col2=F2 Date
Col3=F3 Date


[Export: time_master1.csv]
ColNameHeader=True
CharacterSet=65001
Format=CSVDelimited
textdelimiter="

Col1=コンピューター名 Char Width 10
Col2=日時 Date
Col3=操作種別 Char Width 10
Col4=期間 Date
Col5=端末機No Integer
Col6=端末機名 Char Width 10
[time_master.csv]
ColNameHeader=True
CharacterSet=65001
Format=CSVDelimited
textdelimiter="

[time_master1.csv]
ColNameHeader=True
CharacterSet=65001
Format=CSVDelimited
textdelimiter="
```

###起動用バッチの作成(SYSWOW64)

```shell:OpenCmdAndCurrentExecuteSYSWOW.bat
@echo off
taskkill /IM notepad.exe >nul
SET TARGET_DIR1=C:\csvtest\
cd /d c:\
cd /d csvtest
cd /d %~dp0
START """ "%TARGET_DIR%"
%systemroot%\syswow64\cscript.exe //NOLOGO testadogroupby.vbs
@echo on
exit
```

今回のポイントはSYSTEM32\Cscript.exeではなくSYSWOW64\Cscript.exeを使う点です。
なお、32bit版のWindowsの場合は、

```shell:OpenCmdAndCurrentExecuteSYS32.bat
@echo off
taskkill /IM notepad.exe >nul
SET TARGET_DIR1=C:\csvtest\
cd /d c:\
cd /d csvtest
cd /d %~dp0
START """ "%TARGET_DIR%"
%systemroot%\system32\cscript.exe //NOLOGO testadogroupby.vbs
@echo on
exit
```

を使ってください。

##VBSCript

```vb:filename.vbs
Const testPath = "c:\csvtest\" 'ここはルートではないことが望ましい。また、フォルダの末尾に円マーク(Qiitaの表示ではバックスラッシュ)をつけること
'%Systemroot%\System32\Cscript.exe testadogroupby.vbs //Nologo
Dim objADO
Dim strPath
Dim strDelFile5, strfile5
strPath = testPath
strfile5 = "schema.ini"
strDelFile5 = strPath & strfile5

With CreateObject("Scripting.FileSystemObject")
' Schema.iniは削除しない(自動で作成されるとは限らないため)
'If .FileExists(strDelFile5) Then
' .DeleteFile strDelFile5
'End If
' 既存の出力結果を削除
If .FileExists(testPath & "time_master.csv") Then
 .DeleteFile testPath & "time_master.csv"
End If
If .FileExists(testPath & "time_master1.csv") Then
 .DeleteFile testPath & "time_master1.csv"
End If
End With
' ADO Create
Set objADO = CreateObject("ADODB.Connection")
' ADO Open 今回のVBSでは64bitか判定し、64bitならAccess、そうでなければ32bitでAccessかただのText Driverで開く。
On Error Resume Next
IF LCase(CreateObject("WScript.Shell").Environment("Process").Item("PROCESSOR_ARCHITECTURE"))="amd64" Then
objADO.Open "Provider=MSDASQL;Driver={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
Else
'32 bit Microsoft Text Driver
objADO.Open "Provider=MSDASQL;Driver={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
If err.number <> 0 then 
Err.Clear
objADO.Open "Provider=MSDASQL;Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
End If
End If

' Select Into 全部そのまま出すのと、集計クエリを用いるのを同時にやる
objADO.Execute "Select * INTO time_master1.csv From log_master1.csv;"
objADO.Execute _
"/SELECT [コンピューター名], Format([日時],'yyyy/mm/dd') AS [日付], Format(Sum([期間]),'hh:nn:ss') AS [利用時間計]" & _
" INTO time_master.csv" & _
" FROM log_master1.csv where [操作種別] = '終了'" & _
" GROUP BY [コンピューター名], Format([日時],'yyyy/mm/dd');" 
objADO.Close
Set objADO = Nothing
' 出来上がったものを開く。このスクリプトもバッチファイルもすべて。ODBCアドミニストレータも(フォルダはBatファイルで開いている)
With CreateObject("Wscript.Shell")
Wscript.Sleep 1000
.Run "Notepad.exe """ & testPath & "time_master1.csv" & """"
Wscript.Sleep 1000
.Run "Notepad.exe """ & testPath & "time_master.csv" & """"
Wscript.Sleep 1000
.Run "Notepad.exe """ & testPath & "Schema.ini" & """"
Wscript.Sleep 1000
.Run "Notepad.exe """ & testPath & "filename.vbs" & """"
Wscript.Sleep 1000
.Run "Notepad.exe """ & testPath & "log_master1.csv" & """"
Wscript.Sleep 1000
.Run "%systemroot%\sysWow64\odbcad32.exe"
Wscript.Sleep 1000
.Run "%systemroot%\system32\odbcad32.exe"
End With
```

実際はどこかでやっているのかも知れませんが、これでTextDriverがどちらでも64bitでも32bitでもAccessTextDriverを入れている限り動きます。

#おわりに
それでは実験が終わりましたので、Access Text Driverなら
`C:\Windows\System32\odbcad32.exe`
から削除
Microsoft Text Driverなら
`C:\Windows\SysWOW64\odbcad32.exe`
してください。
#ついでにVBA

条件付き編纂命令Const Directiveを使います。VBA7はいらないかな。
未確認ですが、これで動くでしょう。

```vb
Const testPath = "c:\csvtest\"
#IF WIN64 Then
objADO.Open "Provider=MSDASQL;Driver={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
#ElseIF Win32 Then
On Error Resume Next
'32 bit Microsoft Text Driver
objADO.Open "Provider=MSDASQL;Driver={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
If err.number <> 0 then 
Err.Clear
objADO.Open "Provider=MSDASQL;Driver={Microsoft Text Driver (*.txt; *.csv)};DBQ=" & _
 strPath & ";DefaultDir='" & Left(strPath,Len(strPath) -1) &"';ReadOnly=0"
End If
#End IF
```

#全体の目次
[VBS 64bit Ado で CSV を DBQ でOpenして　集計してSelect Intoで別のCSVに入れる](https://qiita.com/Q11Q/items/be9bc7cfdfc8b3a69a1b)
[VBS 64bit Ado で utf-8(BOMありなし両方) csv を DBQ で Open して Select Into で別のcsvに集計クエリも使用して入れる](https://qiita.com/Q11Q/items/b4ce72054898de2a6534)
[VBS ADO CSV のText Driver の64 bit Windows と32 Bit Windowsの違いと対応策](https://qiita.com/Q11Q/items/4220631d095599b4f127)
派生
[今日のトリビア Notepadのバグ？を利用すると、最新のWin10(2019 May Later)はFilesystemObjectで UTF-8のテキストファイルが作成できる](https://qiita.com/Q11Q/items/a8226c70532bf0716bdd)
[[VBS] ADODB.Streamで使える文字コード一覧の取得](https://qiita.com/Q11Q/items/a8226c70532bf0716bdd)