mogmo .NET

C#/XAML/VB6たまにC++についてメモ程度に書いていく。あくまで自分用。責任は取れません。

VBA|基本①データ型,繰り返し,配列など 

こんにちは。もぐもです。
VBAを基礎から見直す機会があったので投稿します。

そもそもVBAってなに

  • Visual Basic for Applicationsの略
  • MicroSoftのOffice製品の一部(ExcelやWordなど)で利用可能なプログラミング言語
  • プログラムすることで複雑な処理を自動化できますよって機能

環境を整える

エクエルのオプションから開発タブを表示する設定に変更する。
Visual BasicあいこんからVisual Basic Editorを表示する。
挿入>標準モジュールに処理を書いていく

基本の文法

プロシージャ

関数のこと。
Sub~End Subで囲んだ内容が一つの処理として認識される。
プロシージャ名は日本語も使えるが,必ず文字始まりでなければいけない。

Sub プロシージャ名()
End Sub
プロシージャ内部の書き方
Sub Test()
    '一行ずつ処理を書く
    Range("A1").Value = 100
    Range("A2").Value = 200
    
    '一行に複数の処理を書く場合は :(コロン) をつかう
    Range("A1").Value = 100: Range("A2").Value = 200
    
    '複数行に分けるときは _(アンダーバー)をつかう
    Range("A1").Value = 100
    Range("A2").Value _
        = 200
End Sub

変数

Sub Test2()
    '変数の宣言 Dimを先頭に書くことで変数を宣言できる
    Dim name
    Dim age
    Dim level
    
    '格納するデータ型がバラバラでも,カンマで1行にまとめて宣言することもできる
    'Dim name, age, level
    
    '変数の格納: =(イコール)を用いて値を格納する
    name = "もぐも" '文字列は "(ダブルクォーテーション) で囲む
    age = 28
    level = 1
    
    '変数の値をセルに表示する
    Range("A1").Value = name
    Range("A2").Value = age
    Range("A3").Value = level
End Sub
データ型

公式文書:
データ型の概要 | Microsoft Docs

データ型の種類は以下の表のとおり。

データ型 バイト数 値の範囲
Boolean 2バイト True/False
Byte 1バイト 0 ~ 255
Collection 不明 不明
Currency(通貨型) 8バイト -922,337,203,685,477.5808 ~ 922,337,203,685,477.5807
Date 8バイト 100 年 1 月 1 日 から 9999 年 12 月 31 日
Decimal 14バイト 公式サイト参照
Dictionary 不明 不明
Double 8バイト ±double max ~ ±double min
Integer 2バイト -32,768 ~ 32,767
Long 4バイト -2,147,483,648 ~ 2,147,483,647
LongLong 8バイト -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
Object 4バイト 任意
Single 4バイト ±3.402823E+38 から ±-1.401298E-45
String(可変長) 10バイト+文字列の長さ 0~約 20 億
String(固定長) 指定した文字列の長さ 1 ~ 約 65,400
Variant(数値型) 16バイト 最大でDoubleの範囲までの任意の数値
Variant(文字列型) 22 バイト + 文字列長 (64 ビット システムでは 24 バイト) String(可変長)と同じ範囲

※ LongLong: 64ビットプラットフォームでのみ有効
※LongPtr,Typeは割愛した

数値型の場合,整数型はByte,Integer,Longがある。(64ビットではLongLongも利用可能)
浮動小数点の場合はSingle,Doubleがある。しかしこの2つのデータ型には有効桁数が決まっており計算を行えば桁落ちが発生したり,表現できない値が出てくる。正確な計算を強いられる場面ではCurrencyを用いると良い。

データ型を指定して変数を宣言

As を用いて変数のデータ型を指定できる。

Sub Test3()
    '変数の型を指定して宣言: As を用いる
    Dim name As String
    Dim age As Byte
    Dim level As Integer
        
    'カンマで1行にまとめて宣言する場合
    'Dim name As String, age As Byte, level As Integer
End Sub
日付型

#で囲むか文字列として指定する

Dim x As Date

x = "2020年10月12日"
x = #20201012日#
x = #2020/10/12#
x = #12/10/2020#
x = #12:26:39 AM#

