Showing posts with label Program. Show all posts
Showing posts with label Program. Show all posts

2012-10-17

Wireshark SMGP protocol decoder (lua)

Wireshark 解析中国电信的 SMGP 协议的 lua 脚本。

-- SMGP.lua
-- SMGP protocol
-- author: h_Davy
do
 local p_SMGP = Proto("SMGP","SMGP","SMGP Protocol")
 local f_Length = ProtoField.uint32("SMGP.length","Packet Length",base.DEC)
 local f_CommandId = ProtoField.uint32("SMGP.RequestId","Request ID",base.HEX,{
  [1]="Login",      [0x80000001]="LoginResp",
  [2]="Submit",     [0x80000002]="SubmitResp",
  [3]="Deliver",    [0x80000003]="DeliverResp",
  [4]="ActiveTest", [0x80000004]="ActiveTestResp",
  [5]="Forward",    [0x80000005]="ForwardResp",
  [6]="Exit",       [0x80000006]="ExitResp",
  [7]="Query",      [0x80000007]="QueryResp"})
 local f_SequenceId = ProtoField.uint32("SMGP.sequenceId","Sequence ID",base.DEC);
 local f_ClientID = ProtoField.string("SMGP.ClientID","ClientID")
 local f_Authenticator = ProtoField.bytes("SMGP.Authenticator","Authenticator")
 local f_LoginMode = ProtoField.uint8("SMGP.LoginMode","Login Mode",base.DEC)
 local f_TimeStamp = ProtoField.uint32("SMGP.TimeStamp","TimeStamp",base.DEC)
 local f_Version = ProtoField.uint8("SMGP.Version","Version",base.HEX)
 local f_Status = ProtoField.uint32("SMGP.Status","Status",base.DEC,{[0]="OK"})
 local f_MsgType = ProtoField.uint32("SMGP.MsgType","MsgType",base.DEC,{[0]="MO",[6]="MT",[7]="P2P"})
 local f_NeedReport = ProtoField.uint32("SMGP.NeedReport","NeedReport",base.DEC,{[0]="N",[1]="Y"})
 local f_Priority = ProtoField.uint32("SMGP.Priority","Priority",base.DEC)
 local f_ServiceID = ProtoField.string("SMGP.ServiceID","ServiceID")
 local f_FeeType = ProtoField.string("SMGP.FeeType","FeeType")
 local f_FeeCode = ProtoField.string("SMGP.FeeCode","FeeCode")
 local f_FixedFee = ProtoField.string("SMGP.FixedFee","FixedFee")
 local f_MsgFormat = ProtoField.uint32("SMGP.MsgFormat","MsgFormat",base.DEC,{
  [0]="ASCII",[3]="Card",[4]="Binary",[8]="UCS2",[15]="GB18030",[246]="SIM"})
 local f_ValidTime = ProtoField.string("SMGP.ValidTime","ValidTime")
 local f_AtTime = ProtoField.string("SMGP.AtTime","AtTime")
 local f_SrcTermID = ProtoField.string("SMGP.SrcTermID","SrcTermID")
 local f_ChargeTermID = ProtoField.string("SMGP.ChargeTermID","ChargeTermID")
 local f_DestTermIDCount = ProtoField.uint32("SMGP.DestTermIDCount","DestTermIDCount",base.DEC)
 local f_DestTermID = ProtoField.string("SMGP.DestTermID","DestTermID")
 local f_MsgLength = ProtoField.uint8("SMGP.MsgLength","MsgLength",base.DEC)
 local f_MsgContent = ProtoField.string("SMGP.MsgContent","MsgContent")
 local f_MsgID = ProtoField.bytes("SMGP.MsgID","MsgID")
 local f_IsReport = ProtoField.uint8("SMGP.IsReport","IsReport",base.DEC)
 local f_RecvTime = ProtoField.string("SMGP.RecvTime","RecvTime")

 p_SMGP.fields = {f_Length,f_CommandId,f_SequenceId,f_ClientID,f_Authenticator,
 f_LoginMode,f_TimeStamp,f_Version,f_Status,f_MsgType,f_NeedReport,f_Priority,
 f_ServiceID,f_FeeType,f_FeeCode,f_FixedFee,f_MsgFormat,f_ValidTime,f_AtTime,
 f_SrcTermID,f_ChargeTermID,f_DestTermIDCount,f_DestTermID,f_MsgLength,f_MsgContent,
 f_MsgID,f_IsReport,f_RecvTime}

 local data_dis = Dissector.get("data")
 --
 local function SMGP_Login(buf,pkt,t)
  t:add(f_ClientID,buf(12,8))
  t:add(f_Authenticator,buf(20,16))
  t:add(f_LoginMode,buf(36,1))
  t:add(f_TimeStamp,buf(37,4))
  t:add(f_Version,buf(41,1))
 end
 --
 local function SMGP_LoginResp(buf,pkt,t)
  t:add(f_Status,buf(12,4))
  t:add(f_Authenticator,buf(16,16))
  t:add(f_Version,buf(32,1))
 end
 --
 local function SMGP_Submit(buf,pkt,t)
  t:add(f_MsgType,buf(12,1))
  t:add(f_NeedReport,buf(13,1))
  t:add(f_Priority,buf(14,1))
  t:add(f_ServiceID,buf(15,10))
  t:add(f_FeeType,buf(25,2))
  t:add(f_FeeCode,buf(27,6))
  t:add(f_FixedFee,buf(33,6))
  t:add(f_MsgFormat,buf(39,1))
  t:add(f_ValidTime,buf(40,17))
  t:add(f_AtTime,buf(57,17))
  t:add(f_SrcTermID,buf(74,21))
  t:add(f_ChargeTermID,buf(95,21))
  t:add(f_DestTermIDCount,buf(116,1))
  t:add(f_DestTermID,buf(117,21))
  local v_msgLen = buf(138,1)
  t:add(f_MsgLength,v_msgLen)
  v_msgLen = v_msgLen:uint()
  t:add(f_MsgContent,buf(139,v_msgLen))
 end
 --
 local function SMGP_SubDelvResp(buf,pkt,t)
  t:add(f_MsgID,buf(12,10))
  t:add(f_Status,buf(22,4))
 end
 --
 local function SMGP_Deliver(buf,pkt,t)
  t:add(f_MsgID,buf(12,10))
  local v_IsReport = buf(22,1)
  t:add(f_IsReport,v_IsReport)
  v_IsReport = v_IsReport:uint()
  t:add(f_MsgFormat,buf(23,1))
  t:add(f_RecvTime,buf(24,14))
  t:add(f_SrcTermID,buf(38,21))
  t:add(f_DestTermID,buf(59,21))
  local v_msgLen = buf(80,1)
  t:add(f_MsgLength,v_msgLen)
  v_msgLen = v_msgLen:uint()
  if v_IsReport == 1 then
   --
   t:add(f_MsgID,buf(84, 10)):append_text(' (Submit MsgID)')
   t:add(f_MsgContent,buf(94,v_msgLen-13))
  else
   t:add(f_MsgContent,buf(81,v_msgLen))
  end
 end
 --
 local function SMGP_dissector(buf,pkt,root)
  local buf_len = buf:len();
  if buf_len < 8 then return false end
  local v_length = buf(0,4)
  local v_command = buf(4,4)
  local v_sequenceId = buf(8,4)
  pkt.cols.protocol = "SMGP"
  local t = root:add(p_SMGP,buf(0,buf_len))
  t:add(f_Length,v_length)
  t:add(f_CommandId,v_command)
  t:add(f_SequenceId,v_sequenceId)
  --
  v_command = v_command:uint()
  if v_command == 1 then
   SMGP_Login(buf,pkt,t)
  elseif v_command == 2 then
   SMGP_Submit(buf,pkt,t)
  elseif v_command == 3 then
   SMGP_Deliver(buf,pkt,t)
  elseif v_command == 0x80000001 then
   SMGP_LoginResp(buf,pkt,t)
  elseif v_command == 0x80000002 then
   SMGP_SubDelvResp(buf,pkt,t)
  elseif v_command == 0x80000003 then
   SMGP_SubDelvResp(buf,pkt,t)
  elseif v_command > 0x80000000 then
   --
  else
   t:add(f_Data,buf(20,buf_len-20))
  end
  return true
 end
 --
 function p_SMGP.dissector(buf,pkt,root)
  if SMGP_dissector(buf,pkt,root) then
  else
   data_dis:call(buf,pkt,root)
  end
 end

 tcp_table = DissectorTable.get("tcp.port")
 tcp_table:add(8890,p_SMGP)
