https://blogs.msdn.microsoft.com/visualstudio/2018/09/13/how-can-i-pause-my-code-in-visual-studio-breakpoints-faq/
Visual Studio 是我用過最好用的 IDE,沒有之一。
中斷點這件事也是我看過不少碼農不甚使用的事。正好有官方提出一些小技巧給大家知道。
快速摘譯重點,成為超速譯的一篇。
設立 breakpoint
(1)左點左邊界 或是 按F9
(2)按F5
管理 breakpoint
(1)breakpoint window
(2) Debug -> Window -> Breakpoints
Conditional Breakpoint
(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件
(4)條件輸入完畢,關閉設定窗
Iteration breakpoint
(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件為 Hit Count
Function breakpoint
(1) Debug -> New Breakpoint -> Break at Function
Value change breakpoint
* C++, data breakpoints
* Watch Window or the Breakpoints Window 右點 變數 選擇 Break when value changes
* managed code, 針對某個 instance 的屬性偵測改變
(1)在 break mode,右點物件選擇 Make Object ID
(2)在欲偵測的屬性 setter 加入一個 conditional breakpoint 條件是 this == $1
(3)按F5,會停在 setter
(4)在 Call Stack 雙點前一個 frame 可以看到改變屬性的 code 是哪一行
exception breakpoint
在 Exception Settings 窗,設定哪些 exception 要停下來
call stack breakpoint
(1)Debug -> Windows -> Call Statck
(2)右點 calling function,選擇 Breakpoint -> Insert Breakpoint
disassembly breakpoint
(1)打開 disassembly window, Debug -> Windows -> Disassembly
(2)左點左邊界或按F9
2018年9月25日 星期二
2018年9月13日 星期四
[python] WARNING:tornado.general:Invalid multipart/form-data
用 flask 自帶的 server,有時就是會發出 500 之後就無法動作,要重開一次。
想說試試用 tornado 來裝 flask。結果就發現一個 warning。
於是再找一下定義 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
## 同場加映
header 裡的的資料若是超過 ISO-8859-1 還是有救。
剛好在 Content-Disposition 定義找到
https://tools.ietf.org/html/rfc5987
ex: foo: bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates
## tornado 原始碼部份
想說試試用 tornado 來裝 flask。結果就發現一個 warning。
WARNING:tornado.general:Invalid multipart/form-data查了一下,找到 tornado 原始碼 http://www.tornadoweb.org/en/stable/_modules/tornado/httputil.html,發現應該是 Content-Disposition 只要不是 form-data 就叫。
於是再找一下定義 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
> Only the value form-data, as well as the optional directive name and filename, can be used in the HTTP context.attachment 只能用在非 http 的情況。好吧,應該是要改成 form-data 才合規定。就改吧
## 同場加映
header 裡的的資料若是超過 ISO-8859-1 還是有救。
剛好在 Content-Disposition 定義找到
https://tools.ietf.org/html/rfc5987
ex: foo: bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates
## tornado 原始碼部份
def parse_multipart_form_data(boundary, data, arguments, files):"""Parses a ``multipart/form-data`` body.The ``boundary`` and ``data`` parameters are both byte strings.The dictionaries given in the arguments and files parameterswill be updated with the contents of the body... versionchanged:: 5.1Now recognizes non-ASCII filenames in RFC 2231/5987(``filename*=``) format."""# The standard allows for the boundary to be quoted in the header,# although it's rare (it happens at least for google app engine# xmpp). I think we're also supposed to handle backslash-escapes# here but I'll save that until we see a client that uses them# in the wild.if boundary.startswith(b'"') and boundary.endswith(b'"'):boundary = boundary[1:-1]final_boundary_index = data.rfind(b"--" + boundary + b"--")if final_boundary_index == -1:gen_log.warning("Invalid multipart/form-data: no final boundary")returnparts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n")for part in parts:if not part:continueeoh = part.find(b"\r\n\r\n")if eoh == -1:gen_log.warning("multipart/form-data missing headers")continueheaders = HTTPHeaders.parse(part[:eoh].decode("utf-8"))disp_header = headers.get("Content-Disposition", "")disposition, disp_params = _parse_header(disp_header)if disposition != "form-data" or not part.endswith(b"\r\n"):gen_log.warning("Invalid multipart/form-data")continuevalue = part[eoh + 4:-2]if not disp_params.get("name"):gen_log.warning("multipart/form-data value missing name")continuename = disp_params["name"]if disp_params.get("filename"):ctype = headers.get("Content-Type", "application/unknown")files.setdefault(name, []).append(HTTPFile( # type: ignorefilename=disp_params["filename"], body=value,content_type=ctype))else:arguments.setdefault(name, []).append(value)
2018年9月12日 星期三
[點網] process.MainWindowHandle == 0
## 原因
為了拿到 process 的 MainWindowHandle 作隱藏/顯示。
但是在隱藏之後,process 的 MainWindowHandle 會等於 0
## 使用 AttachConsole GetConsoleWindow FreeConsole
其中一個方法是針對 console app 的作法是接到 console,拿到其 consolewindow 要到 ID,再離開。
使用 AttachConsole GetConsoleWindow FreeConsole
宣告需要:
```
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
int GetSmsdMainWindowHandle(int procID)
Int32 tryHandle = 0;
try
{
AttachConsole((uint)procID);
tryHandle = GetConsoleWindow().ToInt32();
FreeConsole();
}
catch (Exception)
{
//pass
}
finally
{
FreeConsole();
}
return tryHandle;
}
```
使用方法:
```
int smsdMainWindowHandle = GetSmsdMainWindowHandle(xProc.Id);
```
## 使用 EnumChildWindows GetWindowThreadProcessId
另一個方法是列舉所有 子window 再拿到其 window thread 的 process ID。
使用 EnumChildWindows GetWindowThreadProcessId
宣告需要:
```
private struct SearchData
{
// You can put any vars in here...
public int currentTaskID;
public IntPtr currenthWnd;
}
private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, ref SearchData data);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);
bool EnumProc(IntPtr hWnd, ref SearchData data)
{
int lProcID;
GetWindowThreadProcessId(hWnd,out lProcID);
if (lProcID == data.currentTaskID)
{
data.currenthWnd = hWnd;
}
return true;
}
```
使用方法:
```
SearchData n = new SearchData();
n.currentTaskID = xProc.Id;
EnumChildWindows(IntPtr.Zero,new EnumWindowsProc(EnumProc),ref n);
int smsdMainWindowHandle = (int)n.currenthWnd;
```
這個方法的 VB Code 由 Cyrus 提供:
```
Dim currenthWnd = 0
Public Function fEnumWindowsCallback(ByVal hWnd As Integer, ByVal lpData As Integer) As Integer
fEnumWindowsCallback = 1
Dim lProcID As Integer
Call GetWindowThreadProcessId(hWnd, lProcID)
If lProcID = currentTaskID Then
currenthWnd = hWnd
End If
End Function
Call EnumChildWindows(0&, AddressOf fEnumWindowsCallback, 0&)
If currenthWnd <> 0 Then
If goSECSInterface.GEMObject.HideSMSD = True Then
ShowWindow(currenthWnd, SW_HIDE)
Else
ShowWindow(currenthWnd, SW_NORMAL)
End If
End If
```
## 參考:
- * https://stackoverflow.com/questions/8949652/do-windows-api-enumwindows-and-enumchildwindows-functions-behave-differently-in
2018年9月11日 星期二
[pi-nas]raspberry pi glusterfs 換硬碟
在樹莓派上裝 gluster,硬碟壞了要換掉。查了幾種方式要來試試。但是想先試個最無腦的方法,就是 umount 舊硬碟,mount 新硬碟,看看有沒有比較方便。以下就是過程。
步驟 1
停止 gluster daemon
`sudo systemctl stop glusterfs-server`
這個只能讓 umount /mnt/gv0 成功,umount /data/brick1 還是不行
glusterfsd 還是佔著,查詢誰在用檔案或掛載 `fuser -m -u /data/brick1`。
用 `sudo /etc/init.d/glusterfs-server stop` https://gluster.readthedocs.io/en/latest/Administrator%20Guide/Start%20Stop%20Daemon/ 也不行
最後只好使用 `kill -9 PID` 處理掉,比較溫和應該用 `kill -15 PID`
umount /data/brick1 成功
步驟 2
拔掉舊的硬碟,插入新的硬碟,格式化
`sudo mkfs.xfs -i size=512 /dev/sda1`
修改 fstab `PARTUUID=c121432b-52f5-4bb2-a260-0d38992df858 /data/brick1 xfs defaults 1 2` 其中 PARTUUID 用 `blkid /dev/sda1` 查詢
`sudo mount -a`
`sudo mkdir /data/brick1/gv0`
到這,試試重開。
步驟 3
檢查 heal 狀況 `sudo gluster volume heal gv0 info`
看來直換是沒有,還需要下些指令。glusterfsd 3.9.0 有 reset-brick 看起來很好用,但!
我的 glusterfsd 是 3.8.8-1 沒有支援 reset-brick。
自身 replace `sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0 commit force` 也不行。
所以一定要換個新名字,所以改成 gv0_1:
`sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0_1 commit force`
這個時候,pi315 的 glusterfsd 才起得來
然後,heal 就自動開始了。
查看 heal 狀態 `sudo gluster volume heal gv0 info`
到這其實就結束了,但是如果很在意那個 gv0_1 的話,我在 heal 結束之後又執行了一次 `replace-brick` 只是把 gv0_1 又換成 gv0。要考慮硬碟空間要足夠兩倍大。看硬碟閃,還是從 pi314 那裡拿資料。
參考:
## 有故意使用 setfattr 強迫 heal
https://serverfault.com/questions/710220/how-do-you-add-a-replacement-hdd-to-a-glusterfs-volume
https://lists.gluster.org/pipermail/gluster-users/2014-August/018515.html
https://docs.gluster.org/en/v3/Administrator%20Guide/Managing%20Volumes/#replace-brick
## 只使用 sudo gluster volume replace-brick 舊brick 新brick
https://sysadmins.co.za/replace-faulty-bricks-in-glusterfs/
## 使用 reset-brick
https://docs.gluster.org/en/latest/release-notes/3.9.0/
步驟 1
停止 gluster daemon
`sudo systemctl stop glusterfs-server`
這個只能讓 umount /mnt/gv0 成功,umount /data/brick1 還是不行
glusterfsd 還是佔著,查詢誰在用檔案或掛載 `fuser -m -u /data/brick1`。
用 `sudo /etc/init.d/glusterfs-server stop` https://gluster.readthedocs.io/en/latest/Administrator%20Guide/Start%20Stop%20Daemon/ 也不行
最後只好使用 `kill -9 PID` 處理掉,比較溫和應該用 `kill -15 PID`
umount /data/brick1 成功
步驟 2
拔掉舊的硬碟,插入新的硬碟,格式化
`sudo mkfs.xfs -i size=512 /dev/sda1`
修改 fstab `PARTUUID=c121432b-52f5-4bb2-a260-0d38992df858 /data/brick1 xfs defaults 1 2` 其中 PARTUUID 用 `blkid /dev/sda1` 查詢
`sudo mount -a`
`sudo mkdir /data/brick1/gv0`
到這,試試重開。
步驟 3
檢查 heal 狀況 `sudo gluster volume heal gv0 info`
```
pi@pi315:~ $ sudo gluster volume heal gv0 info
Brick pi314:/data/brick1/gv0
Status: Connected
Number of entries: 0
Brick pi315:/data/brick1/gv0
Status: Transport endpoint is not connected
Number of entries: -
```
看來直換是沒有,還需要下些指令。glusterfsd 3.9.0 有 reset-brick 看起來很好用,但!
我的 glusterfsd 是 3.8.8-1 沒有支援 reset-brick。
自身 replace `sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0 commit force` 也不行。
所以一定要換個新名字,所以改成 gv0_1:
`sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0_1 commit force`
這個時候,pi315 的 glusterfsd 才起得來
```
pi@pi314:~ $ sudo gluster volume status
Status of volume: gv0
Gluster process TCP Port RDMA Port Online Pid
------------------------------------------------------------------------------
Brick pi314:/data/brick1/gv0 49153 0 Y 1492
Brick pi315:/data/brick1/gv0_1 49153 0 Y 1846
Self-heal Daemon on localhost N/A N/A Y 26710
Self-heal Daemon on pi315 N/A N/A Y 1851
Task Status of Volume gv0
------------------------------------------------------------------------------
There are no active volume tasks
```
然後,heal 就自動開始了。
查看 heal 狀態 `sudo gluster volume heal gv0 info`
到這其實就結束了,但是如果很在意那個 gv0_1 的話,我在 heal 結束之後又執行了一次 `replace-brick` 只是把 gv0_1 又換成 gv0。要考慮硬碟空間要足夠兩倍大。看硬碟閃,還是從 pi314 那裡拿資料。
參考:
## 有故意使用 setfattr 強迫 heal
https://serverfault.com/questions/710220/how-do-you-add-a-replacement-hdd-to-a-glusterfs-volume
https://lists.gluster.org/pipermail/gluster-users/2014-August/018515.html
https://docs.gluster.org/en/v3/Administrator%20Guide/Managing%20Volumes/#replace-brick
## 只使用 sudo gluster volume replace-brick 舊brick 新brick
https://sysadmins.co.za/replace-faulty-bricks-in-glusterfs/
## 使用 reset-brick
https://docs.gluster.org/en/latest/release-notes/3.9.0/
訂閱:
文章 (Atom)