演算子

算術演算子
Sub Test()
    Dim x As Integer
    Dim y As Single
    
    x = 5 + 2 '足し算 = 7
    x = 5 - 2 '引き算 = 3
    x = 5 * 2 '掛け算 = 10
    y = 5 / 2 '割り算 = 2.5
    x = 5 \ 2 '割り算の商 = 2
    x = 5 Mod 2 '割り算の余り = 1
    x = 5 ^ 2 'べき乗 = 25
End Sub
比較演算子

結果はBoolean型で返ってくる。
C++C#と違うのは等しい,等しくないの演算子の書き方。

Sub Test()
    Dim result As Boolean
    result = 8 < 5  'より小さい False
    result = 3 <= 5 '以下 True
    result = 8 > 5  'より大きい True
    result = 3 >= 8 '以上 False
    result = 3 = 8  '等しい False
    result = 3 <> 8 '等しくない True
    
    Range("A1").Value = 10 > 20 'セルA1にFALSEが表示される
End Sub
論理演算子
Sub Test()
    Dim result As Boolean
    '論理積 And
    result = (3 < 5) And (2 < 5) '=True
    '論理和 Or
    result = (3 > 5) Or (2 > 5) '=Flase
    '論理否定 Not
    result = Not (3 < 5) '=False
End Sub

文字の結合

& と +が使えるが,&のほうがケアレスミスが減るかも。

Sub Test()
    Dim hello As String
    Dim name As String
    Dim a As Integer
    Dim b As Integer
    
    hello = "こんにちは"
    name = "もぐも"
    a = 10
    b = 12
    
    Range("A1").Value = hello & name '=こんにちはもぐも
    Range("A2").Value = hello & a '=こんにちは10
    Range("A3").Value = a & hello '=10こんにちは
    Range("A4").Value = a & b '=1012
    
    Range("A5").Value = hello + name 'こんにちはもぐも
    'Range("A6").Value = hello + a 'Error: 型が一致しません
    'Range("A7").Value = a + hello 'Error: 型が一致しません
    Range("A8").Value = a + b '=22
End Sub

オブジェクト

  • データ型の1つ
  • ブックやシート,セルなどVBAで何か操作をしようとする対象となるもの
  • 値の格納にはSetを先頭に書かなければならない
Sub Test()
    'オブジェクト: VBAで何か操作しようとする対象となるもの
    
    'オブジェクトの宣言
    Dim app As Application 'アプリケーション
    Dim book As Workbook 'ブック
    Dim sheet As Worksheet 'シート
    Dim cell As Range 'セル
    Dim books As Workbooks '開いている全てのブック
    Dim sheets As Worksheets 'ブックに含まれる全てのワークシート
    
    '値を格納する: Setを使って格納すること
    Set cell = Range("A1")
    cell.Value = "cellにA1のセルを格納しました"

    'オブジェクトのプロパティやメソッドは.(ドット)を用いて利用することが可能
    cell.Value = "プロパティを変更" 'プロパティ値を変更
    
    Dim test As String 'プロパティ値を取得
    test = cell.Value
    
    cell.Delete 'メソッドを利用
End Sub

条件分岐