end

//EOF Read More...

Wireshark SGIP protocol decoder (lua)

Wireshark 解析中国联通的 SGIP 协议的 lua 脚本。

-- SGIP.lua
-- SGIP protocol
-- author: h_Davy
do
 local p_SGIP = Proto("SGIP","SGIP","SGIP Protocol")
 local f_Length = ProtoField.uint32("SGIP.length","Message Length",base.DEC)
 local f_CommandId = ProtoField.uint32("SGIP.commandId","Command ID",base.HEX,{[1]="Bind",[0x80000001]="BindResp",[2]="UnBind",[3]="Submit",[0x80000003]="SubmitResp",[4]="Deliver",[0x80000004]="DeliverResp",[5]="Report",[0x80000005]="ReportResp"})
 local f_SequenceId = ProtoField.uint32("SGIP.sequenceId","Sequence ID",base.DEC);
 local f_Data = ProtoField.bytes("SGIP.Data","Data")
 local f_LoginType = ProtoField.uint8("SGIP.loginType","Login Type",base.HEX)
 local f_LoginName = ProtoField.string("SGIP.loginName","Login Name")
 local f_LoginPass = ProtoField.string("SGIP.loginPass","Login Pass")
 local f_Result = ProtoField.uint8("SGIP.result","Result",base.DEC,{[0]="OK"})
 local f_Text = ProtoField.string("SGIP.text")
 local f_SPNumber = ProtoField.string("SGIP.SPNumber","SP Number")
 local f_ChargeNumber = ProtoField.string("SGIP.ChargeNumber","Charge Number")
 local f_UserCount = ProtoField.uint8("SGIP.userCount","User Count",base.DEC)
 local f_UserNumber = ProtoField.string("SGIP.UserNumber","User Number")
 local f_CorpId = ProtoField.string("SGIP.CorpId","CorpId")
 local f_ServiceType = ProtoField.string("SGIP.ServiceType","Service Type")
 local f_FeeType = ProtoField.uint8("SGIP.FeeType","Fee Type")
 local f_FeeValue = ProtoField.string("SGIP.FeeValue","Fee Value")
 local f_GivenValue = ProtoField.string("SGIP.GivenValue","Given Value")
 local f_AgentFlag = ProtoField.uint8("SGIP.AgentFlag","Agent Flag")
 local f_MorelatetoMTFlag = ProtoField.uint8("SGIP.MorelatetoMTFlag","Morelateto MT Flag")
 local f_Priority = ProtoField.uint8("SGIP.Priority","Priority")
 local f_ExpireTime = ProtoField.string("SGIP.ExpireTime","ExpireTime")
 local f_ScheduleTime = ProtoField.string("SGIP.ScheduleTime","ScheduleTime")
 local f_ReportFlag = ProtoField.uint8("SGIP.ReportFlag","ReportFlag")
 local f_TP_pid = ProtoField.uint8("SGIP.TP_pid","TP_pid")
 local f_TP_udhi = ProtoField.uint8("SGIP.TP_udhi","TP_udhi")
 local f_MessageCoding = ProtoField.uint8("SGIP.MessageCoding","MessageCoding")
 local f_MessageType = ProtoField.uint8("SGIP.MessageType","MessageType")
 local f_MessageLength = ProtoField.uint8("SGIP.MessageLength","MessageLength")
 local f_MessageContent = ProtoField.string("SGIP.MessageContent","MessageContent")
 local f_SubmitSequenceNumber = ProtoField.uint32("SGIP.SubmitSequenceNumber","SubmitSequenceNumber")
 local f_ReportType = ProtoField.uint8("SGIP.ReportType","ReportType")
 --local f_UserNumber = ProtoField.string("SGIP.UserNumber","UserNumber")
 local f_State = ProtoField.uint8("SGIP.State","State")
 local f_ErrorCode = ProtoField.uint8("SGIP.ErrorCode","ErrorCode")
 --local f_TP_udhi = ProtoField.uint8("SGIP.TP_udhi","TP_udhi")

 p_SGIP.fields = {f_Length,f_CommandId,f_SequenceId,f_Data,f_LoginType,f_LoginName
 ,f_LoginPass,f_Result,f_Text,f_UserCount,f_SPNumber,f_ChargeNumber,f_UserNumber
 ,f_CorpId,f_ServiceType,f_FeeType,f_FeeValue,f_GivenValue,f_AgentFlag,f_MorelatetoMTFlag
 ,f_Priority,f_ExpireTime,f_ScheduleTime,f_ReportFlag,f_TP_pid,f_TP_udhi,f_MessageCoding
 ,f_MessageType,f_MessageLength,f_MessageContent,f_SubmitSequenceNumber,f_ReportType
 ,f_State,f_ErrorCode}

 local data_dis = Dissector.get("data")
 --
 local function SGIP_Bind(buf,pkt,t)
  --
  t:add(f_LoginType,buf(20,1))
  t:add(f_LoginName,buf(21,16))
  t:add(f_LoginPass,buf(37,16))
 end
 --
 local function SGIP_Submit(buf,pkt,t)
  t:add(f_SPNumber,buf(20,21))
  t:add(f_ChargeNumber,buf(41,21))
  local v_UserCount = buf(62,1)
  t:add(f_UserCount,v_UserCount)
  v_UserCount = v_UserCount:uint()
  -- 目标号码
  local v_curPos = 63
  for i=1,v_UserCount do
   t:add(f_UserNumber,buf(v_curPos,21))
   v_curPos = v_curPos+21
  end
  t:add(f_CorpId,buf(v_curPos,5))
  v_curPos=v_curPos+5
  t:add(f_ServiceType,buf(v_curPos,10))
  v_curPos=v_curPos+10
  t:add(f_FeeType,buf(v_curPos,1))
  v_curPos=v_curPos+1
  t:add(f_FeeValue,buf(v_curPos,6))
  v_curPos=v_curPos+6
  t:add(f_GivenValue,buf(v_curPos,6))
  v_curPos=v_curPos+6
  t:add(f_AgentFlag,buf(v_curPos,1))
  v_curPos=v_curPos+1
  t:add(f_MorelatetoMTFlag,buf(v_curPos,1))
  v_curPos=v_curPos+1
  t:add(f_Priority,buf(v_curPos,1))
  v_curPos=v_curPos+1
  t:add(f_ExpireTime,buf(v_curPos,16))
  v_curPos=v_curPos+16
  t:add(f_ScheduleTime,buf(v_curPos,16))
  v_curPos=v_curPos+16
  t:add(f_ReportFlag,buf(v_curPos,1))
  v_curPos=v_curPos+1
  t:add(f_TP_pid,buf(v_curPos,1))
  v_curPos=v_curPos+1
  t:add(f_TP_udhi,buf(v_curPos,1))
  v_curPos=v_curPos+1
  local v_MessageCoding=buf(v_curPos,1)
  t:add(f_MessageCoding,v_MessageCoding)
  v_MessageCoding = v_MessageCoding:uint()
  v_curPos=v_curPos+1
  t:add(f_MessageType,buf(v_curPos,1))
  v_curPos=v_curPos+1
  local v_MessageLength=buf(v_curPos,4)
  t:add(f_MessageLength,v_MessageLength)
  v_MessageLength=v_MessageLength:uint()
  v_curPos=v_curPos+4
  t:add(f_MessageContent,buf(v_curPos,v_MessageLength))
 end
 --
 local function SGIP_Deliver(buf,pkt,t)
  t:add(f_UserNumber,buf(20,21))
  t:add(f_SPNumber,buf(41,21))
  t:add(f_TP_pid,buf(62,1))
  t:add(f_TP_udhi,buf(63,1))
  local v_MessageCoding=buf(64,1)
  t:add(f_MessageCoding,v_MessageCoding)
  v_MessageCoding=v_MessageCoding:uint()
  local v_MessageLength=buf(65,4)
  t:add(f_MessageLength,v_MessageLength)
  v_MessageLength=v_MessageLength:uint()
  t:add(f_MessageContent,buf(69,v_MessageLength))
 end
 --
 local function SGIP_Report(buf,pkt,t)
  --t:add(f_SubmitSequenceNumber,buf(20,12))
  t:add(f_SubmitSequenceNumber,buf(28,4))
  t:add(f_ReportType,buf(32,1))
  t:add(f_UserNumber,buf(33,21))
  t:add(f_State,buf(54,1))
  t:add(f_ErrorCode,buf(55,1))
 end
 --
 local function SGIP_Response(buf,pkt,t)
  t:add(f_Result,buf(20,1))
 end
 --
 local function SGIP_dissector(buf,pkt,root)
  local buf_len = buf:len();
  if buf_len < 8 then return false end
  local v_length = buf(0,4)
  local v_command = buf(4,4)
  local v_sequenceId = buf(16,4)
  pkt.cols.protocol = "SGIP"
  local t = root:add(p_SGIP,buf(0,buf_len))
  t:add(f_Length,v_length)
  t:add(f_CommandId,v_command)
  t:add(f_SequenceId,v_sequenceId)
  --local dt = t:add(f_Data,buf(20,buf_len-20))
  v_command = v_command:uint()
  if v_command == 1 then
   SGIP_Bind(buf,pkt,t)
  elseif v_command == 3 then
   SGIP_Submit(buf,pkt,t)
  elseif v_command == 4 then
   SGIP_Deliver(buf,pkt,t)
  elseif v_command == 5 then
   SGIP_Report(buf,pkt,t)
  elseif v_command > 0x80000000 then
   SGIP_Response(buf,pkt,t)
  else
   t:add(f_Data,buf(20,buf_len-20))
  end
  return true
 end
 function p_SGIP.dissector(buf,pkt,root)
  -- 解析 SGIP
  if SGIP_dissector(buf,pkt,root) then
  else
   -- 使用默认输出
   data_dis:call(buf,pkt,root)
  end
 end

 tcp_table = DissectorTable.get("tcp.port")
 tcp_table:add(8801,p_SGIP)
