Friday, December 29, 2006

ZwOpenFile and ZwCreateFile

使用 ZwOpenFile 可以編譯過, 但是 Window 在載入 Driver Image 時卻會認為這是個已損毀的 Image, 換成 ZwCreateFile 就可以. 怪.





powered by performancing firefox

Monday, November 20, 2006

程式碼排版工具 這是我老闆要我找的,不過我本身也有興趣啦。本來要用 Eclipse 交差的,不過 Eclipse 竟然只內建 java 的 formatter......。 Artistic Style:這個不用錢!不過它沒有 GUI,功能也沒有很多。 SourceFormatX:這個要錢,不過它有 GUI ,而且選項比較多。

Monday, August 28, 2006

Facts and Fallacies of Software Engineering

這本書指出軟體工程的一些事實跟謬誤,還不錯啦。

People

Fact 2

The best programmers are up to 28 times better than the worst programmers, according to "individual differences" research. Given that their pay is never commensurate, they are the biggest bargains in the software field.

說得很好,不過很多老闆似乎並不這麼想。

Fact 3

Adding people to a late project makes it later.

這算人月傳奇的一種吧。反正大家都認為把人塞進專案內,專案就可以加速。事實上並不是這樣的。

Fact 4

The working environment has a profound impact on productivity and product quality.

工作環境很重要!我喜歡這句話:You must get good people, and then you must treat them well, especially in providing a workable environment.

不過工作環境包含工作氣氛嗎?我的工作環境不錯啊,不過氣氛很差。

Tools and Techniques

Fact 6

Learning a new tool or technique actually lowers programmer productivity and product quality initially. The eventual benefit is achieved only after this learning curve is overcome. Therefore, it is worth adopting new tools and techniques, but only (a) if their value is seen realistically and (b) if patience is used in measuring benefits.

可惜大部分的老闆似乎不太瞭解這一點。原因當然是專案很急啊,哪有這個時間去等。

Fact 7

Software developers talk a lot about tools. They evaluate quite a few, buy a fair number, and use practically none.

這個應該是工程師的現象。新奇的東西不玩玩看實在是很對不起自己,但是玩完之後就謝謝再聯絡。

Estimation

Fact 8

One of the two most common causes of runaway projects is poor estimation.

Do we have estimatted something? Hahaha.

Fact 9

Most software estimates are performed at the beginning of the life cycle. This makes sense until we realize that estimates are obtained before the requirements are defined and thus before the problem is understood. Estimation, therefore, usually occurs at the wrong time.

需求未清楚定義之前就先作評估,這當然是錯的。不過很可悲的是,大家好像都是這樣搞專案的。

Fact 10

Most software estimates are made either by upper management or by marketing, not by the people who will build the software or their managers. Estimation is, therefore, done by the wrong people.

同樣地,要評估一件事情,應該是由要作這件事情的人去評估,而不是讓經理人去作。大家都會這樣啦,不過最終決定權還是在經理人手上......。

Fact 11

Software estimates are rarely adjusted as the project proceeds. Thus those estimates done at the wrong time by the wrong people are usually not corrected.

廢話!

Fact 14

The answer to a feasibility study is almost always "yes."

嗯嗯,這是理想狀態啦。

Reuse

Fact 19

Modification of reused code is particularly error-prone. If more than 20 to 25 percent of a component is to be revised, it is more efficient and effective to rewrite it from scratch.

Requirements

Fact 23

One of the two most common causes of runaway projects is unstable requirements.

是啊,需求一直改來改去,根本無法專心把設計搞定啊。

Design

Fact 28

Design is a complex, iterative process. The initial design solution will likely be wrong and certainly not optimal.

所以才會需要作 refactoring。

Testing

Fact 32

Software that a typical programmer believes to be thoroughly tested has often had only about 55 to 60 percent of its logic paths executed. Using automated support, such as coverage analyzers, can raise that roughly to 85 to 90 percent. It is nearly impossible to test software at the level of 100 percent of its logic paths.

工具不是萬能,但是有助於測試的當然是好工具。

Fact 35

Test automation rarely is. That is, certain testing processes can and should be automated. But there is a lot of the testing activity that cannot be automated.

同感,有些東西硬要用自動化測試,實在是強人所難。出一張嘴當然是很簡單啊,做了才知道。

Reviews and Inspections

Fact 37

Rigorous inspections can remove up to 90 percent of errors from a software product before the first test case is run.

Did we have ever code review? Hahaha.

Fact 38

In spite of the benefits of rigorous inspections, they cannot and should not replace testing.

廢話。

Fact 39

Postdelivery reviews (some call them "retrospectives") are generally acknowledged to be important, both from the point of view of determining customer satisfaction and from the point of view of process improvement. But most organizations do not do postdelivery reviews.

深有同感。

Fact 40

