ObjeqtNote #24 選択したファイルの拡張子を取得する

久しぶりのObjeqtNoteの修正。
スタティックなGetOpenFileNameを実装して、選択したファイルの拡張子を取得する。

BinaryFile.hで、

シェルAPIを使うので、shlwapi.hを追加する。

f:id:BG1:20170414121500p:plain

リンクにも追加する。

staticなpublicメンバGetOpenFileNameを追加で定義。

BinaryFile.cppは、

GetOpenFileNameをこんな感じで実装。

MainMenuBar.cppでは、

TextFile.hのインクルードをBinaryFile.hのインクルードにして、CBinaryFile::GetOpenFileNameで拡張子を取るようにする。
txtなら"テキストファイル"、bmpなら"ビットマップファイル"と表示する。

とりあえず、OnFileSaveAsの中の処理はいったん白紙に戻しておく。

MainWindow.cppは、

ユーザコントロールやエディットボックスの処理は削除。

f:id:BG1:20170414123053p:plain

ウィンドウが表示されたら、

f:id:BG1:20170414123141p:plain

"開く"から、

f:id:BG1:20170414123209p:plain

test1.txtを選択する。

f:id:BG1:20170414123300p:plain

txtなので"テキストファイル"と表示される。

・選択したファイルの拡張子を取得する · bg1bgst333/ObjeqtNote@f3b9a53 · GitHub
fixed comment · bg1bgst333/ObjeqtNote@7ec5216 · GitHub

BIO_new_connect

libjpeg以来のオープンソース編・・・。

OpenSSLは、SSL通信を実現するためのオープンソースライブラリ・・・。

/index.html

まずは非セキュアな接続から始めてみる・・・。

今回は、

OpenSSL API によるセキュア・プログラミング: 第 1 回 API の概要

を参考に、BIO_new_connectで接続の作成を行う・・・。

/docs/man1.0.2/crypto/BIO_new_connect.html

OpenSSL自体は、手元のFedoraに入っているが、ヘッダなどが無いので、

$ sudo yum install openssl-devel
[sudo] xxx のパスワード:
Yum command has been deprecated, redirecting to '/usr/bin/dnf install openssl-devel'.
See 'man dnf' and 'man yum2dnf' for more information.
To transfer transaction metadata from yum to DNF, run:
'dnf install python-dnf-plugins-extras-migrate && dnf-2 migrate'

メタデータの期限切れの確認は、1:01:43 時間前の Thu Apr 13 15:58:33 2017 に実施しました。
依存性が解決されました。
================================================================================
 Package                  アーキテクチャ
                                      バージョン             リポジトリ    容量
================================================================================
インストール:
 keyutils-libs-devel      x86_64      1.5.9-8.fc24           fedora        46 k
 krb5-devel               x86_64      1.14.1-6.fc24          fedora       652 k
 libcom_err-devel         x86_64      1.42.13-4.fc24         fedora        36 k
 libselinux-devel         x86_64      2.5-3.fc24             fedora       192 k
 libsepol-devel           x86_64      2.5-3.fc24             fedora        79 k
 libverto-devel           x86_64      0.2.6-6.fc24           fedora        16 k
 openssl-devel            x86_64      1:1.0.2k-1.fc24        updates      1.5 M
 pcre-devel               x86_64      8.38-11.fc24           fedora       543 k
 zlib-devel               x86_64      1.2.8-10.fc24          fedora        55 k

トランザクションの要約
================================================================================
インストール  9 パッケージ