end

//EOF Read More...

Rust

Rust是由Mozilla开发的专门用来编写高性能应用程序的系统编程语言。

(2006年开始,到2012年10月还是0.4版)

Rust创建的目的是用于替换C/C++。
有更优秀的堆栈内存管理特性。
有更简明的语法特性。

http://www.rust-lang.org

//EOF Read More...

2012-02-15

PHP判断是否是移动设备

//判断是否属手机
function is_mobile() {
    $user_agent = $_SERVER['HTTP_USER_AGENT'];
    $mobile_agents = Array("240x320","acer","acoon","acs-","abacho","ahong","airness","alcatel","amoi","android","anywhereyougo.com","applewebkit/525","applewebkit/532","asus","audio","au-mic","avantogo","becker","benq","bilbo","bird","blackberry","blazer","bleu","cdm-","compal","coolpad","danger","dbtel","dopod","elaine","eric","etouch","fly ","fly_","fly-","go.web","goodaccess","gradiente","grundig","haier","hedy","hitachi","htc","huawei","hutchison","inno","ipad","ipaq","ipod","jbrowser","kddi","kgt","kwc","lenovo","lg ","lg2","lg3","lg4","lg5","lg7","lg8","lg9","lg-","lge-","lge9","longcos","maemo","mercator","meridian","micromax","midp","mini","mitsu","mmm","mmp","mobi","mot-","moto","nec-","netfront","newgen","nexian","nf-browser","nintendo","nitro","nokia","nook","novarra","obigo","palm","panasonic","pantech","philips","phone","pg-","playstation","pocket","pt-","qc-","qtek","rover","sagem","sama","samu","sanyo","samsung","sch-","scooter","sec-","sendo","sgh-","sharp","siemens","sie-","softbank","sony","spice","sprint","spv","symbian","tablet","talkabout","tcl-","teleca","telit","tianyu","tim-","toshiba","tsm","up.browser","utec","utstar","verykool","virgin","vk-","voda","voxtel","vx","wap","wellco","wig browser","wii","windows ce","wireless","xda","xde","zte");
    $is_mobile = false;
    foreach ($mobile_agents as $device) {
        if (stristr($user_agent, $device)) {
            $is_mobile = true;
            break;
        }
    }
    return $is_mobile;
}
// EOF Read More...