Peer reviews are both technical and sociological. Paying attention to one without the other is a recipe for disaster.

Peer reviews? 那是甚麼?可以吃嗎?

Efficiency

Fact 52

Efficiency stems more from good design than from good coding.

架構不好效能就差,而且不改架構幾乎是無解。

Fact 53

High-order language (HOL) code, with appropriate compiler optimizations, can be about 90 percent as efficient as the comparable assembler code. Or even higher, for some complex modern architectures.

compiler 萬歲!

Fact 54

There are tradeoffs between size and time optimization. Often, improving one degrades the other.

修過 CS 的 Algorithm 就能夠深深體會這句話。有一好沒兩好。

Testing

Fallacy 7

Random test input is a good way to optimize testing.

Random test 的大問題是,如何知道出問題的是哪個部份。假設整個系統使用 Random test,假設它出現 test fail,怎麼知道這個 fail 是如何產生的呢?因為不能複製 fail 的話,根本無法對這個 fail 除錯,那 run random test 有何意義呢。

Fallacy 10

You teach people how to program by showing them how to write programs.

所以教人家寫code 不如教人家看 code。

Tuesday, August 15, 2006

Windows Application 的 Localization

參考http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcconLocalizedResourcesInMFCApplicationsSatelliteDLLs.asp 只要準備好相對應的 Satellite DLL,OS 就會根據使用者目前的語系,把對應的 Satellite DLL 載入,然後再載入你的應用程式。 Satellite DLL 的命名規則是,如果程式是 ABC.exe,則繁體中文的 Satellite DLL 名稱為 ABCCHT.dll。Satellite DLL 是個 Resource Only DLL,也就是裡面只包含 Resource 相關的資料。 至於如何知道使用者的語系?GetUserDefaultUILanguage() 這個 API 就可以了。繁體中文的 LANGID 為 0x0404。

MFC 的 Dynamic Object Creation

這玩意實在是有點鳥,根據 Programming Windows With MFC 第九章的講法, DECLARE_DYNCREATE(CMyClass) 是個 macro,會被轉成: public: static const AFX_DATA CRuntimeClass classCMyClass; virtual CRuntimeClass *GetRuntimeClass; static CObject *PASCAL CreateObject(); IMPLEMENT_DYNCREATE(CMyClass, CBaseClass) 也是個 macro,其中會把 CreateObject 寫成: CObject *PASCAL CMyClass::CreateObject(){ return new CMyClass; } 最好玩的是,RUNTIME_CLASS() 這個 macro。RUNTIME_CLASS(CMyClass)->CreateObject() 跟 CMyClass *t = new CMyClass(); 是一樣的啊。

Monday, August 14, 2006

Windows USB Driver IRP 射後不理的方式

目的:想要非同步丟 IRP,但是不想管理及善後 IRP 。

在 Programming The Microsoft Windows Driver Model 一書,第十二章,有提到如何用同步的方式發出 USB 的 IRP。但是它沒提到如何發出非同步的 USB IRP。非同步發出 USB IRP 的方式是必要的,因為你總不可能每次都等待這個 IRP 完成後才進行下個步驟吧。 其實 irp 善後很簡單,只要呼叫 iofreeirp 就可以。不過因為 usb 還要多 free urb,所以事情會稍微複雜一點。我原本想要在 complete routine 內利用傳入的 irp 把它對應的 urb 給找出來,不過失敗了(其實這是有可能的,而且這才是比較正確的作法)。所以只好利用傳入的 context 來搞花樣。

IRP 射後不理的方式很簡單,只要能夠在 complete routine 內把對應的 irp 及 urb free 掉就可以。作法是弄一個 data struct ,把 irp 及 urb 的 pointer 寫進去,最後把這個 data struct 傳給 complete routine 。然後你就可以在 complete routine 內 free irp 及 urb。問題來了,這個 data struct 是動態 allocate 的,所以也要 free 它,可以在 complete routine 內 free 它嗎?答案是可以的,所以一切事情就解決了。

要注意幾點: 1. iofreeirp 必須在 complete routine 內最後呼叫,不然整個 OS 會 hang 住。我不知道這是為甚麼。

2. 這樣作會大量消耗 CPU resource。

3. 如果 irp 無法 complete,你也無法 cancel 它。這是個大問題,不過這樣只會導致你的 driver halt 後,在 non-paged pool 內發生 memory leak。解決方法是有,不過考量現況,不作也罷。最快的方式是重開機。不過我很少遇到 irp 不會 complete 的狀況。

下面是範例: ---------------------------------------------------------------------------------------

