安裝方案(setup project): 要如何在 IDE 巨集中存取 DTE.Solution.Projects.Item(1).ProjectItems 呢? 在讀取 ProjectItems 永遠都是 Nothing, 微軟知識文件庫內沒有相關的解答, 在 project 物件中發現 project.Object, 但不知此物件是何種型別, 在除錯過程中意外發現是 IVsdDeployable 介面, 但 MSDN 中找不到此文件庫, 只有亂槍打鳥, 終於可以存取我要的屬性, 範例: project.Object.PlugIns.Item("File").Items.Item("Key String").Exclude = True 其中 Key String 在 vdproj (Visual Studio Deployment Project) 文件中找到
"Deployable"
{
"CustomAction"
{
}
"DefaultFeature"
{
"Name" = "8:DefaultFeature"
"Title" = "8:"
"Description" = "8:"
}
"ExternalPersistence"
{
"LaunchCondition"
{
"{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_109CDC28AA5F4F228EA2CC29D3AE023B"
{
"Name" = "8:.NET Framework"
"Message" = "8:[VSDNETMSG]"
"Version" = "8:3.5.21022"
"AllowLaterVersions" = "11:FALSE"
"InstallUrl" = "8:http://go.microsoft.com/fwlink/?LinkId=76617"
}
}
}
"File"
{
"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_09DBFD9ACD96CF1680BC032323448DB6"
{
"SourcePath" = "8:dte80a.olb"
"TargetName" = "8:dte80a.olb"
"Tag" = "8:"
"Folder" = "8:_458D6C3F7E084B2A93526BC1EAB03D6D"
"Condition" = "8:"
"Transitive" = "11:FALSE"
"Vital" = "11:TRUE"
"ReadOnly" = "11:FALSE"
"Hidden" = "11:FALSE"
"System" = "11:FALSE"
"Permanent" = "11:FALSE"
"SharedLegacy" = "11:FALSE"
"PackageAs" = "3:1"
"Register" = "3:1"
"Exclude" = "11:FALSE"
"IsDependency" = "11:TRUE"
"IsolateTo" = "8:"
}
星期四, 十月 29, 2009
安裝方案(setup project) 存取加入檔案的屬性
星期五, 十月 23, 2009
合併模組專案中加入自訂動作
在合併模組專案中加入自訂動作, 並設定屬性 InstallerClass 為 true, 結果建置此專案時卻發生建置失敗, 後來在 MSDN 論壇找到了解答, 原來要將 VS2008 升級為 SP1, 於是下載VS90sp1-KB945140-CHT.exe, 但為了下次不需重新下載, 寫了批次檔VS90sp1-KB945140-CHT.exe /createlayout '放置路徑'
星期六, 十月 17, 2009
VB.NET 監控 USB 裝置插拔
為了可以監控 USB 裝置插拔, 採用 WMI(Windows Management Instrumentation) 來實現, 如果是在本機查詢的話, 不會有 CPU 佔用使用率的問題 (wmiprvse.exe), 但是在某遠端電腦的監控, 就會有 CPU 使用率過高的問題, 後來改用 WINPROC 處理 Windows 訊息, 不過要用到 window Setup API 由於程式編輯器是 VB.NET, 找到 VC++ 的源碼, 再一步步的轉譯, 再來就是測試, 後來寫成一個類別, 發現處理訊息要靠 Form 表單來觸發, 於是加上繼承類別 NativeWindow, 並使用 AssignHandle 方法, 因為不知道主程式表單的 handle 何時產生, 又加上 Timers.Timer 來監控主程式表單, 結果碰到跨執行緒的問題, 所以再加上 invoke 功能, 到此測試監控遠端電腦 USB 裝置插拔的功能正常, 也許還有 bug 和改進的空間, 繼續工作囉,...
星期二, 十月 06, 2009
WMI Run Remote Process
如何使用 WMI 來遠端執行指定的應用程式, 經過網路搜尋雖然可以用 WIN32_Process 來執行遠端軟體, 但遠端電腦中不能顯示軟體的 UI.
(參考 MSDN WIN32_Process)
後來找到迂迴的方法, 在遠端建立指定軟體的排程工作 Win32_ScheduledJob, 然後再呼叫 schtasks 批次, 但是遠端建立的排程工作卻無法執行在(program files)資料夾中的的軟體, 所以最後利用 psexec 的工具軟體來實現遠端呼叫,
不過還是要設定防火牆的一些設定,
1. netsh firewall set service RemoteAdmin enable
2. netsh firewall add portopening protocol=tcp port=135 name=DCOM_TCP135
3. Do Administrative Tools->Local Security Settings->Local Policies->Security Options and look for the line "Network Access:Sharing and security model for local accounts". As of at most 6 months ago, the default value for this "key" was "Classic - local users authenticate as themselves". But new XP installations and those with recent security updates will have a default value of "Guest only - local users authenticate as Guest". Change it back to "Classic - local users... etc.,."
4. netsh firewall add allowedprogram program=%windir%\system32\wbem\unsecapp.exe name=UNSECAPP (以我的 case 不需要)
Dim options As New ConnectionOptions
With options
.Username = UserName
.Password = Password
End With
CMessage.Show("RemoteCall : " & RemoteIP, "Run remote process.", 26)
Dim scope As New ManagementScope(String.Format("\\{0}\root\cimv2", RemoteIP), options)
scope.Connect()
Dim getOptions As New ObjectGetOptions(Nothing, New TimeSpan(0, 0, 0, 3), True)
Dim processClass As New ManagementClass(scope, New System.Management.ManagementPath("Win32_Process"), getOptions)
For Each m As ManagementObject In processClass.GetInstances
If m("Name").ToString = ("Remote-Tool.exe") Then
m.InvokeMethod("Terminate", New Object() {0})
CMessage.Text("Terminate Process", 26) = "Stop Remote-Server..."
End If
Next
'==============Method Psexec Tool:
Shell(Application.StartupPath & String.Format("\psexec \\{0} -u {1} -p {2} -i -d ""notepad.exe""", RemoteIP, UserName, Password), AppWinStyle.NormalFocus, True)
Dim flag As Boolean
Do
For Each m As ManagementObject In processClass.GetInstances
If m("Name").ToString = "Remote-Tool.exe" Then
flag = True
Exit For
End If
Next m
Threading.Thread.Sleep(200)
Application.DoEvents()
Loop Until flag
End Using
星期二, 九月 29, 2009
VB.NET: 使用 WMI 呼叫應用程式
Using mr As New ManagementClass("Win32_ProcessStartup")
Dim objConfig As PropertyData = mr.Properties("ShowWindow")
objConfig.Value = 1
Using mc As New ManagementClass("Win32_Process")
mc.Scope.Options.EnablePrivileges = True
Dim inParams As ManagementBaseObject = mc.GetMethodParameters("Create")
inParams("CommandLine") = "Notepad.exe"
inParams("CurrentDirectory") = Environment.SystemDirectory
inParams("ProcessStartupInformation") = mr
Dim outParams As ManagementBaseObject = mc.InvokeMethod("Create", inParams, Nothing)
Dim returnObj As Object = outParams("ReturnValue")
End Using
End Using
已經成功使用 WMI 呼叫應用程式, 但如何呼叫遠端呢? 努力中...
星期四, 七月 09, 2009
如何在VB.NET中引用Dll
在VB.NET中通常可以用'加入參考'的方式來引用DLL
也可以用宣告API的方式,這裡我用的是另一種方式
1.需要用到一些函式 LoadLibrary , GetProcAddress , GetModuleHandle , FreeLibrary Public Declare Function GetProcAddress Lib "kernel32" _
(ByVal hModule As Integer, ByVal lpProcName As String) As Integer
Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" _
(ByVal lpProcName As String) As Integer
Public Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" _
(ByVal lpModuleName As String) As Integer
Public Declare Function FreeLibrary Lib "kernel32" Alias "FreeLibrary" _
(ByVal hLibModule As Integer) As Integer
2.加入System.Runtime.InteropServices參考Imports System.Runtime.InteropServices
3.宣告委派,依據DLL的函式,例如Public Delegate Function DllFunction _
(ByVal Parameter As Integer) As Integer
4.建立函式,例如Public Function FDllFunction _
(ByVal Parameter As Integer) As Integer
If hDEV = 0 Then Return -1
Dim v As Integer = GetProcAddress(hDEV, "DllFunction")
Dim a As DllFunction = _
CType(Marshal.GetDelegateForFunctionPointer(New IntPtr(v), _
GetType(DllFunction)), DllFunction)
If IsNothing(a) = False Then FDllFunction = a.Invoke(Parameter)
End Function
5.在使用DLL函式前,要先呼叫 Loadlibary
結束程式也要呼叫 FreeLibary