2012-02-09

效率,灵活,抽象,生产率

如果把我们的对编程语言的需求总结为四个:效率,灵活,抽象,生产率。那么,C语言玩的是前两个,而C++玩的是前三个,Java和C#玩的是后两个(抽象和生产率) http://www.infoq.com/cn/news/2012/02/2012-cpp-to-learn-or-not //EOF Read More...

2009-04-11

动态创建 style 节点

在 IE 中 DOM 方式创建页面内 style 节点有点问题~ (创建出来的东西是不能修改内容的)
可用 document.createStyleSheet() 来解决:

// create style node
var _styleNode = _(u.STYLE_ID);
if (!_styleNode) {
 if (/*@cc_on!@*/0) { // is IE
  var ss = document.createStyleSheet();
  ss.cssText = _defaultStyleText;
  _styleNode = ss.owningElement; // the style node just created
  _styleNode.id = u.STYLE_ID;
 } else { // other browsers
  _styleNode = document.createElement("style");
  _styleNode.id = u.STYLE_ID;
  _styleNode.type = "text/css";
  _styleNode.innerHTML = _defaultStyleText;
  var head = document.getElementsByTagName("head")[0] || document.body;
  head.appendChild(_styleNode);
 }
}

另外,对于 link 引入 css 可用:
document.createStyleSheet("style.css");
对应:
var style = document.createElement("link");
style.href = "style.css";
style.rel = "stylesheet";
style.type = "text/css";
document.getElementsByTagName('head')[0].appendChild(style);