総ダウンロード容量: 3.1 M
インストールされる容量: 6.9 M
これでいいですか? [y/N]: y
パッケージをダウンロードしています:
(1/9): zlib-devel-1.2.8-10.fc24.x86_64.rpm      107 kB/s |  55 kB     00:00    
(2/9): libselinux-devel-2.5-3.fc24.x86_64.rpm   274 kB/s | 192 kB     00:00    
(3/9): libsepol-devel-2.5-3.fc24.x86_64.rpm     107 kB/s |  79 kB     00:00    
(4/9): keyutils-libs-devel-1.5.9-8.fc24.x86_64.  61 kB/s |  46 kB     00:00    
(5/9): libcom_err-devel-1.42.13-4.fc24.x86_64.r  61 kB/s |  36 kB     00:00    
(6/9): libverto-devel-0.2.6-6.fc24.x86_64.rpm   111 kB/s |  16 kB     00:00    
(7/9): krb5-devel-1.14.1-6.fc24.x86_64.rpm       82 kB/s | 652 kB     00:07    
(8/9): pcre-devel-8.38-11.fc24.x86_64.rpm        54 kB/s | 543 kB     00:09    
(9/9): openssl-devel-1.0.2k-1.fc24.x86_64.rpm    80 kB/s | 1.5 MB     00:19    
--------------------------------------------------------------------------------
合計                                            151 kB/s | 3.1 MB     00:20     
トランザクションの確認を実行中...
トランザクションの確認に成功しました。
トランザクションのテストを実行中...
トランザクションのテストに成功しました。
トランザクションを実行中...
  インストール  : pcre-devel-8.38-11.fc24.x86_64                            1/9 
  インストール  : libverto-devel-0.2.6-6.fc24.x86_64                        2/9 
  インストール  : libcom_err-devel-1.42.13-4.fc24.x86_64                    3/9 
  インストール  : keyutils-libs-devel-1.5.9-8.fc24.x86_64                   4/9 
  インストール  : libsepol-devel-2.5-3.fc24.x86_64                          5/9 
  インストール  : libselinux-devel-2.5-3.fc24.x86_64                        6/9 
  インストール  : krb5-devel-1.14.1-6.fc24.x86_64                           7/9 
  インストール  : zlib-devel-1.2.8-10.fc24.x86_64                           8/9 
  インストール  : openssl-devel-1:1.0.2k-1.fc24.x86_64                      9/9 
  検証中        : openssl-devel-1:1.0.2k-1.fc24.x86_64                      1/9 
  検証中        : zlib-devel-1.2.8-10.fc24.x86_64                           2/9 
  検証中        : krb5-devel-1.14.1-6.fc24.x86_64                           3/9 
  検証中        : libselinux-devel-2.5-3.fc24.x86_64                        4/9 
  検証中        : libsepol-devel-2.5-3.fc24.x86_64                          5/9 
  検証中        : keyutils-libs-devel-1.5.9-8.fc24.x86_64                   6/9 
  検証中        : libcom_err-devel-1.42.13-4.fc24.x86_64                    7/9 
  検証中        : libverto-devel-0.2.6-6.fc24.x86_64                        8/9 
  検証中        : pcre-devel-8.38-11.fc24.x86_64                            9/9 

インストール済み:
  keyutils-libs-devel.x86_64 1.5.9-8.fc24   krb5-devel.x86_64 1.14.1-6.fc24     
  libcom_err-devel.x86_64 1.42.13-4.fc24    libselinux-devel.x86_64 2.5-3.fc24  
  libsepol-devel.x86_64 2.5-3.fc24          libverto-devel.x86_64 0.2.6-6.fc24  
  openssl-devel.x86_64 1:1.0.2k-1.fc24      pcre-devel.x86_64 8.38-11.fc24      
  zlib-devel.x86_64 1.2.8-10.fc24          

完了しました!
$

openssl-develをインストール・・・。

BIO_new_connect.cで、

非セキュアでもセキュアでもBIO構造体を通して行う・・・。
BIO_new_connectにサーバ名とポート番号を指定して、戻り値のBIO構造体へのポインタをbioに格納する・・・。
(今回は443を指定しているが、非セキュアな接続で使うものなので80のほうが正しいかも・・・。とはいえ、443でもオープンはできる・・・。)
bioがNULLならエラー処理・・・。
NULLでなければ成功で、接続の作成ができたので、"BIO_new_connect success!"とともにポインタbioのアドレス値を出力・・・。
BIO_free_allは、開いたソケットをクローズして、さらにbioの参照先メモリを解放する・・・。

