1.22.2010

combine 2 .lib into one - or add .obj into .lib

要用 LIB.EXE (不是 AR)

command 就是:

C:\XXX> lib one.obj two.lib /OUT:newname.lib

這樣就可以把 one.obj 跟 two.lib 合併成 newname.lib


在 platform buidler 裡,static library 的專案。
就可以把 上面的 command 寫在 postlink.

這樣就要這注意最後 libraryname ,要改 sources 中的 TARGETNAME,然後 postlink 中的 command 才用真正的 library name。


在 VS2005 里,要在
LIB ".\SDKV0.0.0.8 (ARMV4I)\Debug\mycode.obj" additional.lib /OUT:finalLIB.lib

但是 正式的作法大概是把 additional.lib 寫在 project property 的 Librian -- Additional Dependencies 里

1.21.2010

CeDebugX

msdn 有寫 cedebugx60.dll 在
C:\Program Files\Microsoft Platform Builder\6.00\cepb\bin\Extensions

可以用 platform buidler (in VS2005 mode) 的 load extension load 進來。

貼一下 help:

Error resolving expression <{,,kernel.dll}g_pprcNK->dwId>
ERROR in ReadStruct, can't read {,,kernel.dll}g_pprcNK->dwId

Unable to resolve NK.EXE symbols.

Is the debugger in a break state?

If not, you must first break into the debugger before attempting to use
debugger extension commands.

If so, make sure that valid symbols are loaded.


CEDEBUGX

File Version : 6.00.2217.1
Product Version : 6.00.2217.1


COMMANDS:

To see detailed help type the command followed by /?

Extension Information and Control:

help - display this list
version - display version information for this extension
refresh - refresh cached info (must call after any run/break cycle).
xml - capture debug info in an xml file and display formatted data.
save - prompts the user for a location in which to save all files generated in the session.
getworkingpath - display the path to the debugger extension's current working folder.
setworkingpath - specify a path to use as a new destination for saved files (working folder)

General Information:

exception - exception info and current call stack
kinfo - prints the UserKInfo table
toc - prints ROM table of contents
oat - prints OEM Address Table
disasm - retrieve disassembly for a given address
getsym - list nearest symbol at addr
checksymbols - validate that correct symbols are in use.
dd - dump data at given address
ll - prints linked lists generically
expr - evaluate an expression
getsizeof - get the size, in bytes, of a type or expression
d2x - convert a decimal integer to a hex value.
x2i - convert a hex value to a singed integer.
x2u - convert a hex value to an unsigned integer.
ms2t - display a value in milliseconds as hours, minutes, and seconds.

Diagnostics:

diagnose - provide detailed information about hangs or crashes

Threads:

thread - prints thread information from thread ptr
threadh - prints thread information from thread handle
threadlist - enumerate all threads (basic info). use "threadlist ?" for more options
allthreads - enumerate all threads (extended info)
runlist - enumerate threads on the scheduler's run list.
sleeplist - enumerate threads on the scheduler's sleep list.
context - print context information for a given thread.
stackeval - prints all values on a thread's stack, looking for potential symbols and known objects
stacktrace - prints stack ptr and frame ptrs with PC and ret addr for a given thread

Processes and Modules:

proc - prints process information
proclist - lists all processes
module - prints module information
modlist - lists all loaded modules

Handles:

handlelist - prints active handle list
handle - evaluates a handle to determine type
h2p - get kernel object ptr from a handle
p2h - get a handle from a kernel object ptr

Blocked Threads:

proxy - prints detailed information about a particular proxy (i.e. blocking object)
proxylist - lists all of the proxies in the system or owned by a particualr process
blocked - prints list of blocking objects (proxies) and the threads they are blocking
cslist - prints a list of critical sections that are currently blocking threads
eventlist - prints a list of events that are currently blocking threads
sending - prints a list of threads blocked in SendMessage calls

Memory:

heaplist - prints summary information about all heaps in the system
heapwalk - print extended heap information
walkthisheap - print heap information for specific heap
meminfo - prints system memory information
heapitem - finds a heap item spanning an address and dumps item contents
dumpitem - prints contents of a heap item
valist - prints virtual allocations associated with a process
fsmaplist - prints summary information about all memory-mapped files
fsmap - prints information about a memory-mapped file
fsviewlist - prints summary information about all memory-mapped views
fsview - prints information about a memory-mapped view
pgpool - prints information about the page pools

GWES:

win - enumerate all windows (use it without arguments for more options)
winh - prints the window information for a handle (can use p|c|n|d|a) for navigation
gditable - enumerate all GDI entries
gdih - prints the information of the GDI entity related to the provided handle
gdiobj - prints the information of the GDI entity related to the provided gdi object
screenshot - creates and shows a screenshot of the current UI state of the device
msgqueues - lists active message queues



allthreads 功能真強大.. 會列出所有 thread 的 runstate 和 call stack。

配上 runlist - 列出 scheduler 的 runlist ,可以看出哪個 thread 太糟糕,站住cpu time.

1.18.2010

糟糕的: CeRunAppAtEvent

只能說這真是一個/組莫名奇妙的api呀....