//EOF Read More...

2009-03-31

Win32++: 在 Dialog 中使用 ListView

资源文件中有:

IDD_MAIN DIALOG 0, 0, 186, 95
...
{
  ...
  CONTROL         "", IDC_LSTMAIN, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_REPORT, 7, 7, 118, 81, WS_EX_LEFTSCROLLBAR
}
另有 Dialog :
class CMainDialog : public CDialog
{
...
private:
    CListView   m_lsvMain;
};
则,在:
BOOL CMainDialog::OnInitDialog()
{
    // 加上下面这行:
    m_lsvMain.AttachDlgItem(IDC_LSTMAIN, this);
    // 用 AttachDlgItem(UINT nID, CWnd* pParent) 将Dialog的控件附加到CListView对象。
    ...

    // 添加列
    m_lsvMain.InsertColumn(0, _T("Column 0"), LVCFMT_LEFT, 60);
    //m_lsvMain.InsertColumn(1, _T("Column 1"), LVCFMT_LEFT, 60);

    // 添加项
    m_lsvMain.InsertItem(0, _T("Item 0"));
    m_lsvMain.InsertItem(1, _T("Item 1"));
    m_lsvMain.InsertItem(2, _T("Item 2"));
    m_lsvMain.InsertItem(3, _T("Item 3"));

}

注:
另外 641 中的 InsertColumn(int iCol, LPCTSTR pszColumnHeading, int iFormat, int iWidth, int iSubItem)InsertItem(int iItem, LPCTSTR pszText) 是有 BUG 的。
将 listview.h 更新到 SVN 里面最新的 749 后正常。

//EOF Read More...

2009-03-29

Win32++ CodeBlocks templates & wizard

Win32++ is a C++ library used to build windows GUI applications.
http://sourceforge.net/projects/win32-framework/
Win32 平台上的一个轻量级的 C++ GUI开发库,可以用在 GCC 编译器中。
document:
http://users.bigpond.net.au/programming/documentation.htm

自己花了点时间做了个简陋的 CodeBlocks 的新建 Win32++ 工程的模板向导。

下载:
http://dl.getdropbox.com/u/163800/libs/cxx/Win32%2B%2B/codeblocks_templ.zip

安装步骤:
1. 解包后将 wizard 下的 win32xx 目录放到 [CodeBlocks]\share\CodeBlocks\templates\wizard\ 去。
(其中 [CodeBlocks] 表示 CodeBlocks 的安装目录)
当然也可以放到用户目录中——具体参照 CodeBlocks 的 Wiki。

2. 在 [CodeBlocks]\share\CodeBlocks\templates\wizard\ 中找到 config.script 文件,用文本编辑器打开,在 function RegisterWizards() { ... } 里面加一行:

RegisterWizard(wizProject, _T("win32xx"), _T("Win32++ Application"), _T("GUI"));

3. 这样新建工程的 GUI 分类里面就有 "Win32++ GUI Application" 的选项了,按向导一步步走就可以了。
(当然,前提是你要将 Win32++ 的库引入哦!——在“编译器选项”->"Search directories"->"Compiler"里面加入)

//EOF Read More...

2009-03-17

instance initializer

虽然用Java一段时间了,不过还是第一次听到 instance initializer (实例初始化块)
以前知道有一个 static initializer (静态初始化块)会在类加载的时候执行。
instance initializer 则是在构造函数执行过程中的某一时刻执行。见代码:


// LoadOrder.java

public class LoadOrder {
private Property _property = new Property();

{ // instance initializer
System.out.println("{ Load Block 1 }");
}

static { // static initializer
System.out.println("{ static 1 }");
}

public LoadOrder() {
System.out.println("LoadOrder()");
_property = new Property(this);
}

{
System.out.println("{ Load Block 2 }");
}

static {
System.out.println("{ static 2 }");
}

public static void main(String[] args) {
System.out.println("==== main() 1 ====");
new LoadOrder();
System.out.println("==== main() 2 ====");
new LoadOrder();
Property referee = new Property();
}
}

class Property {
public Property() {
System.out.println("Property()");
}
public Property(Object owner) {
System.out.println("Property(Object)");
}
}
// EOF

运行结果如下:

{ static 1 }
{ static 2 }
==== main() 1 ====
Property()
{ Load Block 1 }
{ Load Block 2 }
LoadOrder()
Property(Object)
==== main() 2 ====
Property()
{ Load Block 1 }
{ Load Block 2 }
LoadOrder()
Property(Object)
Property()