struct IRP_INFO{ DeviceInfo *deviceInfo; USBD_PIPE_HANDLE pipeHandle; PURB pUrb; UCHAR data[2048]; };
/*! \brief The Completion routine for Asynchronous Bulk Out request. */ NTSTATUS USBAsynchronousBulkOutComplete(PDEVICE_OBJECT pUSBDeviceObject, PIRP pIrp, PVOID context) {
NTSTATUS status = STATUS_SUCCESS; struct IRP_INFO *irpInfo = (struct IRP_INFO *)context; DeviceInfo deviceInfo = irpInfo->deviceInfo; PADAPTER pAdapter = (PADAPTER)deviceInfo->pAdapter; USBD_PIPE_HANDLE pipeHandle; ULONG fifoIndex = 0;
// find this IRP belongs which Endpoint pipeHandle = irpInfo->pipeHandle;
if( pIrp->Cancel == TRUE ) { DbgPrint("AsynchronousBulkOutComplete(() : IRP has been cancelled.\n"); }
NdisFreeMemory(irpInfo->pUrb, sizeof(URB), 0); NdisFreeMemory(irpInfo, sizeof(struct IRP_INFO), 0); IoFreeIrp(pIrp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
// \brief USB Asynchronous Bulk Out // This function can be called at IRQL <= Dispatch Level. NDIS_STATUS USBASynchronousBulkOut(ADAPTER *pAdapter, ULONG fifoIndex, UCHAR *data, ULONG dataLength){ NDIS_STATUS status = NDIS_STATUS_SUCCESS; PURB pUrb = NULL; HANDLE usbPipeHandle = NULL; IO_STATUS_BLOCK ioStatus; PIRP pIrp; NTSTATUS ntStatus; PIO_STACK_LOCATION stack; USBD_STATUS usbStatus; struct IRP_INFO *irpInfo = NULL;
if (dataLength > 2048) { return NDIS_STATUS_NOT_ACCEPTED; }
usbPipeHandle = pAdapter->BulkOutPipeHandle;
// Allocate IRP_INFO NdisAllocateMemoryWithTag((PVOID *)&irpInfo, sizeof(struct IRP_INFO), 'AABB'); if (irpInfo == NULL){ KdPrint(("USBASynchronousBulkOut() : can not allocate IRP_INFO.\n")); return NDIS_STATUS_NOT_ACCEPTED; }
// Allocate URB NdisAllocateMemoryWithTag((PVOID *)&pUrb, sizeof(URB), 'AABB'); if (pUrb == NULL){ KdPrint(("USBASynchronousBulkOut() : can not allocate URB.")); NdisFreeMemory(irpInfo, sizeof(struct IRP_INFO), 0); return NDIS_STATUS_NOT_ACCEPTED; }
// Allocate IRP pIrp = IoAllocateIrp(pAdapter->NextDeviceStackSize, FALSE); if (pIrp == NULL){ KdPrint(("USBASynchronousBulkOut() : can not allocate IRP.")); NdisFreeMemory(pUrb, sizeof(URB), 0); NdisFreeMemory(irpInfo, sizeof(struct IRP_INFO), 0); return NDIS_STATUS_NOT_ACCEPTED; }
irpInfo->deviceInfo = &pAdapter->DeviceInfo; irpInfo->pipeHandle = usbPipeHandle; irpInfo->pUrb = pUrb; NdisMoveMemory(irpInfo->data, data, dataLength);
// Build URB for USBD UsbBuildInterruptOrBulkTransferRequest( pUrb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbPipeHandle, (PVOID)irpInfo->data, NULL, dataLength, 0, NULL);
// call the calss driver to perform the operation // pass the URB to the USB driver stack stack = IoGetNextIrpStackLocation(pIrp); stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; stack->Parameters.Others.Argument1 = pUrb; stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine( pIrp, // irp to use USBAsynchronousBulkOutComplete, // routine to call when irp is done (PVOID)irpInfo, // context to pass routine TRUE, // call on success TRUE, // call on error TRUE); // call on cancel
// Call IoCallDriver to send the irp to the usb port ntStatus = IoCallDriver(pAdapter->DeviceIfno.pUSBDeviceObject, pIrp); usbStatus = URB_STATUS(pUrb);
// The USB driver should always return STATUS_PENDING when it receives a write irp if ( ntStatus != STATUS_PENDING || USBD_HALTED(usbStatus) ) {
DbgPrint("[Error]USBASynchronousBulkOut() : IoCallDriver failed!!! IRP STATUS = 0x%X, USB STATUS = %X.\n", ntStatus, usbStatus); status = NDIS_STATUS_NOT_ACCEPTED;
} else {
status = NDIS_STATUS_SUCCESS; }
return status; }

Windows NDIS Protocol Dirver 自動反安裝的作法

呼叫 WINDDK\src\network\config\bindview\component.cpp 裡面, HRESULT UninstallComponent (LPWSTR lpszInfId) 即可。 問題是,lpszInfId 到底要傳甚麼進去?其實,lpszInfId 跟呼叫 INetCfgClassSetup->Install() 安裝 Driver 時,所傳入的 pszwComponentId 是一樣的,也就是 componentID。不知道為甚麼註解會寫的如此的隱晦。

