画面作成中にユーザーコントロールのLoadイベントを処理させない
ユーザーコントロールを使用したForm画面の作成中に次のエラーが出てForm画面が開かなくなった。
ユーザー '' はログインできませんでした。
ユーザーコントロールのLoadイベントにApp.configからDBへの接続情報を取得してDBからデータを取得、表示をするプログラムを追加してからエラーが出ていた。
Form画面を開くときに、配置したユーザーコントロールのLoadイベントが実行されApp.configから接続情報を取得できていないのが原因で、DBへの接続ができずエラーとなっていた。
画面作成中は、Loadイベントが実行されないようにしようと思って調べた時のメモ。
Private Sub UserCtrl_Load(sender As Object, e As EventArgs) Handles MyBase.Load '開発中は処理をしない If Me.DesignMode Then Return 'DBへの接続と取得・表示 End Private
参考URL:.NET:Tips > デザイン:デザイン時に処理を実行させない
ユーザーコントロールが入れ子になっているとき、子のユーザーコントロールのDesignModeはFalseを返すようです。
その情報を調べた時のメモ。
参考URL:デザインモード(this.DesignMode)を正しく得ることができない場合があります
参考URL:入れ子させた UserControl の DesignMode が false になるのを回避したい
DataGridViewのセル編集が3回クリックで編集できるようになる
DataGridViewでセルを直接編集するために編集を有効にしたけどセルを3回クリックしないと、編集モードにならなかった。
1回目のクリックで、セルが選択され次のダブルクリックで編集モードになってる?
ダブルクリックで編集モードとなるようにしたかったのでプログラムのメモ。
'EditModeを次の設定に変更する 'DataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick Dim dgv As DataGridView = DirectCast(sender, DataGridView) If {"Column1", "Column2", "Column3"}.Contains(dgv.Columns(e.ColumnIndex).Name) AndAlso e.RowIndex >= 0 Then dgv.BeginEdit(True) End If End Sub
NASの共有フォルダにつながらない
Windows 10 Pro バージョン 1809をクリーンインストールしました。
データをNASから取ってこようとしたけど、共有フォルダにつながらない。
\\<IPアドレス> にアクセスできません
とメッセージが出るのみ、エラー内容が特定できないと表示される。
色々しらべて解決したのでメモ。
[コントロール パネル]→[ネットワークと共有センター]を開く。
共有の詳細設定の変更をクリックする。
現在のプロファイルの以下を有効にする。
- ネットワーク探索を有効にする。
- ファイルとプリンターの共有を有効にする。
[コントロール パネル]→[プログラムと機能]を開く。
Windowsの機能の有効化または無効化をクリックする。
- SMB 1.0/CIFS File Sharing Support の中を全部チェック状態にする。
これで共有フォルダにつながるようになった!
PC(Windows 10)の時刻を設定するために盾マークのexeを作成
Windows 10になってからではないけど、システム時刻をプログラムから合わせるにはユーザーアカウント制御を何とかするか、管理者権限で実行するかしないと出来なくなった。
タスクスケジューラに登録して管理者で実行する方法もあるみたい。
ユーザーアカウント制御の実行を聞かれるのはしょうがないと諦めて右クリックして"管理者として実行"をしなくても良いように盾マークのexeを作成することにした。
参考URL:再試行でDebugできない~VS2015
次のプログラムを「NTPサーバの現在日時をシステム時計に設定するサンプル(VB.NET)」を転記しています。
タイムサーバーは、time.windows.com です。
Public Class Form1 ' システム時計の日時設定APIの引数 <System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> Public Structure SystemTime Public wYear As Short Public wMonth As Short Public wDayOfWeek As Short Public wDay As Short Public wHour As Short Public wMinute As Short Public wSecond As Short Public wMiliseconds As Short End Structure ' システム時計の日時設定APIの定義 <System.Runtime.InteropServices.DllImport("kernel32.dll")> Public Shared Function SetLocalTime(ByRef sysTime As SystemTime) As Boolean End Function Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ' NTPサーバへの接続用UDP生成 Dim objSck As System.Net.Sockets.UdpClient Dim ipAny As System.Net.IPEndPoint = New System.Net.IPEndPoint(System.Net.IPAddress.Any, 0) objSck = New System.Net.Sockets.UdpClient(ipAny) ' NTPサーバへのリクエスト送信 Dim sdat As Byte() = New Byte(47) {} sdat(0) = &HB objSck.Send(sdat, sdat.GetLength(0), "time.windows.com", 123) ' NTPサーバから日時データ受信 Dim rdat As Byte() = objSck.Receive(ipAny) ' 1900年1月1日からの経過時間(日時分秒) Dim lngAllS As Long ' 1900年1月1日からの経過秒数 Dim lngD As Long ' 日 Dim lngH As Long ' 時 Dim lngM As Long ' 分 Dim lngS As Long ' 秒 ' 1900年1月1日からの経過秒数計算 lngAllS = CLng( rdat(40) * Math.Pow(2, (8 * 3)) + rdat(41) * Math.Pow(2, (8 * 2)) + rdat(42) * Math.Pow(2, (8 * 1)) + rdat(43)) ' 1900年1月1日からの経過(日時分秒)計算 lngD = lngAllS \ (24 * 60 * 60) ' 日 lngS = lngAllS Mod (24 * 60 * 60) ' 残りの秒数 lngH = lngS \ (60 * 60) ' 時 lngS = lngS Mod (60 * 60) ' 残りの秒数 lngM = lngS \ 60 ' 分 lngS = lngS Mod 60 ' 秒 ' 現在の日時(DateTime)計算 Dim dtTime As DateTime = "1900/01/01" dtTime = dtTime.AddDays(lngD) dtTime = dtTime.AddHours(lngH) dtTime = dtTime.AddMinutes(lngM) dtTime = dtTime.AddSeconds(lngS) ' グリニッジ標準時から日本時間への変更 dtTime = dtTime.AddHours(9) ' 現在の日時表示 System.Diagnostics.Trace.WriteLine(dtTime) ' システム時計の日時設定 SetSysTime(dtTime) End Sub ' システム時計の日時設定 Private Sub SetSysTime(ByVal dtm As DateTime) Dim sTime As New SystemTime sTime.wYear = dtm.Year sTime.wMonth = dtm.Month sTime.wDay = dtm.Day sTime.wHour = dtm.Hour sTime.wMinute = dtm.Minute sTime.wSecond = dtm.Second sTime.wMiliseconds = dtm.Millisecond SetLocalTime(sTime) End Sub End Class
ソリューション エクスプローラーからプロジェクトを右クリックして[追加]→[新しい項目]をクリックする。
"アプリケーション マニフェスト ファイル"を選択して追加する。
app.manifestにある次行を変更する。(コメントされているのをコピーして貼り付けると良い)
変更前:<requestedExecutionLevel level="asInvoker" uiAccess="false" />
変更後:<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
ソリューションをリビルドしたらexeに盾マークが付いている。
このexeを実行すると、ユーザーアカウント制御が聞かれるので"はい"を押す。
DataGridViewのセル結合(行のセルを固定)
以前に書いた記事で「DataGridViewのセル結合」をしたときだと、行を固定した場合、上手く描画できません。
その対応したプログラムを書いたのでメモ。
- 表を見せるのみです。
- 行列の追加、編集、削除や、セル幅の変更は考慮していません。
- 行列のヘッダーは無効にしています。
- DataGridViewコントロールの名前は、「DataGridView1」です。
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load Init() End Sub Private Sub Init() 'ちらつき防止 Dim type As System.Type = GetType(DataGridView) Dim propertyInfo As System.Reflection.PropertyInfo = type.GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.NonPublic) propertyInfo.SetValue(DataGridView1, True, Nothing) DataGridView1.AllowUserToAddRows = False DataGridView1.ReadOnly = True DataGridView1.AllowUserToDeleteRows = False DataGridView1.ColumnHeadersVisible = False DataGridView1.RowHeadersVisible = False Dim i As Integer Dim j As Integer Dim colAdd As DataGridViewColumn For i = 1 To 3 colAdd = New DataGridViewColumn colAdd.Name = String.Format("Column{0}", i) colAdd.Width = 60 colAdd.CellTemplate = New DataGridViewTextBoxCell DataGridView1.Columns.Add(colAdd) Next '結合したいセルには同じテキストを入れておく Dim cellText(,) As String = { {"店舗", "店舗", "売上"}, {"店舗名", "担当エリア", "売上"}, {"北支店01", "駅北", "10000"}, {"北支店02", "駅南", "9000"}, {"西支店03", "商店街", "12000"}, {"東支店04", "住宅区", "8000"}, {"南支店05", "商業区", "11000"}, {"北支店06", "駅北", "10000"}, {"北支店07", "駅南", "9000"}, {"西支店08", "商店街", "12000"}, {"東支店09", "住宅区", "8000"}, {"南支店10", "商業区", "11000"}, {"北支店11", "駅北", "10000"}, {"北支店12", "駅南", "9000"}, {"西支店13", "商店街", "12000"}, {"東支店14", "住宅区", "8000"}, {"南支店15", "商業区", "11000"}, {"北支店16", "駅北", "10000"}, {"北支店17", "駅南", "9000"}, {"西支店18", "商店街", "12000"}, {"東支店19", "住宅区", "8000"}, {"南支店20", "商業区", "11000"} } Dim rowAdd As DataGridViewRow For i = 0 To cellText.GetLength(0) - 1 rowAdd = New DataGridViewRow rowAdd.CreateCells(DataGridView1) For j = 0 To rowAdd.Cells.Count - 1 rowAdd.Cells(j).Value = cellText(i, j) Next DataGridView1.Rows.Add(rowAdd) Next 'ヘッダー行を固定とする DataGridView1.Rows(1).Frozen = True End Sub Private Sub DataGridView1_CellPainting(sender As Object, e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles DataGridView1.CellPainting '結合したいセルをここに書く MergeCell(e, New Point(0, 0), New Point(1, 0)) MergeCell(e, New Point(2, 0), New Point(2, 1)) MergeCell(e, New Point(0, 1), New Point(0, 1)) MergeCell(e, New Point(1, 1), New Point(1, 1)) End Sub 'Cell1には、セルの開始位置(X, Y) 'Cell2には、セルの終了位置(X, Y) Private Sub MergeCell(ByRef e As System.Windows.Forms.DataGridViewCellPaintingEventArgs, Cell1 As Point, Cell2 As Point) If (e.RowIndex >= Cell1.Y AndAlso e.RowIndex <= Cell2.Y) AndAlso (e.ColumnIndex >= Cell1.X AndAlso e.ColumnIndex <= Cell2.X) Then Dim rect As New Rectangle With {.X = 0, .Y = 0, .Width = 0, .Height = 0} Dim i As Integer Dim firstRowIndex As Integer '固定セルであれば、先頭から描画されているとする If DataGridView1.Rows(e.RowIndex).Frozen = True Then firstRowIndex = 0 Else firstRowIndex = DataGridView1.FirstDisplayedScrollingRowIndex End If '開始セルの位置 '結合セルが画面外にあるときの位置を考慮 For i = Cell1.Y + 1 To firstRowIndex rect.Y -= DataGridView1(Cell1.X, i - 1).Size.Height Next For i = firstRowIndex + 1 To Cell1.Y rect.Y += DataGridView1(Cell1.X, i - 1).Size.Height Next '結合セルが画面外にあるときの位置を考慮 For i = Cell1.X + 1 To DataGridView1.FirstDisplayedScrollingColumnIndex rect.X -= DataGridView1(i - 1, Cell1.Y).Size.Width Next For i = DataGridView1.FirstDisplayedScrollingColumnIndex + 1 To Cell1.X rect.X += DataGridView1(i - 1, Cell1.Y).Size.Width Next '終了セルの幅 For i = Cell1.Y To Cell2.Y rect.Height += DataGridView1(Cell2.X, i).Size.Height Next For i = Cell1.X To Cell2.X rect.Width += DataGridView1(i, Cell2.Y).Size.Width Next 'セル位置の補正 rect.X += 1 rect.Y += 1 'グラデーションをかけてヘッダーぽく見せる Dim gb As New System.Drawing.Drawing2D.LinearGradientBrush(rect, SystemColors.ControlLightLight, SystemColors.Control, System.Drawing.Drawing2D.LinearGradientMode.Vertical) gb.GammaCorrection = True '通常の塗りつぶし 'e.Graphics.FillRectangle(New SolidBrush(SystemColors.Control), rect) e.Graphics.FillRectangle(gb, rect) e.Graphics.DrawRectangle(New Pen(DataGridView1.GridColor), rect) gb.Dispose() '描画するセル位置の文字をヘッダーテキストとして表示 Dim headerText As String = DataGridView1(e.ColumnIndex, e.RowIndex).Value TextRenderer.DrawText(e.Graphics, headerText, e.CellStyle.Font, rect, e.CellStyle.ForeColor, TextFormatFlags.HorizontalCenter Or TextFormatFlags.VerticalCenter) e.Handled = True End If End Sub
WebBrowserコントロールでポップアップ表示されるユーザーとパスワードの入力
WebBrowserコントロールで機器接続用の専用ブラウザを作っていてユーザーとパスワードの入力をポップアップで聞いてくるのがあった。
色々調べるとBASIC認証すれば接続できたので、そのときのメモ。
接続するURLを次のようにして接続した。
httpとIPアドレスの間に、<ユーザー名>:<パスワード>@ を追加した。
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim userName As String = "mainte" Dim password As String = "99999" Dim urlString As String = "http://" & userName & ":" & password & "@192.168.0.254/" ExWebBrowser1.Navigate(urlString) End Sub
リソースモニターの内容をファイルに保存する(VBS)
メモリの使用量を長期にわたって保存する必要がでてきた。
リソースモニターを開いたときの各プロセスのメモリの値をファイル保存する。
スクリプトをタスク スケジューラに登録して定期的に実行するようにした。
ResourceLog.vbs
'各プロセスのメモリ使用率をCSVで保存する 'ファイル名は"PerfLog_yyyyMMdd_HHmmss.csv"" Const savePath = "D:\" Dim oClassSet Dim oClass Dim oLocator Dim oService Dim sMesStr Dim oRange() Dim oRangeA() Dim oRangeB() Dim i Dim j Dim iRow Dim cpuPercent Set oLocator = CreateObject("WbemScripting.SWbemLocator") Set oService = oLocator.ConnectServer iRow = 0 '1回目の計測 Set oClassSet = oService.ExecQuery("SELECT * FROM Win32_PerfRawData_PerfProc_Process") ReDim oRangeA(oClassSet.Count - 1, 10) i = 0 For Each oClass In oClassSet oRangeA(i, 0) = oClass.Name oRangeA(i, 1) = oClass.IDProcess oRangeA(i, 2) = oClass.PageFaultsPersec oRangeA(i, 3) = oClass.PrivateBytes / 1024 oRangeA(i, 4) = oClass.WorkingSet / 1024 oRangeA(i, 5) = (oClass.WorkingSet - oClass.WorkingSetPrivate) / 1024 oRangeA(i, 6) = oClass.WorkingSetPrivate / 1024 oRangeA(i, 7) = oClass.PercentPrivilegedTime oRangeA(i, 8) = oClass.PercentUserTime oRangeA(i, 9) = oClass.Timestamp_Sys100NS i = i + 1 Next Set oClass = Nothing Set oClassSet = Nothing '1秒の待ち WScript.Sleep 1000 '2回目の計測 Set oClassSet = oService.ExecQuery("SELECT * FROM Win32_PerfRawData_PerfProc_Process") ReDim oRangeB(oClassSet.Count - 1, 10) i = 0 For Each oClass In oClassSet oRangeB(i, 0) = oClass.Name oRangeB(i, 1) = oClass.IDProcess oRangeB(i, 2) = oClass.PageFaultsPersec oRangeB(i, 3) = oClass.PrivateBytes / 1024 oRangeB(i, 4) = oClass.WorkingSet / 1024 oRangeB(i, 5) = (oClass.WorkingSet - oClass.WorkingSetPrivate) / 1024 oRangeB(i, 6) = oClass.WorkingSetPrivate / 1024 oRangeB(i, 7) = oClass.PercentPrivilegedTime oRangeB(i, 8) = oClass.PercentUserTime oRangeB(i, 9) = oClass.Timestamp_Sys100NS i = i + 1 Next Set oClass = Nothing Set oClassSet = Nothing Set oService = Nothing Set oLocator = Nothing On Error Resume Next ReDim oRange(1 + UBound(oRangeB), 10) oRange(0, 0) = "名称" oRange(0, 1) = "プロセスID" oRange(0, 2) = "コミット(KB)" oRange(0, 3) = "ワーキングセット(KB)" oRange(0, 4) = "共有可能(KB)" oRange(0, 5) = "プライベート(KB)" oRange(0, 6) = "CPU使用率(%)" For i = 0 To UBound(oRangeB) cpuPercent = 0 For j = 0 To UBound(oRangeA) If oRangeB(i, 0) = oRangeA(j, 0) And oRangeB(i, 1) = oRangeA(j, 1) Then cpuPercent = ((CDbl(oRangeB(i, 7)) + CDbl(oRangeB(i, 8))) - (CDbl(oRangeA(j, 7)) + CDbl(oRangeA(j, 8)))) / (CDbl(oRangeB(i, 9)) - CDbl(oRangeA(j, 9))) Exit For End If Next oRange(1 + i, 0) = oRangeB(i, 0) oRange(1 + i, 1) = oRangeB(i, 1) oRange(1 + i, 2) = oRangeB(i, 3) oRange(1 + i, 3) = oRangeB(i, 4) oRange(1 + i, 4) = oRangeB(i, 5) oRange(1 + i, 5) = oRangeB(i, 6) oRange(1 + i, 6) = FormatNumber(cpuPercent, 2, -1, 0, 0) Next Dim oFs Dim oText Dim sPath Dim sText() ReDim sText(UBound(oRange, 2)) sPath = savePath & "\PerfLog_" & FormatDay() & ".csv" Set oFs = CreateObject("Scripting.FileSystemObject") Set oText = oFs.CreateTextFile(sPath, True) For i = 0 To UBound(oRange) For j = 0 To UBound(sText) sText(j) = oRange(i, j) Next oText.Write Join(sText, ",") & vbCrLf Next oText.Close Set oText = Nothing Set oFs = Nothing Function FormatDay() Dim sDate, dtNow dtNow = Now sDate = FormatDateTime(dtNow, vbShortDate) & " " & Right("0" & FormatDateTime(dtNow, vbLongTime), 8) FormatDay = Replace(Replace(Replace(sDate, "/", ""), ":", ""), " ", "_") End Function