お客様より温麺をいただきました。

先日、お客様より白石名物温麺うーめん)をいただきました。

いただいた温麺は通常の温麺ではなく、たれで食べる温麺やカレー麺など

バリエーション豊かな温麺でした♪

 

スタッフ一同、美味しくいただきました。

この場を借りてお礼申し上げます。

21 20

樋口理事長様 おめでとうございます。

当社お客様の、福島信用金庫 樋口理事長様が平成29年秋の褒章「黄綬褒章」を受章されました。

樋口理事長様が長年、全身全霊をかけて信用金庫業界発展のためご尽力された賜物と存じます。
誠におめでとうございます。

「黄綬褒章」受章の記念品として、福島県の伝統的工芸品、しかも菊の御紋入りの「会津塗二ツ引タンス」を樋口理事長様より頂戴いたしました。

ojuhousyou

IT技術者たるもの、これくらいは暗記しておかねば・・・

IT戦士の方々皆さま、日々業務にお疲れ様です。

本日は、IT技術者であれば、恐らく皆さま暗記していると思われる事項を記事にさせていただきます。

その暗記物とは「10進数⇔2進数」「10進数⇔16進数」になります。

もちろん、10進数の10,000を16進数に暗記なんてのは無理ですよね。

私が申し上げたいの、10進数の「0~15」を対象にした暗記の話になります。つまり、16進数であれば「0~F」、2進数であれば「0~1111」の範囲となる4ビットで表現できる16個の数字のことです。この範囲の変換は即時に行えるように暗記しておいて損はありません。

実際、我々の業務で10進数の「0~15」を2進数や16進数に変換することや、その逆変換を行う場面は少なくありません。この変換作業に時間をかけられては作業の生産性に支障をきたしてしまいます。(諸兄方々から「当たり前でしょ!」という声が聞こえてきそうですが)

ところが、これが出来ないルーキーIT技術者も少なくないようです。

10進数の「0~15」を即座に2進数や16進数に変換できないIT技術者の方は、今すぐに下述の変換表を印刷し、暗記することをお勧めします。(自分のためですよ!)

 

<変換表>

henkanhyo

 

余談:

約30年前ですが、私が学生プログラマだったころ、ゲーム作りに夢中でした。

その際、ゲーム画面で動き回るキャラクタの絵を作る時に、下図のように16進数変換を行い、当時のコンピュータにキャラクタの絵を描画させていました。かなり、懐かしい思い出ですね。(苦笑)

hexchar

[補足]
キャラクタの色を塗りたいドットを「1(2進数)」、色を塗らないドットを「0(2進数)」で表現しています。

 

VB.NET開発者にクイズです! ちゃんと正解を出せますか?

VB.NETの開発者にクイズです。

是非とも、正解を出して下さい・・・ね。

出せなかった人は、VB.NETの基本から見直すことも必要かもしれませんよ。

 

それでは、クイズです。

先ずは下記のコードをお読みください。

Private Sub BTN_HUTU_Click(sender As Object, e As EventArgs) Handles BTN_FUTU.Click

  Dim l_SideA As Integer

  Dim l_SideB As Integer


  '■A側の変数に1000を代入
  l_SideA = 1000

  '■B側の変数にA側の値を代入
  l_SideB = l_SideA

  '■B側の変数の値を2000に変更
  l_SideB = 2000

  '■A側の変数の値を画面に表示
  MessageBox.Show("l_SideA側の値:" & l_SideA)

  '■B側の変数の値を画面に表示
  MessageBox.Show("l_SideB側の値:" & l_SideB)

End Sub

 

さて、このコードの最後に表示されるメッセージボックスに表示される値は何でしょうか?

なんて問題は、聞くまでもありませんね。

結果は、以下のように表示されます。

res_h_1

res_h_2

 

では、下記のコードの最後に表示される2つのメッセージボックスに表示される値は何でしょうか?

Private Sub BTN_OBJECT_Click(sender As Object, e As EventArgs) Handles BTN_OBJECT.Click

  Dim l_SideA As DataTable

  Dim l_SideA_AddRow As DataRow

  Dim l_SideB As DataRow


  '■A側のオブジェクト変数(DataTableの1行目)に1000を代入
  l_SideA = New DataTable
  l_SideA.Columns.Add("A", GetType(Integer))
  l_SideA_AddRow = l_SideA.NewRow
  l_SideA_AddRow("A") = 1000
  l_SideA.Rows.Add(l_SideA_AddRow)

  '■B側のオブジェクト変数にA型のオブジェクト変数を代入
  l_SideB = l_SideA.Rows(0)

  '■B側のオブジェクト変数の値を2000に変更 
  l_SideB.Item("A") = 2000

  '■A側のオブジェクト変数の値を画面に表示
  MessageBox.Show("l_SideA.Row(0)側の値:" & l_SideA.Rows(0).Item("A"))

  '■B側のオブジェクト変数の値を画面に表示
  MessageBox.Show("l_SideB側の値:" & l_SideB.Item("A"))