//EOF Read More...

2009-02-20

junit 4 使用

NOTE:
junit 4 中
1. 测试类不需要继承 TestCase,直接在方法前用 @Test 即可。
2. @BeforeClass, @AfterClass 方法需要是 public static 的。

//EOF Read More...

2009-01-31

svn portable

Apache 集成 Subversion 的Win32便携式版本。
用做个人的版本管理之用。

集成环境为:
Apache 2.2.9
PHP 5.2.6
Subversion 1.5.5

默认解压到 D:/ 下运行里面的 install.bat 就能用了。
若解压到其它地方修改 D:\svn\svn-win32-1.5.5\conf\httpd.conf 中的 ServerRoot 到正确的位置。
默认项目数据保存在 D:\svn\svn-win32-1.5.5\svn_data 中。
(注:会注册服务 Apache2.2 ,若以前安装有 Apache2.2 就会安装失败。)
运行 start.bat 启动
(注:启动HTTP服务会用 80 端口,若被占用 则启动失败,在 D:\svn\svn-win32-1.5.5\conf\httpd.conf 中修改。)
运行 uninstall.bat 卸载。


访问 http://localhost/ 可以进行简单的管理:
创建、删除 项目
创建、删除 帐号、修改帐号密码

修改帐号访问权限现在还是需要自己修改文件
D:\svn\svn-win32-1.5.5\conf\svn\authz

文件下载:svn_portable.zip

// EOF Read More...

2009-01-21

在程序中处理设备的热插拔通知

注册 WM_DEVICECHANGE 事件,但还不够。
仅注册该事件则仅仅只会收到 DBT_DEVNODES_CHANGED 通知(包括光驱的弹出、收入,网络的通断等都会触发该事件)。
所以还需要用 RegisterDeviceNotification() 注册相应的设备通知。

HDEVNOTIFY RegisterDeviceNotification(
  IN HANDLE hRecipient,  // 注册 WM_DEVICECHANGE 事件的窗口或Service句柄
  IN LPVOID NotificationFilter, // DEV_BROADCAST_DEVICEINTERFACE 结构
  IN DWORD Flags
);

BOOL UnregisterDeviceNotification(
  IN HDEVNOTIFY Handle  // RegisterDeviceNotification() 返回的那个Handle
);
在 DEV_BROADCAST_DEVICEINTERFACE 结构里有个 dbcc_classguid 为需要监听的设备 GUID。
MSDN 上说 RegisterDeviceNotification() 的 Flags 加上 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 后可以不要GUID 但我这里似乎 不能不要GUID~~ RegisterDeviceNotification() 时失败说 “Bad Data!”~ 不知道是怎么回事,也许没用对吧。

参考:
http://www.microsoft.com/whdc/Driver/tips/PnPUmNotif.mspx
http://msdn.microsoft.com/en-us/library/aa363211(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa363431(VS.85).aspx


另外,在 Linux 上的热插拔通知 可用 udev, HAL, D-BUS。

//EOF Read More...

使用 RegEnumValue 要注意的地方

LONG RegEnumValue(
  HKEY hKey,              // handle to key to query
  DWORD dwIndex,          // index of value to query
  LPTSTR lpValueName,     // address of buffer for value string
  LPDWORD lpcbValueName,  // address for size of value buffer
  LPDWORD lpReserved,     // reserved
  LPDWORD lpType,         // address of buffer for type code
  LPBYTE lpData,          // address of buffer for value data
  LPDWORD lpcbData        // address for size of data buffer
);

返回值 ERROR_NO_MORE_ITEMS,表示都枚舉完了。
dwIndex 為索引,如果是枚舉并刪除的話,就一直為0就行了。
lpcbValueName 這個是ValueNameBuffer 的大小,這個地方要注意!!每次調用前設置成buffer大小,調用后都會設置成返回的ValueName實際的長度,所以這里需要在每次調用前都設置一下,@@ 暈死~,沒注意看MSDN。
lpcbData 同上。

//EOF Read More...

2009-01-11

修改文件/資料夾的用戶訪問權限

用WinAPI:

BOOL SetFileSecurity(
  LPCTSTR lpFileName,  // address of string for filename
  SECURITY_INFORMATION SecurityInformation,
                       // type of information to set
  PSECURITY_DESCRIPTOR pSecurityDescriptor 
                       // address of security descriptor
);
如:
::SetFileSecurity(szFileName, DACL_SECURITY_INFORMATION, psd);
其中 psd 的取得見上一篇:http://dave3068.blogspot.com/2009/01/securityattributeslpsecuritydescriptor.html

另外,對上一篇的補充:
SECURITY_ATTRIBUTES 中 lpSecurityDescriptor 的使用還可以使用 API :
SetSecurityDescriptorDacl
SetSecurityDescriptorControl
等。
不過感覺一般情況下還是這個 ConvertStringSecurityDescriptorToSecurityDescriptor 方便些 :)。
要如何使用就要看具體的場合了。

//EOF Read More...

2009-01-10

SECURITY_ATTRIBUTES.lpSecurityDescriptor 的使用

在 WinAPI:CreateFile 等函數中有個 SECURITY_ATTRIBUTES 可以用來控制文件的用戶訪問權限,但一直不知道SECURITY_ATTRIBUTES結構中的lpSecurityDescriptor如何設置,今天查了一下MSDN發現可以用函數:

BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptor(
  __in   LPCTSTR StringSecurityDescriptor,
  __in   DWORD StringSDRevision,
  __out  PSECURITY_DESCRIPTOR *SecurityDescriptor,
  __out  PULONG SecurityDescriptorSize
);
來設置pSa->lpSecurityDescriptor。
要使用該函數需要引入Sddl.h 頭文件,但 VC6 里面沒有這個頭文件。
還有個方法是自己 LoadLibrary => GetProcAddress 來取得:
ConvertStringSecurityDescriptorToSecurityDescriptor 在 Windows 2000 Professional 以上的 Advapi32.dll 中。
可以用以下代碼得到:
typedef BOOL (WINAPI *FN__CSSDTSD__) (
  IN LPCTSTR,
  IN DWORD,
  OUT PSECURITY_DESCRIPTOR *,
  OUT PULONG);

FN__CSSDTSD__ ConvertStringSecurityDescriptorToSecurityDescriptor = NULL;

//   SDDL   Version   information
#define SDDL_REVISION_1  1
#define SDDL_REVISION  SDDL_REVISION_1


void _initLIBS()
{
 HMODULE hAdvapi32 = ::LoadLibrary("Advapi32");
 if (hAdvapi32)
 {
  ConvertStringSecurityDescriptorToSecurityDescriptor =
   (FN__CSSDTSD__)::GetProcAddress(
    hAdvapi32,
    "ConvertStringSecurityDescriptorToSecurityDescriptorA");
 }
}

參考:
http://msdn.microsoft.com/en-us/library/ms717798.aspx
http://msdn.microsoft.com/en-us/library/aa379570%28VS.85%29.aspx
http://msdn.microsoft.com/en-us/library/aa376401%28VS.85%29.aspx

//EOF Read More...

2008-12-31

替換Windows的Desktop時,如何獲取應用程序注冊的圖標?

今天整理硬盤的時候發現這個,放上來算了,希望對需要的人有幫助。
是以前寫的一個東西——曾經覺得 Windows 的 Desktop 太難看了,所以打算自己寫一個。其它的沒啥子主要是些 GDI+ 的操作。
中間遇到的最大問題是如何獲得應用程序對 TrayNotifyIcon 的注冊。關于這個問題曾經 debug 了 explorer.exe ,才得出以下方法:(Windows XP)

1、如何接收應用程序的注冊圖標通知:
自己實現一個Window注冊Class為"Shell_TrayWnd"(Windows界面中的控件元素都可看作Window——所以叫做 Windows 嘛~~),其下一個子窗口(控件)注冊Class為"TrayNotifyWnd"。
在注冊Class為"Shell_TrayWnd"的窗口中可處理 WM_COPYDATA 消息:
此時 lParam 為 PCOPYDATASTRUCT pcds
(pcds->dwData == 1) 時表示是一個通知消息
此時的 pcds->lpData 結構如下:
(這是我自己定義的一個結構,不知道MSDN是否有這樣的結構,反正我是沒找到,所以自定義了個)

// the struct for WM_COPYDATA to "Shell_TrayWnd"
typedef struct _NOTIFY_MSG_DATA {
 DWORD dwUnknow;  // ??? I don't know what's this ?
 DWORD dwNotifyCode; // NIM_ADD, NIM_DELETE, NIM_MODIFY, ...
 NOTIFYICONDATA nid; // 這里就是應用程序注冊圖標時的數據了
 bool operator== (const _NOTIFY_MSG_DATA& nmd) const
 {
  return nid.hWnd == nmd.nid.hWnd;
 };
} NOTIFY_MSG_DATA, *PNOTIFY_MSG_DATA;
子窗口注冊Class為"TrayNotifyWnd"主要是想和 explorer.exe 保持一致罷了,接收消息的實質上是"Shell_TrayWnd"。

另外,要注意的是:
if (pnid->uFlags & NIF_ICON) // pnid為上面的NOTIFYICONDATA的指針
{
 // Some applications destroy the icon immediately after completing the
 // NIM_ADD/MODIFY message, so we have to make a copy of it.
 if (hIcon)
  ::DestroyIcon(hIcon);
 hIcon = (HICON) ::CopyIcon(pnid->hIcon);

 bChanged = true;
}
某些程序在注冊圖標后會 destory 這個 hIcon ,所以最好是自己拷貝一份——要不然也會出現某些得到的圖標莫名其妙不見了的情況。

2、explorer.exe 出異常中途結束后重啟,得到被終結之前的圖標。
(在XP之前的Win版本中是會丟失的——失去之前注冊的程序圖標)
XP 中主要在以下注冊表項目中,以二進制方式存儲:
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify]
IconStreams 当前项目
PastIconsStream 过去的项目
存儲的數據格式如何,自己dump一下就知道了 :)


嗯……其它的就沒有什么好多說的了,基本上就是一些 GDI+ 操作了。

哦!還有就是 explorer.exe 除了桌面外,還充當文件管理器等其它的作用,所以要替換它的話除了繪制桌面還要做其它方面的準備,或者那些方面的替代品。

差不多就是這些了,以上!

//EOF Read More...

2008-12-13

DOM 还是 SAX

