ファイルを操作する為に、 LocalDB のプロセスを、一旦、終了させるコードを考えます。
プロセス終了後の再起動は 元々、 LocalDB の仕組みに組み込まれた もの で賄えます。
つまり、ここでは、再起動させる為の事は 検討しなくても良い 筈です。
前回 VB LocalDB とファイル操作 1-2 の プロセスの動きを表にして見ます。
Process | PID | PID-parent | parent | Notice |
---|---|---|---|---|
1st App1 Start | ||||
App1.exe | 9516 | 4768 | explorer | |
- sqlservr.exe | 5900 | 9516 | App1 | |
2nd LocalDB kill | ||||
App1.exe | 9516 | 4768 | explorer | |
3rd App1 Action | ||||
App1.exe | 9516 | 4768 | explorer | |
- sqlservr.exe | 6272 | 9516 | App1 | |
4th App1 Close | ||||
sqlservr.exe | 6272 | 9516 | App1 | ! Out of Explorer |
5th App1 Start | ||||
App1.exe | 5776 | 4768 | explorer | |
sqlservr.exe | 6272 | 9516 | App1 | ! Not Child Of App1 |
6th App1 Close | ||||
sqlservr.exe | 6272 | 9516 | App1 | ! App1 Is Unknown |
LocalDB 、 複雑です。
でも、 この相手を 判別して 停止(破棄) しないと、 ファイル操作は 叶いません ... 。
そして、 自分(対象アプリ)以外にも、 LocalDB が配下で 動いている可能性もあります。
さて、
検索して見ると分かりますが、sqlserver.exe と書かれた記事が多いです。
でも、Program Files を覗いて見れば ... 。
C:\Program Files\Microsoft SQL Server\110\LocalDB\Binn\sqlservr.exe
C:\Program Files\Microsoft SQL Server\120\LocalDB\Binn\sqlservr.exe
実行ファイル名は sqlservr.exe であって、sqlserver.exe ではありませんでした。
うっ、8 文字に合わせてる ... 。
LongName と 8.3Name が一致する様にか ... 。
どう言う事になるかと言えば、
Process ID を取得する為に、
Process.GetGetProcessesByName で sqlserver.exe を検索しても、LocalDB には辿り着きません。
更に、
名前 は Process Name (実行ファイル名 拡張子なし) ですので、注意ですね。 :( 。
msdn のヘルプにも記載があります。
https://msdn.microsoft.com/en-us/library/z3w4xdc9(v=vs.110).aspx Remarks 参照。
A processName can be specified for an executable file that is not currently running on the local computer, ...
中略 <omit>
The process name is a friendly name for the process, such as Outlook, that does not include the .exe extension or the path.
では、 お約束のコード。
検索しまくり! のコードなので、 その点はご容赦を。
また、 実際の Project から抜粋したコードですので、 これ単独では用をなしませんし、試せません。
是非、 LocalDB が稼働する状態のものに 組み込んで見て下さい。
尚、 一部、 クラスを流用させて戴きました。 Original : C# > VB.net に変換。
作者の tezaurismosis さまに感謝!。
記載の Code 内にも 記事の URL と お名前 とを貼ってあります。
ロシア語の QA サイトの様ですが、 ロシア語は全く分かりません ... 。
LocalDB のプロセスを取得し、
その親プロセスが残っていれば、 その名前を自アプリと照合し、 削除します。
親プロセスが消滅していれば、 その内容は確認出来ないので、 不本意ながら、 全て 削除です。
コード上では、 自プロセス名 ("MyApp" 赤字) をハードコーディング していますが、
汎用的にするなら、 p_parentName.StartsWith(My.Application.Info.AssemblyName) に書き替えて下さい。
Imports System.Runtime.InteropServices
Imports System.Diagnostics
Public Class Form1
Private flagCompared As Integer = 0
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub ButtonX_Click(sender As Object, e As EventArgs) Handles ButtonX.Click
DoCopyTo()
End Sub
Private Sub DoCopyTo()
Me.Cursor = Cursors.WaitCursor
LocalDB_ProcessEnding()
Me.Cursor = Nothing
'Do Copy_
' *
' * Add Your Code
' *
End Sub
Private Sub LocalDB_ProcessEnding()
'LocalDBプロセスは、アプリケーションの子プロセスとしてスタート
'このプロセスに最後に接続してから数分後、プロセスを閉じるためプロセスをシャットダウン
'実行モード:SQL Server Compactはin-proc DLL、LocalDBは分離プロセス
' RefURL:http://sqlazure.jp/r/sql-server/233/
'LocalDB Process Name "sqlservr" (sqlservr.exe) Parent Name "MyApp" Only Kill
'Get (MyApp) LocalDB Process
Dim ps As System.Diagnostics.Process() = _
System.Diagnostics.Process.GetProcessesByName("sqlservr")
'System.Diagnostics.Process.GetProcessesByName("MyApp")
'Closing
For Each p As System.Diagnostics.Process In ps
Dim procID As Integer = p.Id
Dim p_parentID As Integer = GetPPID(procID)
Try
'Alive Parent Process
Dim p_parentName = Process.GetProcessById(p_parentID).ProcessName
If p_parentName.StartsWith("MyApp") Then ' On VS : MyApp.vshost
'p.CloseMainWindow()
p.Kill()
End If
Catch ex As ArgumentException
'Already Killed Parent Process > All LocalDB Close !!!
p.Kill()
End Try
p.WaitForExit(10000)
Next
End Sub
Private Function GetPPID(ByVal procID As Integer) As Integer
Dim pProc As Process = myProcessEx.GetParentProcess(procID)
If pProc Is Nothing Then
Return -1
Else
Return pProc.Id
End If
End Function
End Class
NotInheritable Class myProcessEx
'This Class Notice !!!
'Original Code : on C# > Modify : Error No Catch, Return Nothing
'Written by : tezaurismosis 18.12.2013, 23:06
'Ref.URL : http://www.cyberforum.ru/csharp-beginners/thread1044660.html
'Convert To VB.net : by http://codeconverter.sharpdevelop.net/SnippetConverter.aspx
Private Sub New()
End Sub
'inner enum used only internally
<Flags> _
Private Enum SnapshotFlags As UInteger
HeapList = &H1
Process = &H2
Thread = &H4
[Module] = &H8
Module32 = &H10
Inherit = &H80000000UI
All = &H1F
NoHeaps = &H40000000
End Enum
'inner struct used only internally
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _
Private Structure PROCESSENTRY32
Const MAX_PATH As Integer = 260
Friend dwSize As UInt32
Friend cntUsage As UInt32
Friend th32ProcessID As UInt32
Friend th32DefaultHeapID As IntPtr
Friend th32ModuleID As UInt32
Friend cntThreads As UInt32
Friend th32ParentProcessID As UInt32
Friend pcPriClassBase As Int32
Friend dwFlags As UInt32
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=MAX_PATH)> _
Friend szExeFile As String
End Structure
<DllImport("kernel32", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function CreateToolhelp32Snapshot(<[In]> dwFlags As UInt32, <[In]> th32ProcessID As UInt32) As IntPtr
End Function
<DllImport("kernel32", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function Process32First(<[In]> hSnapshot As IntPtr, ByRef lppe As PROCESSENTRY32) As Boolean
End Function
<DllImport("kernel32", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Auto)> _
Private Shared Function Process32Next(<[In]> hSnapshot As IntPtr, ByRef lppe As PROCESSENTRY32) As Boolean
End Function
<DllImport("kernel32", SetLastError:=True)> _
Private Shared Function CloseHandle(<[In]> hObject As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
' get the parent process given a pid
Public Shared Function GetParentProcess(pid As Integer) As Process
Dim parentProc As Process = Nothing
Dim handleToSnapshot As IntPtr = IntPtr.Zero
Try
Dim procEntry As New PROCESSENTRY32()
procEntry.dwSize = CType(Marshal.SizeOf(GetType(PROCESSENTRY32)), UInt32)
handleToSnapshot = CreateToolhelp32Snapshot(CUInt(SnapshotFlags.Process), 0)
If Process32First(handleToSnapshot, procEntry) Then
Do
If pid = procEntry.th32ProcessID Then
parentProc = Process.GetProcessById(CInt(procEntry.th32ParentProcessID))
Exit Do
End If
Loop While Process32Next(handleToSnapshot, procEntry)
Else
Throw New ApplicationException(String.Format("Failed with win32 error code {0}", Marshal.GetLastWin32Error()))
End If
Catch ex As Exception
'Throw New ApplicationException("Can't get the process.", ex) 'Return Nothing
Finally
' Must clean up the snapshot object!
CloseHandle(handleToSnapshot)
End Try
Return parentProc
End Function
End Class
これで、 LocalDB が動いている環境でも、一時停止の上、ファイル操作が可能になりました。
注意点は、 他の 親プロセスが消滅した LocalDB が稼働していた場合 不都合が無いか? です。 一応確認を。,
0 件のコメント:
コメントを投稿