これで、libsslとlibcryptoをリンクしてコンパイルして実行・・・。

$ vi BIO_new_connect.c 
$ gcc -o BIO_new_connect BIO_new_connect.c -lssl -lcrypto
$ ./BIO_new_connect 
BIO_new_connect success! bio = 01963030
$

こんな感じで、bioが取得出来たので、とりあえず接続の作成はできた模様・・・。

Sample/openssl/BIO_new_connect/BIO_new_connect/src/BIO_new_connect at master · bg1bgst333/Sample · GitHub

yield

前回、IEnumeratorを継承したオブジェクトを作ってGetEnumeratorで返すことで、foreachによるアクセスを可能にした。
しかし、いちいちオブジェクトを作るのも大変・・・。

GetEnumerator内で、要素ごとにyield returnすれば、その要素を持つ仮想のコレクションオブジェクトを作成し、IEnumeratorを返してくれる・・・。

TestCollection.csでは、

オブジェクトは用意せず、yield returnの後に、要素とする値を指定するだけである・・・。
returnが複数あるのも不思議な感じがするが、foreachで取り出される時、yield returnのところで一旦処理は終了する・・・。
そして、次の要素の取出しの時には、次のyield returnのところまで処理する・・・。
これが繰り返されていくのである・・・。

MainClass.csで、

foreachで値を取り出してみる・・・。

yield return 1 before.
value = 1
yield return 3 before.
value = 3
yield return 5 before.
value = 5
yield return 7 before.
value = 7
yield return 9 before.
value = 9
続行するには何かキーを押してください . . .

このように、foreachの値の取出し時にyield returnのところに来てるのがわかる・・・。

Sample/cs/yield/yield/src/yield at master · bg1bgst333/Sample · GitHub

IEnumerator

前回は、配列が持っているGetEnumeratorメソッドでIEnumeratorを返すことができた・・・。

IEnumerator インターフェイス (System.Collections)

IEnumeratorは、C++でいうイテレータで、コレクションの次の要素の取出しをするためのインターフェイス・・・。

今回は、これを継承したクラスを実装して、GetEnumeratorで返す・・・。

int配列の参照container、サイズのlength、現在位置(正確には+1)を持つindexを用意・・・。

Currentプロパティのgetで、index-1の指しているオブジェクトを返す・・・。

コンストラクタは渡された配列con、サイズlenをセットし、indexは0に・・・。

MoveNextでは、1つindexを増やし、indexが範囲内ならtrue、そうでないならfalseを返す・・・。

これまで、index-1としているが、これはforeachが、

IEnumerator enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
    object obj = enumerator.Current;
}

このように、enumerator.MoveNext()を最初に呼ぶ前方評価で取り出しているせいでこうなっている・・・。
※.最初はindexでつくったが、おかしいとおもったら、foreachはそういう仕様らしい・・・。後方評価のほうがindexですっきりするのに・・・。
だから、indexは内部では1から始まるが、外から配列にアクセスするときは0からになるようにしている・・・。

今回Resetは使わない・・・。

このようなインターフェイスを使うことで、どんなコレクションでも取り出せる(今回はint配列だけだが・・・。)

TestCollection.csは、

collection本体はこちらでもっている・・・。
collectionをこちらで生成して、testEnumeratorにcollectionとサイズlenを渡してる・・・。
IEnumeratorは列挙しかできないので、個別の値のセットはインデクサで・・・。

testCollectionをサイズ5で生成し、4, 2, 1, 3, 5という感じで値をセット・・・。
foreachで取り出すと、

GetEnumerator()
MoveNext, index = 0
index = 0, Current = 4
value = 4
MoveNext, index = 1
index = 1, Current = 2
value = 2
MoveNext, index = 2
index = 2, Current = 1
value = 1
MoveNext, index = 3
index = 3, Current = 3
value = 3
MoveNext, index = 4
index = 4, Current = 5
value = 5
続行するには何かキーを押してください . . .

このように出力される・・・。