End Sub

 

正解を出して下さいよ~~。

(-_-)/~~~ピシー!ピシー!

【正解】はこちらになります。

res_o_1

res_o_2

 

皆さん、正しい正解をだせましたか?

もしかして「最初のメッセージボックス(l_SideA側)の値は、変更されないから初期設定のまま1000だよ。」なんて解答をした人いませんでしたか?

 

 

上記のコードのコメントを書き換えると以下のようになるわけです。

Private Sub BTN_OBJECT_Click(sender As Object, e As EventArgs) Handles BTN_OBJECT.Click

  Dim l_SideA As DataTable

  Dim l_SideA_AddRow As DataRow

  Dim l_SideB As DataRow


  '■A側のオブジェクト変数(DataTableの1行目)に1000を代入
  l_SideA = New DataTable
  l_SideA.Columns.Add("A", GetType(Integer))
  l_SideA_AddRow = l_SideA.NewRow
  l_SideA_AddRow("A") = 1000
  l_SideA.Rows.Add(l_SideA_AddRow)

  '■B側のオブジェクト変数にA型のオブジェクト変数のアドレスを代入
  l_SideB = l_SideA.Rows(0)

  '■B側のオブジェクト変数の値を2000に変更 → 同時にA側のオブジェクト変数も変更されてしまう。
  l_SideB.Item("A") = 2000

  '■A側の値を画面に表示 → B側の値に変更により、A側の値も変更されることを確認
  MessageBox.Show("l_SideA.Row(0)側の値:" & l_SideA.Rows(0).Item("A"))

  '■B側の値を画面に表示
  MessageBox.Show("l_SideB側の値:" & l_SideB.Item("A"))

End Sub

 

私見ですが、これはただのクイズで終わるような問題ではないと考えます。

VB.NETのビギナーであれば、まず間違いなく「最初のメッセージボックスの値は、1000だよ。」と解答してしまうのではないでしょうか?

無理もないかもしれません。コードを見る限りオブジェクト変数のl_SideA側を変更するような命令行を見つけることができませんから・・・

つまり、先輩プログラマが開発したソースコードをビギナープログラマーが誤って読み解いて、そのプログラムに対して誤ったメンテナンス作業を行ってしまう危険性がある考えます。

開発したシステムのライフサイクルとなる数年間(長ければ10年近く)の間、メンテナンス作業を行う度に、この問題記事のような誤った解釈によるコードが書かれることがないか心配してしまいます。

この問題記事の内容は、VB.NETを使用するすべてのプログラマーが認識し、かつ後輩プログラマに対して誤った解釈をしないように教育をしていく必要がある重要な事項と考えます。

 

もし、本記事のクイズに誤った解答を出してしまった方は、今後十分に注意して下さいね。

 

※本記事記載のVB.NETのソースコード(ソリューション一式)のダウンロードはこちらからどうぞ。

地元ネタ:船岡の「一目千本桜」を見てきました。

地元情報になります。

宮城県柴田郡大河原町の有名な観光名所になります。

先日、家族みんなで「白石川堤 一目千本桜」を見に行ってきました。