CE 可以用
CeRunAppAtEvent(_T("\\\\.\\Notifications\\NamedEvents\\MYWAKEUPEVENT"),
NOTIFICATION_EVENT_WAKEUP
要求 kernel (GWES) 把 OS內部 的 EVENT_WAKEUP 轉成 Signal MYWAKEUPEVENT。

但是...這個 funciton 被 call 幾次, wakeup 時,那個 event 就會被 signal 幾次。
也就是說,即使你的 ap 已經結束,但是event 已經 create 起來,OS也註冊了,所以即使你的 Ap 已經結束了,OS 還是會依照註冊的內容執行..


所以,要 記得 un-register...就是把那個 event 改對應到 NOTIFICATION_EVENT_NONE 就可以:
CeRunAppAtEvent(_T("\\\\.\\Notifications\\NamedEvents\\MYWAKEUPEVENT"),
NOTIFICATION_EVENT_NONE)


附上測試的 code :

// SYSWAKEUPEVENT.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#include <notify.h>


HWND MainWnd;
int rcvcnt=0;

DWORD WINAPI WaiterThread(PVOID pArg)
{
HANDLE WakeUpEvent;

WakeUpEvent = CreateEvent(NULL,FALSE,FALSE,_T("MYWAKEUPEVENT"));
if(WakeUpEvent == NULL){
RETAILMSG(1,(TEXT("CreateEvent Failed\r\n")));
ExitThread(0);
}

if(!CeRunAppAtEvent(_T("\\\\.\\Notifications\\NamedEvents\\MYWAKEUPEVENT"),
NOTIFICATION_EVENT_NONE)){
RETAILMSG(1,(TEXT("CeRunAppAtEvent NONE Failed\r\n")));
ExitThread(0);
}


if(!CeRunAppAtEvent(_T("\\\\.\\Notifications\\NamedEvents\\MYWAKEUPEVENT"),
NOTIFICATION_EVENT_WAKEUP)){
RETAILMSG(1,(TEXT("CeRunAppAtEvent Failed\r\n")));
ExitThread(0);
}

while(1){
DWORD EventGot;

EventGot = WaitForSingleObject(WakeUpEvent,INFINITE);
if(EventGot==WAIT_OBJECT_0){
rcvcnt++;
RETAILMSG(1,(TEXT("received! %d\r\n"),rcvcnt));
InvalidateRect(MainWnd,NULL,TRUE);
}else{
RETAILMSG(1,(TEXT("receive not object 0 : %d\r\n"),EventGot));
}
}

}

HANDLE hWaiterThread;


LRESULT CALLBACK MainWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
RECT rect;
HDC hdc;

switch(wMsg){
case WM_PAINT:
{
TCHAR outtext[50];

GetClientRect(hWnd,&rect);
hdc = BeginPaint(hWnd, &ps);

swprintf(outtext,TEXT("Received WAKEUP EVENT: %d"),rcvcnt);

DrawText(hdc, outtext,-1,&rect,DT_CENTER | DT_CENTER | DT_SINGLELINE);
EndPaint(hWnd,&ps);
}
return 0;
case WM_DESTROY:
if(hWaiterThread)
CloseHandle(hWaiterThread);
PostQuitMessage(0);
}
return DefWindowProc(hWnd, wMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wc;
MSG msg;

// register the main windows class
wc.style = 0;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("SYSWAKEUPEVENT");

if(RegisterClass(&wc) == NULL){
RETAILMSG(1,(TEXT("RegisterClass Failed\r\n")));
return -1;
}

MainWnd = CreateWindowEx(WS_EX_NODRAG,TEXT("SYSWAKEUPEVENT"),TEXT("SYSWAKEUPEVENT"),
WS_VISIBLE | WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
if(!IsWindow(MainWnd)){
RETAILMSG(1,(TEXT("CreateWindowsEx Failed\r\n")));
return -2;
}

ShowWindow(MainWnd,nCmdShow);
UpdateWindow(MainWnd);

hWaiterThread = CreateThread(NULL,0,WaiterThread,NULL,0,NULL);
if(hWaiterThread == NULL){
RETAILMSG(1,(TEXT("CreateThread Failed\r\n")));
}





while(GetMessage (&msg,NULL,0,0) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return msg.wParam;


return 0;
}

reference 這一個 (http://social.msdn.microsoft.com/Forums/en-US/vssmartdevicesvbcs/thread/11c91a9f-9626-4db5-afaa-233ad514e6a3) 討論串。

WM_PAINT, InvalidRect, ValidRect, and UpdateWindow

超複雜。

UpdateWindow, WM_PAINT, InvalidateRect, ValidateRect..


大概是說:GWES 會為每個 Windows mantain 一個 invalid region list : 哪些區域的圖形已經過時,需要重畫了。
而且當 invalid region 不是空的時候,就會送出 WM_PAINT 給 Windows (自動嗎?)。

Windows Application 在 call BeginPaint 時,GWES 就會把 invalude region list 清空 (因為你已經要開始重畫了)


因為 WM_PAINT 的 message priority 很低,所以系統很忙的時候,call InvalidRec( ) 可能會很久以後才會送出 WM_PAINT。
如果要立刻送,可以自己call UpateWindows( )。這個funciton 會立刻送出 WM_PAINT 給 application。

1.13.2010

ape.cue to mp3 with tag

要將當初保存的 losses CD 由 ape+cue轉成 有 tag的 mp3好放入 iTune:
  • 先將 ape 轉成 wave
  • 將 wave 壓成 mp3
  • 依照 cue,將 mp3 split成一首一首,並且依照 cue加入 id3tag.
每個用的工具不一樣
  • ape 轉 wave -- ffmpeg
    ffmpeg -i file.ape output.wav
  • wave 轉 mp3 -- lame
    lame -h CDImage.wav CDImage.mp3
  • split and add id3tag - mp3splt
  • mp3splt -T1 -c CDImage.cue  // 使用 id3tag ver 1 -- 其實要看一下 man
就是follow 這一篇 的說明