foreachの、

foreach (int value in testCollection)

ここでGetEnumeratorが呼ばれて、IEnumerator操作のできるオブジェクトが生まれている・・・。
あとはループするごとに、MoveNextとCurrentが呼ばれる・・・。

Sample/dotnet/IEnumerator/IEnumerator/src/IEnumerator_ at master · bg1bgst333/Sample · GitHub

IEnumerable

配列やリストなどのコレクションクラスは、foreachを使って、各要素を取り出すことができた・・・。
では、foreachで各要素を取り出せるようなコレクションクラスを作るにはどうしたらいいか・・・。
そのクラスにIEnumerableインターフェイスを実装すればいい・・・。

IEnumerable インターフェイス (System.Collections)

IEnumerableインターフェイスを実装したクラスは、GetEnumeratorメソッドを実装する必要がある・・・。
戻り値がIEnumeratorとなっているが、これはどうしよう・・・。

配列もコレクションの一つなのでIEnumerableを持っている・・・。
とりあえず、今回は、内部で配列を生成して、その配列オブジェクトのGetEnumeratorをそのまま返そう・・・。

TestCollection.csを追加して、

GetEnumeratorの中で、要素数5の配列を用意し、0から4をセットして、その配列arrayのGetEnumeratorでIEnumeratorを返す・・・。

MainClass.csは、

TestCollectionオブジェクトtestCollectionを生成して、foreachで中身を全部取り出して出力・・・。

value = 0
value = 1
value = 2
value = 3
value = 4
続行するには何かキーを押してください . . .

GetEnumerator内部で生成した配列の各値が、そのままforeachでtestCollectionの各要素の値として取り出され、出力された・・・。
なんか不思議な感じである・・・。

ひとまず、IEnumerableをこんな感じで実装すると、foreachで取り出せるのがわかる・・・。

Sample/dotnet/IEnumerable/IEnumerable/src/IEnumerable_ at master · bg1bgst333/Sample · GitHub

Array

配列も1つのオブジェクトであり、すべての配列はArrayクラスを継承している・・・。

Array クラス (System)

配列がArrayクラスの派生であることの確認と、Arrayが持つプロパティLengthで配列のサイズを取得する・・・。

intArray.GetType().ToString()で型名を出力する・・・。

そして、intArrayがArrayクラスの派生クラスならば、is演算子でキャスト可能かどうかがわかるはず・・・。
(is演算子はキャスト可能かどうか、つまり基底クラスなのかを判定する演算子・・・。詳細はいずれ扱う・・・。)

その後、intArray.Lengthに配列のサイズが入ってるので、sizeに格納して出力・・・。

intArray: System.Int32[]
intArray is Array!
size = 5
続行するには何かキーを押してください . . .

GetType()では、System.Int32[]と出る・・・。
intArrayそのものはInt32[]だが、その後のis演算子でArrayの派生クラスであることはわかる・・・。
Int32[]がArrayの派生クラスというのは、そういう定義があるというより、

csharplang/arrays.md at master · dotnet/csharplang · GitHub

そういう仕様らしい・・・。

intArray.Lengthには、配列の要素数5が入っている・・・。

Sample/dotnet/Array/Array/src/Array_ at master · bg1bgst333/Sample · GitHub

String

Stringクラスは、エイリアスであるstring型の実体・・・。

String クラス (System)

Stringとstringが同じかどうかの確認・・・。
また、IndexOfメソッドで指定の文字が何番目にあるかをチェック・・・。

strTypeに"ABC"、strClassに"XYZ"をセット・・・。
(クラスなので最初はnullだが、newがなくても代入だけでインスタンスができるみたい・・・。)

型名の出力・・・。

strType.IndexOfで'B'がstrTypeの何番目かを取得し、int型indexに格納・・・。
indexを出力・・・。

strType: System.String
strClass: System.String
index = 1
続行するには何かキーを押してください . . .

結果はこうなる・・・。

Sample/dotnet/String/String/src/String_ at master · bg1bgst333/Sample · GitHub