选择 DOM 还是选择 SAX,这取决于下面几个因素:

  • 应用程序的目的:如果打算对数据作出更改并将它输出为 XML,那么在大多数情况下,DOM 是适当的选择。并不是说使用 SAX 就不能更改数据,但是该过程要复杂得多,因为您必须对数据的一份拷贝而不是对数据本身作出更改。
  • 数据容量: 对于大型文件,SAX 是更好的选择。
  • 数据将如何使用:如果只有数据中的少量部分会被使用,那么使用 SAX 来将该部分数据提取到应用程序中可能更好。 另一方面,如果您知道自己以后会回头引用已处理过的大量信息,那么 SAX 也许不是恰当的选择。
  • 对速度的需要: SAX 实现通常要比 DOM 实现更快。
SAX 和 DOM 不是相互排斥的,记住这点很重要。您可以使用 DOM 来创建 SAX 事件流,也可以使用 SAX 来创建 DOM 树。事实上,用于创建 DOM 树的大多数解析器实际上都使用 SAX 来完成这个任务!

參考:
http://www.ibm.com/developerworks/cn/views/xml/tutorials.jsp?cv_doc_id=84979

//EOF Read More...

2008-12-10

struts 配置文件中元素的順序

今天才發現原來 struts 配置文件中元素之間的順序是有要求的。

controller 放在 message-resources 之前會報錯,雖然程序能夠正常運行,但在加載的時候會報一個“配置文件解析錯誤”。

看來順序還是不能變~

//EOF Read More...

2008-12-07

ASP.NET TreeView check childs/parents

給 ASP.NET 的 TreeView 寫了一個掛件,主要功能就是在 TreeView 是 ShowCheckBox 模式的時候,當勾選某個節點時能自動的勾選這個節點相關的所有父節點,以及勾選、反勾選這個節點的所有子節點。

功能很簡單純 javascript 實現:

/*************************************************************************
 * change the tree view node's child nodes check-state, when check
 * this node.
 *
 *   NOTE: for ASP.NET TreeView
 *
 * @author h_Davy
 * @version 2008-12-5
 *************************************************************************/

/**
 * check the tree node's childs with this checkbox's stats
 *
 * @param chk   the check box element
 *
 * @private
 */
function _checkTreeChilds(chk)
{
    var childId = chk.id.replace('CheckBox', 'Nodes');
    var child = document.getElementById(childId);
    if (child) {
        var chks = child.getElementsByTagName('input');
        for (var i in chks) {
            if (chks[i].type == "checkbox") {
                chks[i].checked = chk.checked;
            }
        }
    }
}

/**
 * find out the checkbox-node's parent node's checkbox id
 *
 * @param chk       the check box element
 * @param treeView  the treeView element
 *
 * @return  the parent node checkbox id
 *
 * @private
 */
function _findTreeParentId(chk, treeView)
{
    if (!chk) return null;
    var tmpElm = chk.parentNode;
    for(;;) {
        if (tmpElm.tagName == "TABLE") {
            return tmpElm.parentNode.id.replace('Nodes', 'CheckBox');
        } else {
        // go up to find out the parent node, until touch the treeview
            tmpElm = tmpElm.parentNode;
            if (tmpElm == treeView) return null;
        }
    }
    return null;
}

/**
 * check the tree node's parent w this checkbox is checked
 *
 * @param chk   the check box element
 * @param treeView  the treeView element
 *
 * @private
 */
function _checkTreeParent(chk, treeView)
{
    if (!chk.checked) return;
    var tmpChk;
    var parentId = _findTreeParentId(chk);
    for(;;) {
        if (!parentId) return;
        if (chk.checked) {
            tmpChk = document.getElementById(parentId);
            if (!tmpChk || tmpChk == treeView) return;
            tmpChk.checked = true;
        }
        parentId = _findTreeParentId(tmpChk, treeView);
    }
}

/**
 * use this bind to a tree view
 *
 * @param id    the tree view's id (NOTE: it's the HTML node id, not .NET page server id)
 */
function bindCheckEvent(id) {
    var treeView = document.getElementById(id);
    var chks = treeView.getElementsByTagName('input');
    for(var i in chks) {
        if (chks[i].type == "checkbox") {
            chks[i].onclick = function() {
                _checkTreeChilds(this);
                _checkTreeParent(this, treeView);
            };
        }
    }
}

// -- EOF --

使用方法,在要使用的頁面導入以上代碼后,在頁面結尾處加上:
<script type="text/javascript">

bindCheckEvent('TreeView1');
// 這里的 'TreeView1' 就是那個TreeView的ID
// !!!注意:這里的ID指的是最終生成的HTML頁面中的ID,
//                 如果你的TreeView是在某個使用了模板頁的內容頁里面的話,
//                 就有可能是 'ctl00_ContentPlaceHolder1_TreeView1' 了。

</script>

//EOF Read More...

2008-11-30

Linux 中使用NetBeans部署、运行Web应用要注意目录权限设置

使用的是 tomcat
要注意以下几个目录的权限要当前用户可写

$CATALINA_HOME/conf/Catalina/localhost/
$CATALINA_HOME/webapps/
$CATALINA_HOME/work/Catalina/localhost/
$CATALINA_HOME/temp/

否则,有可能会出现无法写入部署目录而部署失败:

Failed to deploy application at context path /xxx

另外,还要注意
$CATALINA_HOME/bin/
下几个.sh文件的当前用户执行权限,不然tomcat都无法运行。

//EOF Read More...