If と Select(C++C#ではswitchに相当する) が使える。

Sub test()
    Dim cell As Range
    Set cell = Range("A1")
    
    '条件分岐①: If 条件式 Then ~ ElseIf 条件式 Then ~ Else ~ End If
    If (cell.Value = "") Then '空白なら
        cell.Value = "あ"
    ElseIf (cell.Value = "あ") Then
        cell.Value = "い"
    Else
        cell.Value = "う"
    End If
    
    '条件分岐②-1: Select
    Select Case cell.Value
        Case ""
            cell.Value = "あ"
        Case "あ"
            cell.Value = "い"
        Case Else
            cell.Value = "う"
    End Select
    
    '条件分岐②-2: 比較演算子の省略
    Dim x As Integer
    x = 10
    
    Select Case x
        Case Is > 20
            cell.Value = "20より大きい"
        Case Is > 5
            cell.Value = "5より大きい"
        Case Else
            cell.Value = "5以下の値です"
    End Select
End Sub

繰り返し

Sub test()
    Dim sum As Integer
    
    '繰り返し①: Do While ... Loop
    Dim sum As Integer
    Dim x As Integer
    sum = 0
    x = 1

    Do While x <= 10 '条件式 xが10以下 がTrueなら繰り返す
        sum = sum + x
        x = x + 1
    Loop
    
    '繰り返し②: Do Until ... Loop
    sum = 0
    x = 1
    Do Until x > 10 '条件式 xが10より大きい がFalseの場合は繰り返す
        sum = sum + x
        x = x + 1
    Loop
    
    '繰り返し③: Do ... Loop While
    '処理を行った後に条件式の判定を行う。つまり必ず1度は繰り返し処理を行う。
    sum = 0
    x = 1
    Do
        sum = sum + x
        x = x + 1
    Loop While x <= 10 '条件式 xが10以下 がTrueなら繰り返す
        
    '繰り返し④: For a To b ~ Next
    sum = 0
    For x = 1 To 10
        sum = sum + x
    Next i
    
    Range("A1").Value = sum
End Sub

配列

配列の宣言は

Dim 変数名(要素数-1) As データ型

と行う。
変数名(3 To 6)と宣言する方法もあるが,保守しやすいとは思わないので割愛する。

サンプル

Sub Test()
    '配列の宣言: 配列数10個
    Dim collection(9) As Integer
    
    collection(0) = 1
    collection(1) = 2
    collection(2) = 3
    collection(3) = 4
    collection(4) = 5
    collection(5) = 6
    collection(6) = 7
    collection(7) = 8
    collection(8) = 9
    collection(9) = 10
    'collection(10) = 11 '要素数を超えたらエラーとなる
    
    Dim i As Integer
    For i = 0 To 9
        Range("A1").Value = collection(i)
    Next i
End Sub

参考

Excel VBA入門 ~基本的な使い方から高度な利用方法までサンプルを使って解説します~
こちらのサイトをもとに学習しています。

ではまた(`・ω・´)
もぐも

リモートコードレビューを試した - 失敗

もぐもです。試験的に在宅勤務が開始されました。
そこで,りもーど環境でコードビューを試してみようとしたところ問題点だらけ...
次回コードレビューを行うときはこの問題点を解決しなければならない。

試そうとしたこと

  • VS 2019 の Live Share 機能を使ってリモートコードレビューをしようとした。
  • ビデオ通話はGoogleのハングアウトかmeetしか使えない

問題点

  • ハングアウト,Meetでマイク,ビデオ環境をテストしていなかった
  • そもそもVS2019をインストールしてない人がいた
  • Live Shareは問題なく開始できたが,文章の途中でテキストの色分けがint や void 以外すべてコメント色になってしまい読みづらさMAX
  • MFCアプリケーションのコードレビューを行ったが実際の動作を確認したい → exeはファイル転送サービスを利用して受け渡しするしか思いつかなかった。泥臭い。

C++ | テンプレートの実装はヘッダファイルに書かなければならない

f:id:mogmo811:20200402170734j:plain

こんにちは。もぐもです。
久しぶりにC++を触っています。

さて,C++MFCアプリケーションを実装している際に,以下のようなエラーが出て四苦八苦しました。

LNK2019 未解決の外部シンボル "public: static int __cdecl Calc::Add(int,int)" (?Add@?$Calc@H@@SAHHH@Z) が関数 "private: void __thiscall CMFCApplication1Dlg::Adding(void)" (?Adding@CMFCApplication1Dlg@@AAEXXZ) で参照されました。

結論から言うと

原因を調べた結果,分割コンパイルによる実体の不在のためにおこるリンクエラーのようです。
対策は,テンプレートクラスや関数の実装をヘッダファイルで行うことでコンパイルが通ります。

原因について

サンプルコード

エラーの出るサンプルコードを記載します。
プロジェクトはMFCアプリケーションで作成しました。
MFCApplication1Dlgクラス の Adding関数 の中で Calcクラス の Add関数 を呼ぶコードになっている。

/* Calc.h */

#pragma once
template<class T>
class Calc
{
public:
    static int Add(T a, T b);
};
/* Calc.cpp */

#include "pch.h"
#include "Calc.h"

template<class T>
inline int Calc<T>::Add(T a, T b)
{
    return a + b;
}
/* MFCApplication1Dlg.cpp */

#include "Calc.h"

// ----- 省略 -----

void CMFCApplication1Dlg::Adding()
{
	int sum = Calc<int>::Add(10, 20);
}

ビルドするとどうなるか

ビルド出力は以下のようになった。

1>------ すべてのリビルド開始: プロジェクト:MFCApplication1, 構成: Debug Win32 ------
1>pch.cpp
1>Calc.cpp
1>MFCApplication1.cpp
1>MFCApplication1Dlg.cpp
1>コードを生成中...
1>MFCApplication1Dlg.obj : error LNK2019: 未解決の外部シンボル "public: static int __cdecl Calc::Add(int,int)" (?Add@?$Calc@H@@SAHHH@Z) が関数 "private: void __thiscall CMFCApplication1Dlg::Adding(void)" (?Adding@CMFCApplication1Dlg@@AAEXXZ) で参照されました。
1>C:\Users\***\repos\MFCApplication1\Debug\MFCApplication1.exe : fatal error LNK1120: 1 件の未解決の外部参照
1>プロジェクト "MFCApplication1.vcxproj" のビルドが終了しました -- 失敗。
========== すべてリビルド: 0 正常終了、1 失敗、0 スキップ ==========

Calc.cppコンパイル時,Add関数を使っている箇所が見当たらない→Add関数のテンプレートの実体化が行われません。
もっと言えば,今回のコードの場合がCalc自体がテンプレートクラスなのですが,Calcクラスを使用している箇所が見当たらないため,クラスの実体化も行われません。
結果,実体化していない状態でCalc.objファイルが生成されます。

次に,MFCApplication1Dlg.cppのコンパイルです。
MFCApplication1Dlg.cppではAdding関数でCalcクラスのAdd関数を使用していますが,Calc.hに宣言されているので実体の有無にかかわらずコンパイルが通り,MFCApplication1Dlg.objファイルが生成されます。

さて,これでコードを生成しようとすると,MFCApplication1Dlg.objちゃんはCalcクラスのAdd関数をCalc.objから探し出そうとしますが,Calc.objは分割コンパイル時に実体化が行われていないのでint型のAdd関数は存在しません。
よって,未解決の外部シンボルエラーが発生するという流れでビルドエラーになります。

正しい実装方法

インライン関数でヘッダファイルに実装します。
Calc.cppは空でOKです。

/* Calc.h */

#pragma once
template<class T>
class Calc
{
public:
    static int Add(T a, T b);
};

template<class T>
inline int Calc<T>::Add(T a, T b)
{
    return 0;
}

参考

以下ブログを参考にしました。
テンプレートの実装をヘッダに書かなければならない理由 - (void*)Pないと

せっかくなので自分の言葉で書いてみました。
間違い等あれば連絡ください。

ではまた。
もぐも(`・ω・´)🍙

Git|SSHで接続できなくなった

新しい環境でリモートリポジトリをクローン出来なくなったのでさあ困った。ってなったときに対処した方法。

結果

lipoyang.hatenablog.com
を見ていると,ユーザー設定がおかしそうだいうことが分かった。
どうやらサーバーが受け取るユーザIDの設定が違うので,接続できないという状況。。。
userhostsの中身を修正したら無事接続できた。

紆余曲折

一応メモっとく。

  • コマンドプロンプトSSH接続→できる
  • SourceTreeオプション>認証を確認→本来ここにアカウント設定が確認できない
  • パスワードを保存している場所を探し出す

メイン画面が起動する前にダイアログを表示する

メイン画面を起動する前に独自のダイアログを表示したくて調べた。
ログイン画面を表示する時なんかが多いかもしれない。

問題点

App.xaml.csでMainWindowを表示する前にダイアログを表示するコードを書いて実行すると,ダイアログを閉じたらアプリケーションが終了してしまい,MainWindowが開きません。
この対策についてメモしておく。

対策1 ShutdownModeを設定する

アプリケーションの実行停止モードを設定してダイアログをとじてもアプリが終了しないようにしてしまう方法。

ShutdownMode 説明
OnLastWindowClose[規定値] アプリケーションの最後のウィンドウを閉じると暗黙的に終了
OnMainWindowClose Application.MainWindowプロパティに割り当てられているウィンドウが閉じた時暗黙的に終了
OnExplicitShutdown 手動でShutdown();するまで終了しない

ShutdownMode公式ドキュメント→Application.ShutdownMode プロパティ (System.Windows) | Microsoft Docs

事前にMainWindowプロパティにメイン画面を登録できない & 元の値に戻さなければならない都合が合って以下のような書き方になっているが,参考までに載せておく。

var dialog = new SampleDialog();
var temp = Current.ShutdownMode;
Current.ShutdownMode = ShutdownMode.OnExplicitShutdown; // memo: 一時的な変更
if (dialog.ShowDialog() != true)
{
	this.Shutdown();
}
Current.ShutdownMode = temp; // memo: 元に戻す


ではまた。
もぐも

テストケース管理の基礎知識

弊社はクラウドサービスの使用が禁止されているため,世に出ている便利ツールのほとんどが使えない。
Googleサービスはギリギリ使用OKなのでテスト項目管理ツール「Qase」を参考にスプレッドシートでどうにかテストケース管理できないか試行錯誤している。

テストスイート

グループ化されたテストケースのコレクションのこと。
とりあえずテストケースの種類ごとにテストスイートを作成すると良さそう。
テストスイート単位でテストプランを設定,実行することが多いと思うのでテストスイート設計時はテストプランも考えながらやると良い。
(例)

  • テストスイート 回帰テスト
    • テストスイート システム系
      • テストケース1
      • テストケース2
  • テストスイート 機能テスト
      • テストケース3

テストケース

種類

覚えておきたい種類は以下の通り。

  • スモークテスト
    • 本格的なテストに着手可能かどうか確認するテスト。「開発者さん,これができる状態でテスト部隊にソフトを渡してね」っていうテスト
    • テストエンジニアがいればスモークテストは必要かもしれない。
  • 機能テスト:ソフトウェアの仕様を満たしているか確認するテストのこと
  • 回帰テストリグレッションがないか確認するテスト
  • セキュリティテスト
  • ユーザビリティテスト
  • パフォーマンステスト
    • 負荷テスト
    • ストレステスト
    • キャパシティ(処理能力)テスト
  • 受け入れテスト:納入されたソフトの受け入れを判定するための公式テストのこと
  • その他:

テストについて

Googleスプレッドシートでテストケースを管理しているチームは世の中にどれくらいいるんだろう。。
うちの会社ではスプレッドシートやエクセルがゴリゴリに使われているので,無償のツールで成果を出さないと導入が厳しい。
という背景があり,テストケース管理ができるツールを調べてみた。

テストケース管理ツール

有料のものはごろごろある。
無料で使えるのは数少ないが「Qase」がよさそう。

Qase

Qase | Test case management software

  • メリット
    • 無料版でもユーザ制限やテストケース数に制限がない
    • ※ただし,500MBまでの容量制限はある
  • デメリット
    • 日本語非対応なので最初は学習コストちょい高い
    • エクスポートすると日本語が文字化けする。ShiftJisにエンコードする必要あり
    • 私のPCだと,Microsoft Edgeブラウザじゃないとテストケース作成ページのコンボボックスが表示されない

Klaros

Klaros Test Management - Professional Test Case Management Software
ドイツのテスト管理ソフトウェアみたい。

  • メリット
    • 買い切りプランがあるみたい
  • デメリット
    • 文献が少なそう
    • ちょっと使ってみたが直感的には操作できなさそう

Klaros Test Management - Professional Test Case Management Software

テストコード

テストコードが必要かどうか

必要ではあるが,どの段階からテスト設計・実装をしていくかが重要なように思える。

「テストコードを書く?書かない?」ソフトウェアテストのいろんな疑問をテストのプロに聞いてみた - エンジニアHub|若手Webエンジニアのキャリアを考える!