丁度、桜が良い感じで咲いており、それはそれは大変綺麗なものでした。
(^^♪

以下は、私からの「桜」のおすそ分けです。(苦笑)

(1)
白石川堤からの景色になります。この写真では、判りにくいかもしれませんが、白石川に沿ってず~っと桜が続いているんです。
hitome1

(2)
途中の桜をアップで撮影したものです。こんな満開状態の桜が沢山です。
hitome2

(3)
平成27年に完成した「しばた千桜橋」からの景色になります。先ほどの説明と重なりますが、白石川に沿ってこのとおりです。
hitome3

(4)
東北本線の線路沿いでもこのとおりです。電車に乗りながら鑑賞することができます。写真左の車との比較で感じてもらえると思いますが、桜の咲いている区間距離が長いです。
hitome4

(5)
こちらの写真右下の橋が、平成27年に完成した「しばた千桜橋」です。この橋からの景色は最高ですよ。
hitome5

 

皆様も機会があれば、是非「船岡駅」で下車されて鑑賞されてみては・・・

 

<余談>
桜を鑑賞する人が多すぎます。(私も含めて)
お花見弁当は売り切れ状態でした。ですが、その隣で売られていた「100円おにぎり」が、ボリュームもあり、味もよく、最高に美味かったです。

ちなみに、私は電車で行ったのですが、満員の満員の満員状態でした。

 

ExcelのVBAのFindメソッドで困ったエラーが発生!

ExcelのVBAでの話になります。

RangeオブジェクトのFindメソッドを使用し、指定された値を所持するセルの行位置を取得する処理を組み入れた業務APを開発される際の注意喚起になります。

実際の業務APの内容をお見せすることは出来ないため、デフォルメ化したサンプルAPで説明させていただきます。

※サンプルExcelファイルのダウンロードはこちらからどうぞ。

<サンプルAP仕様>
シート「Sheet1」上の表より、指定された値を所持するセルを探索しその行位置を結果としてメッセージ表示する。

先ずは、シート「Sheet1」の内容になります。
excel_01_00_data

 

そして、当初開発時のソースコード(VBAマクロ)

Sub 一見問題のないように見える書き方()

 Dim l_Row As Long   '探し物の行位置

 With Sheets("Sheet1")

  '■探索範囲に存在する"くじら"を探索
  l_Row = .Range("A:A").Find("くじら").Row

  MsgBox "探し物の行は[" & Format(l_Row, "#,##0") & "]です。"

 End With

End Sub

 

これを実行すると正常に処理されます。
excel_01_01_ok1

 

しかし、下記のソースコードのように探索値を変更してみたところ・・・

Sub 問題が発生します()

 Dim l_Row As Long   '探し物の行位置
 
 With Sheets("Sheet1")

  '■探索範囲に存在しない"ことり"を探索
  l_Row = .Range("A:A").Find("ことり").Row

  MsgBox "探し物の行は[" & Format(l_Row, "#,##0") & "]です。"

 End With

End Sub

 

Findメソッドの実行行で、このように結果がエラーとなります。
excel_01_02_ng1

しかも、withブロック変数の設定が原因とのこと・・・・

見てのとおりwithブロックの書き方に間違いは見られない。

しかし、エラーはwithブロック変数・・・これは困りました。

 

諸々の情報収集と検証をしたところ、原因は本当につまらないことでした。

Findメソッドで条件該当するセルを探索することが出来ないにも関わらず、Rowプロパティを要求したため「Rowプロパティを返したいけど対象のセルがありませんよ!」というエラーだったようです。

つまり、下記のソースコードのようにオブジェクトとメソッドとプロパティの3連続ピリオド結合を止めて、正しく途中経過を判定すれば良いだけだったのです。

Sub 皆様このように書きましょう()

 Dim l_Range As Range   '探し物の結果セル

 With Sheets("Sheet1")

  '■探索範囲に存在しない"ことり"を探索
  Set l_Range = .Range("A:A").Find("ことり")

  '■探索結果を判定する。
  If (Not l_Range Is Nothing) Then
   MsgBox "探し物の行は[" & Format(l_Range.Row, "#,##0") & "]です。"
  Else
   MsgBox "探し物はありませんでした。"
  End If

 End With

End Sub

 

その結果は、このとおり正常に表示されました。
excel_01_03_ok2

 

ExcelのVBAコードを記述する場合、このようにオブジェクト.メソッド.プロパティのように連続したピリオドで結合し、ソースコードの記述を楽したいと思う心情は私も理解します。

しかし、お客様へ納品する業務APとしてVBAコードを記述する際は、このような楽をすべきではありません

今回の記事では、Findメソッドを例として記載しましたが、Findメソッド以外の他のメソッドの場合も考え方は同じです。

 

今回は、このFindメソッドの原因を究明するために、本来なら出さなくてもよいあぶら汗を約1時間も出しながら苦戦することになりました。

「作れば良い」「動けば良い」ではダメなのです。

「保守しやすいか?」「エラーが発生した場合、原因究明しやすいか?」を念頭に置いて、プログラマ諸君にはVBAコードを書いていただきたいものです。

 

(検索キーワード)
オブジェクト変数または With ブロック変数が設定されていません。

幸福を求めてルノワール展へ・・

先日、宮城県美術館で開催されている「ルノワール展」に行ってきました。

runowal2_w

たまたま、愚息の用事で休日に仙台市内に出かけることになり、その待ち時間に「ルノワール展に行こう!」ということになった次第です。

私個人として、美術館へ絵画鑑賞に出かけることは、今回が生まれて初めてのことでした。

実際に、本物の絵を鑑賞し、改めて「本物の重み」というのか「本物の質」というのか、言葉で表せない感動を覚えた次第です。(すみません。稚拙な表現しかできなくて・・・でも、本当に感動しました)

ちなみに、お土産に買ってきてしまったルノワール作品で、自宅にプチ「ルノワール展」を作ってしまいました。(笑)

runowal1_w

中でも、私のお気に入りは「ムーラン・ド・ラ・ギャレット」という絵です。

runowal3_w

この写真は、はがきサイズのものですが、展示場で販売されていた特製レプリカ(約15万円)を買うか迷ったほどです。この作品は、ルノワールの代表作品かつ人気作品といわれているらしく、私もすっかり魅了されました。ちなみに、本作品は絵画史上において第2位の高額金額で落札されたとのことでした。 (私の自宅のこの絵は、パネル込みで500円未満ですが・・苦笑)

 

この、ルノワールですが「幸福の画家」と称されているようです。

ルノワールの作品はどれも「明るく、楽しく、幸福」といった印象を感じる心安らぐものばかりでした。

「人生は不快なものさ、だからこそ楽しい絵を描くのさ!」と言わんばかりに・・・・

ルノワールは、「【観る者を幸せにする絵】を描くいちばんの方法は、描く自分が幸せでいる必要がある」という考えを持ちながら絵を描き続けていたようです。

 

これを聞いて私見ではありますが、我々システムサービスを提供する業者も「【利用者を幸せにするシステム】を開発提供するいちばんの方法は、開発提供する我々が幸せでいる必要がある」という考えを持つべきと思いました。

 

お客様の幸せも大事ですが、サービス提供を行う我々の幸せも大事・・・そう、ルノワールに言われたようが気がした美術鑑賞でした。

 

VB.NETでExcel編集を行った後でExcelプロセスが消えないトラブル

先日VB.NETでExcelブックにデータを読み書きするプログラムを作っていたのですが、
その際にタスクマネージャにExcelのプロセスが残ったままになる現象が起きてはまって
しまったので備忘録を書いておこうと思います。

【環境】
・Windows 10
・Visual Studio 2013
・Microsoft Office 2013

結論から言うとExcelのオブジェクトを解放してあげればいいのですが、それにはコツがあるのです。

NG例

xlApplication.Workbooks.Item("Sheet1")

'■COMオブジェクトの解放
Call ReleaseCOMObject(xlsApp)

何がいけないかというと「xlsApp.Workbooks.Item(“Sheet1”)」の部分です。
ドット(.)が二つ以上続く操作を行う場合は、COMオブジェクトを解放してもExcelのプロセスが残ってしまいます。
この場合は一つずつ分解して変数に保持しなければいけません。

OK例(サンプルソース)

Imports Microsoft.Office.Interop

Public Shared Sub P_Sample()

'■Excel用
Dim xlApplication As Excel.Application = Nothing
Dim xlWkBooks As Excel.Workbooks = Nothing
Dim xlBook As Excel.Workbook = Nothing
Dim xlSheets As Excel.Sheets = Nothing
Dim xlWkSheet As Excel.Worksheet = Nothing
Dim xlActvSheet As Excel.Worksheet = Nothing
Dim xlRange As Excel.Range = Nothing

Try

'■Excel.Application の新しいインスタンスを生成する
xlApplication = New Excel.Application()

'■アプリケーションの非表示
xlApplication.Visible = False

'■test.xlsmを開く
xlWkBooks = xlApplication.Workbooks
xlBook = xlWkBooks.Open(“D:\test.xlsm”)

'■シートの指定
xlSheets = xlBook.Worksheets

'***********************
' [Sheet1]シート
'***********************
xlWkSheet = xlSheets.Item("Sheet1")
xlWkSheet.Activate()

'■指定エリアの値をクリア
xlRange = xlWkSheet.Range("B7:C59")
xlRange.Value = ""
'■COMオブジェクトの解放
Call ReleaseCOMObject(xlRange)

'■COMオブジェクトの解放
Call ReleaseCOMObject(xlWkSheet)

'***********************
' [Sheet2]シート
'***********************
xlWkSheet = xlSheets.Item("Sheet2")
xlWkSheet.Activate()

'■指定エリアの値をクリア
xlRange = xlWkSheet.Range("B7:C59")
xlRange.Value = ""
'■COMオブジェクトの解放
Call ReleaseCOMObject(xlRange)

'■COMオブジェクトの解放
Call ReleaseCOMObject(xlWkSheet)

'----------------------------------------
' Sheet1シートに社員番号、氏名をセット
'----------------------------------------

xlWkSheet = xlSheets.Item("Sheet1")
xlWkSheet.Activate()

xlRange = xlWkSheet.Range("C1”)
xlRange.Value = “001” ‘社員番号
'■COMオブジェクトの解放
Call ReleaseCOMObject(xlRange)

xlRange = xlWkSheet.Range("D1”)
xlRange.Value = “佐藤” ‘氏名
'■COMオブジェクトの解放
Call ReleaseCOMObject(xlRange)

'■COMオブジェクトの解放
Call ReleaseCOMObject(xlWkSheet)

'■Excelを上書保存して閉じる
xlBook.Close(True)

'■COM オブジェクトの参照カウントを解放する
Call ReleaseCOMObject(xlSheets)
Call ReleaseCOMObject(xlWkBooks)
Call ReleaseCOMObject(xlBook)

xlApplication.Quit()
Call ReleaseCOMObject(xlApplication)

Exit Sub
'**エラー処理 ******************************************
Catch ex As Exception

'■エラーメッセージとログ出力、強制終了
Messagebox.Show “処理に失敗しました。”

Finally

'■Excelを保存
If Not xlBook Is Nothing Then
xlBook.Close(True)
End If

'■COM オブジェクトの参照カウントを解放する
Call ReleaseCOMObject(xlRange)
Call ReleaseCOMObject(xlWkSheet)
Call ReleaseCOMObject(xlSheets)
Call ReleaseCOMObject(xlWkBooks)
Call ReleaseCOMObject(xlBook)

If Not xlApplication Is Nothing Then
xlApplication.Quit()
End If

Call ReleaseCOMObject(xlApplication)
End Try
End Sub

'■====================================================■
'■ COMオブジェクトの解放
'■====================================================■
Public Shared Sub ReleaseCOMObject(Of T As Class)(ByRef objCom As T)

'オブジェクトが空の場合処理を抜ける
If objCom Is Nothing Then
Return
End If

Try
'パラメタがCOMオブジェクトかチェック
If System.Runtime.InteropServices.Marshal.IsComObject(objCom) Then

'Runtime Callable Wrapperの解放を行う
Dim cntRCW As Integer = System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objCom)

If cntRCW <> 0 Then
'解放しきれていない場合、メッセージを出力
MessageBox.Show("解放エラー")
End If

End If

Finally
objCom = Nothing
End Try

End Sub

一つの操作ごとにCOMオブジェクトを解放しています。
また、最後にCOMオブジェクトを解放だけではなく、「Excel.Application」の「Quit」と
Excel.Workbook」の「Close」を必ず行って下さい。

COMオブジェクトの解放が煩わしという人には「ClosedXML」や「EPPlus」といったライブラリを
使ったExcelファイルの読み書きを行う方法もありますよ。

遅くなりましたが…。

新年あけましておめでとうございます!
今年もどうぞよろしくお願いします。

昨年はいろいろありましたが、今年も良い年になるといいですね。
私自身は今年は厄年ですので、戦々恐々としております(笑)

ところで、近頃めっきり寒くなってきました。
仙台はそんなに雪が降らないだろうと思っていたのですが、
意外と雪の日が多くびっくりしております。
大して積もらないようなので一安心ですが。

最近でこそ温暖化の影響からか積雪量が減ってきておりますが、
私の実家(秋田県の某所)周辺ではこの時期になると、2m近くの積雪になることもあります。

onndannka
また、屋根に積もった雪が滑り落ちて下に溜まっていくと、
家の外周は3m程の積雪になりますので、1階の窓が塞がってしまうんですね。
昼でも暗くて照明が必要になりますので、雪国は大変です。
子供の頃はかまくらや雪だるまを作ってよく遊んでいましたが、
今となっては雪も迷惑な存在にしか思えません(笑)

yukidaruma

真冬の寒さもあと1、2か月の辛抱ですので、体を温めて乗り切りましょう!

 

 

 

 

巨大なリンゴが届きました!

先程巨大なリンゴが届きました!

先日、梨を贈ってくださった福島県のお客様からです。

fk_ringo

 

毎回ボリュームのある贈り物を頂き大変有り難く思います。

それにしてもここまで大きなリンゴを見ることもなかなかありません。
1つ食べるだけですぐにお腹がいっぱいになりそうですね。

リンゴは栄養価も高く健康に良いので、美味しくいただいて社員一同来年も健康に過ごしていきたいと思います。

素敵な贈り物をありがとうございました!