Saturday, August 12, 2006

Valkyrie Profile 2 Seraphic Gate 第一輪突破

其實 SG 第一輪也沒有很難啦。花點時間把魔晶石賺到 40000 點(這個真的要賺很久,找スルス火山洞窟 的老大打,給敵方裝 軽き綿埃の戒,然後先把它浮空,然後三個弓箭手齊射,每場都 80 個。),然後去換封印石 威を凪ぐ鞘の戒常に常とする理,第一輪大概就可以輕鬆過關了。 只是,如果沒有加攻擊力的話,要打很久罷了。 所以目標很簡單,加攻擊力: 1. 先找 フレイ 加入。 2. 讓對上其他三人躺在地上。 3. フレイ 的技能掛上:ソリタリィストラグルアイアンフィスト 4. 己方封印石:常に常とする理鋭剣の理糧なき突撃兵の理剣の加護 5. 敵方封印石:威を凪ぐ鞘の戒手械の戒 6. フレイ 的裝備:魔龍的大角 * 4 這樣打イセリア・クイーン 根本是小菜一碟。イセリア・クイーン最難打的是她會放傳送,這個實在很麻煩,有防傳送的裝備似乎不好找,所以只好用 常に常とする理 來防。 魔龍的大角要找バハムート打。問題來啦,攻擊力不夠才會需要打魔龍的大角,可是攻擊力不夠是無法拆バハムート的身體的。陷入矛盾中.....。 這樣只好吃重劍英靈啦。重劍英靈要裝備壊剣ティルフィング,解放後就會留下劍士知識 * 99。壊剣ティルフィング 只要 DA ティアマット 即可。依照目前的狀況,フレイ 要DA 它實在很簡單。所以一切問題都解決啦。 ディルナ・ハミルトン 的攻略也是如此,只是無法裝手械の戒。一下子就解決了。

Friday, August 11, 2006

Windows NDIS Protocol Dirver 自動安裝的作法

1. 準備好 inf 跟 sys 檔案。 2. 呼叫 SetupCopyOEMInf() 3. Windows DDK 內有個 bindview(WINDDK\3790.1830\src\network\config\bindview),裡面有寫如何 install/uninstall network component。 基本上它是利用 INetCfg 這個 COM interface 來安裝 network component。COM 的 C++ 寫法有些繁雜,不過這些程式碼用抄的就可以 work 了。 取 得 INetCfg interface 後,便可以透過 INetCfg 取得 INetCfgClass interface,然後再透過 INetCfgClass 取得 INetCfgClassSetup,然後再呼叫 INetCfgClassSetup 的 Install method 安裝 network component。 HRESULT Install ( IN LPCWSTR pszwComponentId, IN OBO_TOKEN *pOboTokendwSetupFlags, IN DWORD dwUpgradeFromBuildNo, IN LPCWSTR pszwAnswerFile, IN LPCWSTR pszwAnswerSections, OUT INetCfgComponent **ppComponent OPTIONAL ); 比較機車的是 pszwComponentId 要給甚麼。要給它的是 INF 檔案中的某個字串,EX: Provider = %Msft% [MSFT.NTx86] %NDISPROT_Desc%=Install, MS_NDISPROT_XXXX 看到 MS_NDISPROT_XXXX 了嗎?把它丟給 pszwComponentId 即可。 pszwAnswerFilepszwAnswerSections 目前不清楚是甚麼。不過傳 NULL 似乎也可以。

Windows Dirver 自動安裝的作法

1. 準備好 inf 跟 sys 檔案。 2. 呼叫 SetupCopyOEMInf(), 其 prototype :
BOOL WINAPI SetupCopyOEMInf(
PCTSTR SourceInfFileName,
  PCTSTR OEMSourceMediaLocation,
  DWORD OEMSourceMediaType,
  DWORD CopyStyle,
  PTSTR DestinationInfFileName,
  DWORD DestinationInfFileNameSize,
  PDWORD RequiredSize,
  PTSTR DestinationInfFileNameComponent
); 
CopyStyle 比較機車一點,SP_COPY_DELETESOURCE 會把原始的 INF 檔案砍掉。我是選SP_COPY_NOOVERWRITE,這樣似乎每次呼叫 SetupCopyOEMInf() 都會成功的樣子。
SetupCopyOEMInf() 會把你的INF copy 到 Windows\Inf\ 下面,並且 rename 為 oemXX.inf,
然後為這個 INF 檔產生相對應的 PNF 檔案。之後如果你把相對應的 Device 插進 PC 內,
Windows會去找尋這些 oemXX.inf 檔案,然後自動幫你把 driver 安裝到好。

至於 sys 檔案勒?這個就再研究了。

codeblock