2008年8月20日星期三

【转】几个可以让博客(圈子)人气急升的方法

玩了163BLOG几个月.

由本来的一个人都没来现在一天来几百.

多多少少有点心得.

整天有人问我我干嘛那么高人气.

我也不卖关子了.

说几条可以让自己BK人气急升的方法:

人际篇:

1.拉帮结派篇

尽量快的时间内去别人BLOG踩点.结交认识些和自己志同道合聊得来的朋友.然后强逼别人到你BLOG上留言

2.流氓篇

谁进你的BK不留言就到他那强逼他回来留言聊天.逼着逼着人家就习惯了``不上你那就不舒服了.

以上两点都是某人增加人气的方法```是谁我就不说了``哈哈

3.冒名顶替

把网上的美女帅哥相片帖去你自己BLOG上.然后说你就是那个人.那肯定色狼就会登门而上.

4.广告篇

到多人的圈子里狂刷讨论区.让地球人都知道你的存在.或在讨论区里面发一张帖`然后回复1-200张回复.那么你的帖子就会出现在163圈子首页.那么你的连接就出现在圈子首页了

5.色BLOG篇

把自己BK弄成SEX网站``加晒D咸湿图片上去.让色狼都上你那看.注意:只要把照片名字写成人体艺术.哪都不会封你BK```当然``不推荐这样做

6.经营篇

自己开一个圈子.经营好一点``那么BLOG友就会常常来看你的了

搜索篇:

BLOG的标签全加热点搜索的标签.转帖几篇比较多人找的文章.然后让搜索引擎收录你的BK.那么搜索来的人气也会增加.

说了这么多,怎么将你的博客提交给搜索引擎啊?下面提供你们一些搜索引擎的提交地址:
有道搜索:http://tellbot.yodao.com/report?type=web
百度:http://www.baidu.com/search/url_submit.html
GOOGLE:http://www.google.com/intl/zh-CN/add_url.html
搜狗:http://db.sohu.com/regurl/regform.asp
TOM:http://search.tom.com/tools/weblog/log.php
中搜:http://d.zhongsou.com/NetSearch/pageurlrecord/frontpageurl.jsp
爱问:http://www.iask.com/guest/add_url.php
一搜: http://www.yisou.com/search_submit.html?source=yisou_www_hp
ALEXA:http://pages.alexa.com/help/webmasters/index.html#crawl_site
有道博客搜索:http://tellbot.yodao.com/report?type=BLOG
百度博客搜索:http://utility.baidu.com/blogsearch/submit.php
GOOGLE BLOGSearch:http://blogsearch.google.com/ping?hl=zh-CN
  以上搜索基本包含了比较有名的搜索,但根据本人的经验,一般访问的人都是通过百度、google搜索到你的博客的,小强提醒而已。下面就赶紧行动吧,让你的博客装上引擎吧!

网站篇:

找专门收录博客的网站.让他们收录你的博客.为你带来人气

收录网站:

http://www.blogall.com.cn/

http://www.souyo.com/

http://so.blogchinese.com/

http://blog.lalec.com/index.asp

http://www.blogrank.cn/submit.asp

集成篇:

1.博客中的文章要精彩。
2.博客标题要新颖。
3.背景要丰富。
4.音乐要优美。
5.要多引导一些人去你的博客参观,然后让他们再引导别人来参观。

软件篇:

软件分为自己的人气和别人给自己的人气.

自己给自己作的人气``很简单``自己开刷.

自己开刷也不是那么简单的事情.别以为1秒开100个网页人家的确会给你一百个浏览量.绝不.

我现今找到的有效刷网工具只有一个了.

下载地址:http://www.rt-520.cn/bbs/thread-5824-1-4.html

另一个软件是别人给你的人气.

自己登录博客后,浏览别人的博客就会留下自己的头像,呵呵,而该博客的主人或来访问这个博客的客人,看到您精心设计的头像,就会回访您的博客,于是 人气因此而涨涨涨……使用《网易博客漫游专家标准版》软件,轻松漫游千万网易博客,只要有1/100的回访率,您的人气就高达10万以上,而这都是软件在 自动行动……您只需要充实您的博客,展示您最精彩的一页……想拥有一个超高人气的博客吗?那么还等什么,下载软件

http://hao500.net/download9/92464.htm

以上两点方法``第一个不推荐.第二个要是你想猛增人气的.可以购买正式版

至于你怎么选择``由你而定了``

2008年8月15日星期五

wince5.0系统时间、音量及背光、触摸屏校正以及进程查看大集合

参考了Norains写的一些东西。然后参考了网上一些大侠们写的东西。总结了一个比较零碎的东西。整个程序由三部分。进程查看器,系统时间修改器,音量及背光修改器。
进程查看器主要是查看当前运行的EXE文件。
同时有触摸校验按钮进入系统触摸屏校验界面。
系统时间修改按钮导出系统时间修改器
音量修改按钮导出音量修改,背光修改界面。
=====================================================================
进程查看可以参考付林林写的东西。不过我现在还是不知道如何产看EXE所调用了的DLL。这个还得研究。
=====================================================================
先介绍如何调用WINCE5.0系统的触摸校验
1.引用
#include
pwinuser.h主要是这个文件。每个人路进不一样可能位置不一样。只要找到这个文件的位置引用就好了
2. TouchCalibrate();//在按钮里调用这个函数。触摸矫正就出来了。。。汗。。很简单。
======================================================================
再次是介绍如何调用外部EXE。
1.这个使用的原因是因为音量控制,时间控制我都做成外部的小程序模块,发现一个很严重的问题就是如果做成子窗体的话如果修改音量还好,修改时间会报系统内存溢出之类的致命错误。所以还是做了外部小程序。
2.用的函数如下:
CreateProcess( szMapPath, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,NULL )
这里要重点说一下。。。。
http://msdn.microsoft.com/en-us/library/ms682425.aspx这个是对的。但是参考范围是2000,XP系统。MSDN上的例子不是WINCE下的。第二个参数是路径,而WINCE下的是第一个参数是路进。这个地方以前研究了很久才发现。这个地方一定要小心
szMapPath这个是你的外部程序路径了。
还有。。。wince下的路径都是用“\\”的哦。。。。
=====================================================================
接下来是系统时间修改器
1.一共六个输入控件,年月日时分秒。
2.6个微调控件,Spin控件
3.初始化的时候定好初始设定和微调设定:
//设置 年 微调按钮
CSpinButtonCtrl *pYEAR = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN1);

ASSERT(pYEAR!=NULL);
//设置伙伴窗口
//int str=2007;

pYEAR->SetBuddy(GetDlgItem(IDC_YEAR));

pYEAR->SetRange(2008,2099);

pYEAR->SetPos(2008);

m_CYear.SetWindowText(_T("2008"));


//设置 月 微调按钮
CSpinButtonCtrl *pMONTH = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN2);

ASSERT(pMONTH!=NULL);

//设置伙伴窗口

pMONTH->SetBuddy(GetDlgItem(IDC_MONTH));

pMONTH->SetRange(1,12);

pMONTH->SetPos(1);

m_CMonth.SetWindowText(_T("8"));


//设置 日 微调按钮
CSpinButtonCtrl *pDAY = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN3);

ASSERT(pDAY!=NULL);
//设置伙伴窗口
pDAY->SetBuddy(GetDlgItem(IDC_DAY));

pDAY->SetRange(1,31);

pDAY->SetPos(1);

m_CDay.SetWindowText(_T("8"));

//设置 小时 微调按钮
CSpinButtonCtrl *pHOUR = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN4);

ASSERT(pHOUR!=NULL);
//设置伙伴窗口
//int str=2007;
pHOUR->SetBuddy(GetDlgItem(IDC_HOUR));

pHOUR->SetRange(0,23);

pHOUR->SetPos(12);

m_CHour.SetWindowText(_T("8"));

//设置 分钟 微调按钮
CSpinButtonCtrl *pMINUTE = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN5);

ASSERT(pMINUTE!=NULL);
//设置伙伴窗口

pMINUTE->SetBuddy(GetDlgItem(IDC_MINUTE));

pMINUTE->SetRange(0,59);

pMINUTE->SetPos(0);

m_CMinute.SetWindowText(_T("8"));

//设置 秒 微调按钮
CSpinButtonCtrl *pSECOND = (CSpinButtonCtrl*)GetDlgItem(IDC_SPIN6);

ASSERT(pSECOND!=NULL);

//设置伙伴窗口

pSECOND->SetBuddy(GetDlgItem(IDC_SECOND));

pSECOND->SetRange(0,59);

pSECOND->SetPos(0);

m_CSecond.SetWindowText(_T("8"));

4.设定时间
UpdateData(TRUE);

SYSTEMTIME sysTime;

sysTime.wYear =m_Year;

sysTime.wMonth =m_Month;

sysTime.wDay = m_Day;

sysTime.wHour =m_Hour;

sysTime.wMinute =m_Minute;

sysTime.wSecond =m_Second;

SetLocalTime(&sysTime);

UpdateData(FALSE);

5.完成
////////////////////////////////////////////////////////////////////////////////////////
接下来是音量控制,背光控制,任务栏隐藏,
1.隐藏任务栏,先定义一个全局变量控制。

CWnd * hwndTaskBar = FindWindow(TEXT("HHTaskBar"), NULL);
//获取wince任务栏句柄
if (m_HideTaskBar == FALSE)

{

if(hwndTaskBar)

{

hwndTaskBar->EnableWindow(FALSE);
//窗体失效
hwndTaskBar->ShowWindow(SW_HIDE);
//窗体隐藏
m_HideTaskBar = TRUE;

}

}
else

{

if(hwndTaskBar)

{

hwndTaskBar->EnableWindow(TRUE);
//窗体有效
hwndTaskBar->ShowWindow(SW_SHOW);
//窗体显示
m_HideTaskBar = FALSE;

}

}

2.控制屏幕点击音。这个有点麻烦,同样设定一个全局变量控制下。
//点击屏幕声 Screen 0:无声 1:柔和 65538:洪亮
HKEY m_hKey;

LPCTSTR Screen=_T("Screen");

LPCTSTR son_Key=_T("ControlPanel\\Volume\\");

DWORD ScreenNumber = 0;

DWORD ReturnValue=RegOpenKeyEx(HKEY_CURRENT_USER,son_Key,0,0,&m_hKey);
//写注册表修改按键音
if (FALSE == m_ScreenClick)

{

if(ReturnValue==ERROR_SUCCESS)

{

DWORD SetValue=RegSetValueEx(m_hKey,Screen,0,REG_DWORD,(LPBYTE)&ScreenNumber,sizeof(DWORD));
//送按键音值,使按键音失效
}

RegCloseKey(m_hKey);

Apply();

m_ScreenClick = TRUE;

}

else

{

if(ReturnValue==ERROR_SUCCESS)

{

DWORD ScreenNumber = 1;


DWORD SetValue=RegSetValueEx(m_hKey,Screen,0,REG_DWORD,(LPBYTE)&ScreenNumber,sizeof(DWORD));
//送按键音值,使按键音有效
}

RegCloseKey(m_hKey);

Apply();

m_ScreenClick = FALSE;

}
以前参考Norains的修改注册表类。其实有点麻烦。直接用RegSetValueEx去修改还更直接。CReg类也是调用了这个东西。而且要区分DWORD和STRING型。在这两个类新上我也话了不少时间。不同的类型控制效果是不一样的。如果串了类新可能会失效。就是REG_DWORD这个东西。
======================================================================
3.音量控制。这个同样是修改注册表。两个按钮。+/-,加减的步进值都是0x33333333。
if (m_vol != 0x0)

{

m_vol = m_vol - 0x33333333;

}

//SetVolume(m_vol);

waveOutSetVolume(0,m_vol);

m_volshow = m_vol;

this->UpdateData(FALSE);
减法
if (m_vol != 0xFFFFFFFF)

{

m_vol = m_vol + 0x33333333;

}

//SetVolume(m_vol);

m_volshow = m_vol;

waveOutSetVolume(0,m_vol);

this->UpdateData(FALSE);
加法

这里有个问题是忘记了获取系统当前音量。这个大家自己加下。就是要获取下注册表里当前音量的值赋值给m_vol就好了
====================================================================
背光设置。这里要用到修改注册表和用背光流驱动两个方向去修改
1.代码如下:
HKEY hKey;

DWORD dwType=0;

DWORD dwState=Lumin;

hStr = CreateFile(_T("BKL1:"),GENERIC_READ| GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,NULL,NULL);
//读取底层驱动,通过底层驱动用流式文件形式修改背光
if (DeviceIoControl(hStr,IOCTL_BACKLIGHT_GET,NULL,NULL,&Lumin,sizeof(Lumin),NULL,NULL))

{

++Lumin;

// ::AfxMessageBox(Lumin);

}

if((Lumin>0)&&(Lumin<6))

{

if (DeviceIoControl(hStr,IOCTL_BACKLIGHT_SET,&Lumin,sizeof(Lumin),NULL,0,NULL,NULL))
{

// ::AfxMessageBox(_T("set ok!"));

}


if(ERROR_SUCCESS==RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("ControlPanel\\Backlight\\"),0,0,&hKey))
{


RegSetValueEx(hKey, TEXT("BacklightCurrentLevel"),0,REG_DWORD,(BYTE*)&dwState,sizeof(DWORD));

}

Apply();

HANDLE hBL=CreateEvent(NULL,FALSE,FALSE,TEXT("BackLightChangeEvent"));

if(hBL)

{

SetEvent(hBL);

CloseHandle(hBL);

}

RegCloseKey(hKey);

}
加背光

HKEY hKey;

DWORD dwType=0;

DWORD dwState=Lumin;

hStr = CreateFile(_T("BKL1:"),GENERIC_READ| GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,NULL,NULL);
//读取底层驱动,通过底层驱动用流式文件形式修改背光
if (DeviceIoControl(hStr,IOCTL_BACKLIGHT_GET,NULL,0,&Lumin,sizeof(Lumin),NULL,NULL))

{

--Lumin;
// ::AfxMessageBox(Lumin);

}

if((Lumin>0)&&(Lumin<6))

{

if (DeviceIoControl(hStr,IOCTL_BACKLIGHT_SET,&Lumin,sizeof(Lumin),NULL,0,NULL,NULL))

{

// ::AfxMessageBox(_T("set ok!"));

}


if(ERROR_SUCCESS==RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("ControlPanel\\Backlight\\"),0,0,&hKey))

{

RegSetValueEx(hKey, TEXT("BacklightCurrentLevel"),0,REG_DWORD,(BYTE*)&Lumin,sizeof(DWORD));

}

Apply();

HANDLE hBL=CreateEvent(NULL,FALSE,FALSE,TEXT("BackLightChangeEvent"));

if(hBL)

{

SetEvent(hBL);

CloseHandle(hBL);

}


RegCloseKey(hKey);

}
减背光
BKL1这个可以按照你的自己注册的BKL来定。
===================================================================
以上就是这整个程序组的参考代码希望给大家有所帮助
xumercury@gmail.com

【转帖By:Norains】CReg类轻松读取注册表收藏

//========================================================================
//TITLE:
// CReg类轻松读取注册表
//AUTHOR:
// norains
//DATE:
// Sunday 8-April-2007
//Environment:
// EVC4.0 + Standard SDK
//========================================================================

开篇之处先说说这个类的来历.准确的说,这个类是我垂诞已久的东东,昨天在查看微软的控制面板的代码时,不小心发现的.觉得使用上挺便利的,所以本着"洋为中用"的原则,拷贝出来用吧!

/**//////////////////////////////////////////////////////////////////////
// Reg.h: interface for the CReg class.
//
//Version:
// 1.0.0
//Date:
// 2007.04.07
/**///////////////////////////////////////////////////////////////////////

#ifndef REG_H
#define REG_H



class CReg
...{
public:
BOOL DeleteKey(LPCTSTR szName);
BOOL DeleteValue(LPCTSTR szName);
BOOL SetMultiSZ(LPCTSTR szName, LPCTSTR lpszValue, DWORD dwLen);
BOOL SetBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen);
BOOL SetDW(LPCTSTR szName, DWORD dwValue);
BOOL SetSZ(LPCTSTR szName, LPCTSTR szValue);
BOOL SetSZ(LPCTSTR szName, LPCTSTR szValue, DWORD dwLen);
DWORD GetValueDW(LPCTSTR szName, DWORD dwDefault=0);
LPCTSTR GetValueSZ(LPCTSTR szName);
LPBYTE GetValueBinary(LPCTSTR szName);
DWORD GetValueBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen);
BOOL GetValueSZ(LPCTSTR szName, LPTSTR szValue, DWORD dwLen);
BOOL EnumValue(LPTSTR pszName, DWORD dwLenName, LPTSTR pszValue, DWORD dwLenValue);
BOOL EnumKey(LPTSTR psz, DWORD dwLen);
BOOL IsOK();
operator HKEY();
void Reset();
CReg(HKEY hkRoot, LPCTSTR pszKey);
BOOL Open(HKEY hkRoot, LPCTSTR pszKey, REGSAM sam=KEY_READ);
BOOL Create(HKEY hkRoot, LPCTSTR pszKey);
CReg();
virtual ~CReg();

private:
HKEY m_hKey;
int m_Index;
LPBYTE m_lpbValue; // last value read, if any
};

#endif //#ifndef REG_H



/**///////////////////////////////////////////////////////////////////////
// Reg.cpp: implementation of the CReg class.
//
/**///////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Reg.h"


//=======================================================================
//Macro define
#define MyFree(p) { if(p) LocalFree(p); }
//=======================================================================
/**///////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**///////////////////////////////////////////////////////////////////////

CReg::CReg()
...{
m_hKey = NULL;
m_Index = 0;
m_lpbValue = NULL;
}

CReg::CReg(HKEY hkRoot, LPCTSTR pszKey)
...{
m_hKey = NULL;
m_Index = 0;
m_lpbValue = NULL;
Open(hkRoot, pszKey);
}


CReg::~CReg()
...{
if(m_hKey)
...{
RegCloseKey(m_hKey);
}
MyFree(m_lpbValue);
}


//-------------------------------------------------------------------
//Description:
// Create the key
//-------------------------------------------------------------------
BOOL CReg::Create(HKEY hkRoot, LPCTSTR pszKey)
...{
DWORD dwDisp;
return ERROR_SUCCESS == RegCreateKeyEx(hkRoot, pszKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &m_hKey, &dwDisp);
}


//-------------------------------------------------------------------
//Description:
// Open the key
//-------------------------------------------------------------------
BOOL CReg::Open(HKEY hkRoot, LPCTSTR pszKey, REGSAM sam)
...{
return ERROR_SUCCESS == RegOpenKeyEx(hkRoot, pszKey, 0, sam, &m_hKey);
}

//-------------------------------------------------------------------
//Description:
// Reset the value
//-------------------------------------------------------------------
void CReg::Reset()
...{
if(m_hKey)
...{
RegCloseKey(m_hKey);
}
MyFree(m_lpbValue);
m_hKey = NULL;
m_Index = 0;
m_lpbValue = NULL;
}

//-------------------------------------------------------------------
//Description:
// Operator overload
//-------------------------------------------------------------------
CReg::operator HKEY()
...{
return m_hKey;
}

//-------------------------------------------------------------------
//Description:
// Test whether is the handle of the key OK for next operate
//-------------------------------------------------------------------
BOOL CReg::IsOK()
...{
return m_hKey != NULL;
}


//-------------------------------------------------------------------
//Description:
// Enum the key
//-------------------------------------------------------------------
BOOL CReg::EnumKey(LPTSTR psz, DWORD dwLen)
...{
if(!m_hKey)
...{
return FALSE;
}

return ERROR_SUCCESS == RegEnumKeyEx(m_hKey, m_Index++, psz, &dwLen, NULL, NULL, NULL, NULL);
}


//-------------------------------------------------------------------
//Description:
// Enum registry Value
//-------------------------------------------------------------------
BOOL CReg::EnumValue(LPTSTR pszName, DWORD dwLenName, LPTSTR pszValue, DWORD dwLenValue)
...{
DWORD dwType;

if(!m_hKey)
...{
return FALSE;
}

dwLenValue *= sizeof(TCHAR); // convert length in chars to bytes

return ERROR_SUCCESS == RegEnumValue(m_hKey, m_Index++, pszName, &dwLenName, NULL, &dwType, (LPBYTE)pszValue, &dwLenValue);
}


//-------------------------------------------------------------------
//Description:
// Get the string value
//-------------------------------------------------------------------
BOOL CReg::GetValueSZ(LPCTSTR szName, LPTSTR szValue, DWORD dwLen)
...{
if(!m_hKey)
...{
return FALSE;
}

dwLen *= sizeof(TCHAR); // convert length in chars to bytes

return ERROR_SUCCESS == RegQueryValueEx(m_hKey, szName, NULL, NULL, (LPBYTE)szValue, &dwLen);
}

//-------------------------------------------------------------------
//Description:
// Get the binary value
//-------------------------------------------------------------------
DWORD CReg::GetValueBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen)
...{
if(!m_hKey)
...{
return FALSE;
}

DWORD dwLenWant = dwLen;
if(ERROR_SUCCESS == RegQueryValueEx(m_hKey, szName, NULL, NULL, lpbValue, &dwLen))
...{
return dwLen;
}
else
...{
return 0;
}
}


//-------------------------------------------------------------------
//Description:
// Get the binary value
//-------------------------------------------------------------------
LPBYTE CReg::GetValueBinary(LPCTSTR szName)
...{
return (LPBYTE)GetValueSZ(szName);
}


//-------------------------------------------------------------------
//Description:
// Get the string value
//-------------------------------------------------------------------
LPCTSTR CReg::GetValueSZ(LPCTSTR szName)
...{
return 0;
}


//-------------------------------------------------------------------
//Description:
// Get the DWORD value
//
//Parameters:
// szName:[in] The value of registry
// dwDefault:[in] The default value return when failed in getting the
//DWORD value.
//-------------------------------------------------------------------
DWORD CReg::GetValueDW(LPCTSTR szName, DWORD dwDefault)
...{
if(!m_hKey)
...{
return FALSE;
}
DWORD dwValue = dwDefault;
DWORD dwLen = sizeof(DWORD);
RegQueryValueEx(m_hKey, szName, NULL, NULL, (LPBYTE)&dwValue, &dwLen);
return dwValue;
}


//-------------------------------------------------------------------
//Description:
// Set the string value
//-------------------------------------------------------------------
BOOL CReg::SetSZ(LPCTSTR szName, LPCTSTR szValue, DWORD dwLen)
...{
//Prefix
if(!m_hKey)
...{
return FALSE;
}

return ERROR_SUCCESS == RegSetValueEx(m_hKey, szName, 0, REG_SZ, (LPBYTE)szValue, sizeof(TCHAR)*dwLen);
}


//-------------------------------------------------------------------
//Description:
// Set the string value
//-------------------------------------------------------------------
BOOL CReg::SetSZ(LPCTSTR szName, LPCTSTR szValue)
...{
return SetSZ(szName, szValue, 1+lstrlen(szValue));
}


//-------------------------------------------------------------------
//Description:
// Get the DWORD value
//-------------------------------------------------------------------
BOOL CReg::SetDW(LPCTSTR szName, DWORD dwValue)
...{
//Prefix
if(!m_hKey)
...{
return FALSE;
}

return ERROR_SUCCESS==RegSetValueEx(m_hKey, szName, 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
}


//-------------------------------------------------------------------
//Description:
// Get the binary value
//-------------------------------------------------------------------
BOOL CReg::SetBinary(LPCTSTR szName, LPBYTE lpbValue, DWORD dwLen)
...{
//Prefix
if(!m_hKey)
...{
return FALSE;
}

return ERROR_SUCCESS == RegSetValueEx(m_hKey, szName, 0, REG_BINARY, lpbValue, dwLen);
}


//-------------------------------------------------------------------
//Description:
// Set the Multi value
//-------------------------------------------------------------------
BOOL CReg::SetMultiSZ(LPCTSTR szName, LPCTSTR lpszValue, DWORD dwLen)
...{
return ERROR_SUCCESS == RegSetValueEx(m_hKey, szName, 0, REG_MULTI_SZ, (LPBYTE)lpszValue, sizeof(TCHAR)*dwLen);
}


//-------------------------------------------------------------------
//Description:
// Delete the value
//-------------------------------------------------------------------
BOOL CReg::DeleteValue(LPCTSTR szName)
...{
//Prefix
if(!m_hKey)
...{
return FALSE;
}
//
return ERROR_SUCCESS == RegDeleteValue(m_hKey, szName);
}



//-------------------------------------------------------------------
//Description:
// Delete Key
//-------------------------------------------------------------------
BOOL CReg::DeleteKey(LPCTSTR szName)
...{
if(!m_hKey)
...{
return FALSE;
}

return ERROR_SUCCESS == RegDeleteKey(m_hKey, szName);
}


使用CReg类读取注册表非常方便,至少不用再去翻查platform builder文档上的注册表函数了^_^.

以将注册表中"HKEY_CURRENT_USER\ControlPanel\Volume"的"Screen"(DWORD类型)数值设置为2作例子:
CReg reg(HKEY_CURRENT_USER,TEXT("ControlPanel\Volume"));
reg.SetDW(TEXT("Screen"),Screen);

要读取也挺简单:
DWORD dwValue = reg.GetValueDW(TEXT("Screen"));

其它函数的功能,可以依照函数名推断,并且使用方法也很简单,在此不再赘述.

需要注意的是,这些代码是直接从微软代码集中拷贝过来的,原代码GetValueBinary(LPCTSTR szName)和GetValueSZ(LPCTSTR szName)的功能尚未完成.最近因为工作关系,在发表这篇豆腐块前,也没将这两个函数补完.如果各位朋友有兴趣,可以自行将之补全.当然,如果补全后 能给我发封e-mail,我会表示最衷心的感激:-)

【转帖by:norains】WinCE系统音量的设置收藏

//========================================================================
//TITLE:
// WinCE系统音量的设置
//AUTHOR:
// norains
//DATE:
// Sunday 8-April-2007
//Environment:
// EVC4.0 + Standard SDK 4.2
// EVC4.0 + Standard SDK 5.0
//========================================================================

首先我们来看一段最简单的改变音量的代码:
DWORD dwVolume = 0xAAAAAAAA;
waveOutSetVolume(0,dwVolume);


waveOutSetVolume()的第一个参数是设备ID,因为需要更改的是整个系统音量,所以在这里直接取0值即可;第二个参数是需要设置的音量数值,范围是从 0x0 ~ 0xFFFFFFFF.

但这个函数的功能却也是非常有限的,也就是说,它只能更改系统的主音量;如果想修改屏幕点击声,则就无能为力.

有些细心的朋友会从"控制面板"的"声音"入手,发现每次在控制面板调节声音,相应的"ControlPanel\Volume"下的键值数值都会变更.但如果是直接修其下的改注册表,却是无论如何都达不到相应的功能的----因为没有通知系统,注册表已经被修改.

如果需要告知系统,注册表已经修改,并请系统依照修改的数值来更改音量,则需要调用微软一个未公开的函数:AudioUpdateFromRegistry().

这个函数在文档中是无法搜索到,如果需要调用这个函数,可以有两种方法.

一是直接包含"pwinuser.h"文件,然后直接调用.

二是调用coredll.dll库,引出该函数并使用.

这里展示一个调用的例子:
typedef void (WINAPI *DLL_AUDIOUPDATEFROMREGISTRY)();

DLL_AUDIOUPDATEFROMREGISTRY Dll_AudioUpdateFromRegistry = NULL;
HINSTANCE hCoreDll = LoadLibrary(TEXT("coredll.dll"));
if (hCoreDll)
...{
Dll_AudioUpdateFromRegistry = (DLL_AUDIOUPDATEFROMREGISTRY)GetProcAddress(hCoreDll, _T("AudioUpdateFromRegistry"));
if (Dll_AudioUpdateFromRegistry)
...{
(Dll_AudioUpdateFromRegistry)();
}

只要更新了注册表,然后调用该函数,则系统会根据键值来进行相应的调整.

那么现在让我们来看看位于"ControlPanel\Volume"注册表中各键值的意义:

Volume: 系统的主音量,范围是0x0 ~ 0xFFFFFFFF.

Screen: 屏幕敲击声. 当数值为0时即为无声,1为柔和,65538为洪亮

Key: 键盘敲击声,数值的意义和Screen相同.

Mute: 控制其它静音的选项. 置0x04位为1时允许事件声音,0x02允许应用程序声音,0x01允许警告声.需要注意的是,如果不允许应用程序声音,则警告声位也将被忽略.


如果每次更改音量都要改写注册表,调用动态链接库,会显得比较麻烦.为了写代码的便利,在此封装了这个声音的操作:
(注:CReg 请参见此篇文章:http://blog.csdn.net/norains/archive/2007/04/08/1556296.aspx)

/**///////////////////////////////////////////////////////////////////////
// SysVolume.h: interface for the CSysVolume class.
//
//Version:
// 1.0.0
//Date:
// 2007.04.08
/**///////////////////////////////////////////////////////////////////////

#ifndef SYSVOLUME_H
#define SYSVOLUME_H



#include "Reg.h"

//-------------------------------------------------------------------------
//Macro define
#define MIN_VOLUME 0
#define MAX_VOLUME 0xFFFFFFFF
//-------------------------------------------------------------------------
//Enum value
enum VolumeModeType
...{
VOL_SOFT,
VOL_LOUD,
VOL_MUTE
};
//------------------------------------------------------------------------

class CSysVolume
...{
public:
BOOL SetVolumeScreenTap(VolumeModeType volMode);
BOOL SetVolumeKeyClick(VolumeModeType volMode);
BOOL EnableSoundNotification(BOOL bEnable);
BOOL EnableSoundApplication(BOOL bEnable);
BOOL EnableSoundEvent(BOOL bEnable);
BOOL SetVolume(DWORD dwVol);
CSysVolume();
virtual ~CSysVolume();

protected:
BOOL Apply();
CReg m_Reg;
};

#endif //#ifndef SYSVOLUME_H


/**///////////////////////////////////////////////////////////////////////
// SysVolume.cpp: implementation of the CSysVolume class.
//
/**///////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SysVolume.h"


//======================================================================
//Macro define

//Registry KEY
#define BASE_KEY HKEY_CURRENT_USER
#define SUB_KEY TEXT("ControlPanel\Volume")
#define VALUE_VOLUME TEXT("Volume")
#define VALUE_SCREEN TEXT("Screen")
#define VALUE_KEY TEXT("key")
#define VALUE_MUTE TEXT("Mute")


//For the screen tap and the key click
#define VOL_VALUE_MUTE 0
#define VOL_VALUE_LOUD 65538
#define VOL_VALUE_SOFT 1


//The bit for sound
#define BIT_EVENT 0x4
#define BIT_APPLICATION 0x2
#define BIT_NOTIFICATION 0x1
//======================================================================
/**///////////////////////////////////////////////////////////////////////
// Construction/Destruction
/**///////////////////////////////////////////////////////////////////////

CSysVolume::CSysVolume()
...{
m_Reg.Create(BASE_KEY, SUB_KEY);
}

CSysVolume::~CSysVolume()
...{

}





//---------------------------------------------------------------------
//Description:
// Apply the volume
//---------------------------------------------------------------------
BOOL CSysVolume::Apply()
...{
typedef void (WINAPI *DLL_AUDIOUPDATEFROMREGISTRY)();

DLL_AUDIOUPDATEFROMREGISTRY Dll_AudioUpdateFromRegistry = NULL;
HINSTANCE hCoreDll = LoadLibrary(TEXT("coredll.dll"));
if (hCoreDll)
...{
Dll_AudioUpdateFromRegistry = (DLL_AUDIOUPDATEFROMREGISTRY)GetProcAddress(hCoreDll, _T("AudioUpdateFromRegistry"));
if (Dll_AudioUpdateFromRegistry)
...{
(Dll_AudioUpdateFromRegistry)();
}
else
...{
return FALSE;
}
FreeLibrary(hCoreDll);
}
else
...{
return FALSE;
}
return TRUE;
}



//---------------------------------------------------------------------
//Description:
// Enable the sound for events
//---------------------------------------------------------------------
BOOL CSysVolume::EnableSoundEvent(BOOL bEnable)
...{
if(m_Reg.IsOK() != TRUE)
...{
return FALSE;
}

DWORD dwVal = m_Reg.GetValueDW(VALUE_MUTE);

if(bEnable == TRUE)
...{
dwVal |= BIT_EVENT;
}
else
...{
dwVal &= ~BIT_EVENT;
}

m_Reg.SetDW(VALUE_MUTE,dwVal);

return Apply();
}


//---------------------------------------------------------------------
//Description:
// Enable the sound for application
//---------------------------------------------------------------------
BOOL CSysVolume::EnableSoundApplication(BOOL bEnable)
...{
if(m_Reg.IsOK() != TRUE)
...{
return FALSE;
}

DWORD dwVal = m_Reg.GetValueDW(VALUE_MUTE);

if(bEnable == TRUE)
...{
dwVal |= BIT_APPLICATION;
}
else
...{
dwVal &= ~BIT_APPLICATION;
}

m_Reg.SetDW(VALUE_MUTE,dwVal);

return Apply();
}


//---------------------------------------------------------------------
//Description:
// Enable the sound for notifications. If the sound of application is
//mute, the sound of notification is mute too.
//---------------------------------------------------------------------
BOOL CSysVolume::EnableSoundNotification(BOOL bEnable)
...{
if(m_Reg.IsOK() != TRUE)
...{
return FALSE;
}

DWORD dwVal = m_Reg.GetValueDW(VALUE_MUTE);

if(bEnable == TRUE)
...{
dwVal |= BIT_NOTIFICATION;
}
else
...{
dwVal &= ~BIT_NOTIFICATION;
}

m_Reg.SetDW(VALUE_MUTE,dwVal);

return Apply();
}


//---------------------------------------------------------------------
//Description:
// Set the key click volume
//---------------------------------------------------------------------
BOOL CSysVolume::SetVolumeKeyClick(VolumeModeType volMode)
...{

DWORD dwVol = 0;

switch(volMode)
...{
case VOL_SOFT:
dwVol = VOL_VALUE_SOFT;
break;
case VOL_LOUD:
dwVol = VOL_VALUE_LOUD;
break;
case VOL_MUTE:
dwVol = VOL_VALUE_MUTE;
break;
}

if(m_Reg.IsOK() != TRUE)
...{
return FALSE;
}
m_Reg.SetDW(VALUE_KEY,dwVol);

return Apply();
}


//---------------------------------------------------------------------
//Description:
// Set the screen tap volume
//---------------------------------------------------------------------
BOOL CSysVolume::SetVolumeScreenTap(VolumeModeType volMode)
...{
DWORD dwVol = 0;

switch(volMode)
...{
case VOL_SOFT:
dwVol = VOL_VALUE_SOFT;
break;
case VOL_LOUD:
dwVol = VOL_VALUE_LOUD;
break;
case VOL_MUTE:
dwVol = VOL_VALUE_MUTE;
break;
}

if(m_Reg.IsOK() != TRUE)
...{
return FALSE;
}
m_Reg.SetDW(VALUE_SCREEN,dwVol);
return Apply();
}


//---------------------------------------------------------------------
//Description:
// Set the volume.
//
//Parameters:
// dwVol: The volume to set. And the range is MIN_VOLUME ~ MAX_VOLUME
//---------------------------------------------------------------------
BOOL CSysVolume::SetVolume(DWORD dwVol)
...{
if(dwVol <> MAX_VOLUME)
...{
return FALSE;
}
m_Reg.SetDW(VALUE_VOLUME,dwVol);
return Apply();
}

由于CSysVolume类将复杂的操作封装在内部,因此设置音量的非常简单.

以更改屏幕敲击声为洪亮为例:
CSysVolume sysVol;
sysVol.SetVolumeScreenTap(VOL_LOUD);

2008年8月13日星期三

WINCE驱动开发问题精华集锦

[RTOS]WINCE驱动开发问题精华集锦
seu_dust 发表于 2008-4-21 21:30:00

转自http://www.cnblogs.com/hbt19860104/archive/2008/04/11/1147884.html 对原出处表示感谢。

如何让系统加载自己写的驱动程序?
两种办法:
1、在[HKEY_LOCAL_MACHINE\Drivers\BuiltIn]下添加注册键。
2、在应用程序中调用ActivateDeviceEx。

在一些文件中用分号来表示注释,例如下面的内容
; @CESYSGEN IF SERVERS_MODULES_HTTPD
; @CESYSGEN ENDIF
在“CESYSGEN...”前加了“@”,有没有什么特别的含义?
在WINCE的一些文件中,用“;”作为注释并在注释文字中用@CESYSGEN作为标记,后面接条件语句。Cefilter.exe工具负责按照条件来筛选文件内容,所以不要轻易地删除包含@CESYSGEN的注释语句。

通过串口建立ActiveSync联接,串口线用三线的可以吗?
不可以,因为用串口同步时要用到其余口的状态。


WINCE是否支持MAPI?
不支持。WINCE自带的pmail.exe软件也不是很好用。建议自开发邮件收发软件。如果需要购买WINCE下邮件收发软件可以联系我。

如何旋转屏幕显示的内容?
例子代码如下(前提是显示驱动程序支持旋转):
DEVMODE devmode = {0};
devmode.dmSize = sizeof(DEVMODE);
devmode.dmDisplayOrientation = DMDO_90; ///垂直模式
devmode.dmFields = DM_DISPLAYORIENTATION;
ChangeDisplaySettingsEx(NULL, &devmode, NULL, 0, NULL); ///改变显示的设置
CRect rcWorkArea(0, 0, 320, 240); ///整个屏幕尺寸
///设置客户区大小并广播消息,这样所有软件也就随之更改显示
SystemParametersInfo(SPI_SETWORKAREA, 0, (void*)&rcWorkArea, SPIF_SENDCHANGE);

请问如何修改字形缓存的容量?
[HKEY_LOCAL_MACHINE\System\GDI\GLYPHCACHE]
"limit"=dword:0400

如何得到从WINCE启动开始到现在的时间?
调用API GetTickCount,得到的值为32位整数,单位为毫秒。

如何调用WINCE的软键盘?

调用API SipShowIM(SIPF_ON),前提是内核加入了软键盘组件。

基于HIVE的注册表,如何在系统关闭前保存注册表的数据到文件system.hv?
调用API RegFlushKey函数。

使用VirtualAlloc和VirtualCopy的时候需要注意哪些事项?
1、 VirtualAlloc的作用是申请虚拟地址空间,这肯定不是最终的目的,最终目的可能是申请物理内存、映射寄存器、提交文件等。没有一个目的会在意虚 拟地址空间的位置,所以尽量传递参数1为0,也就是让WINCE自动分配虚拟地址空间。VirtualAlloc分配地址空间实际上是以64KB为单位, 所以要指定申请的虚拟空间的首地址的话,参数1应该为64KB的整数倍,申请的长度也应该为64KB的整数倍,即使你不需要那么大。
2、 VirtualCopy的主要作用是映射物理地址空间,如果参数2为物理地址,那么最后一个参数要添加PAGE_PHYSICAL,参数2必须是256的 整数倍。如果参数2为虚拟地址(0x80000000以上),那么最后一个参数就不要添加PAGE_PHYSICAL,WINCE内核会根据这个虚拟地址 找到对应的物理地址。

驱动程序和应用程序之间传递数据时何时调用MapPtrToProcess?
因 为设备管理器负责加载驱动程序DLL,这意味着当应用程序调用驱动程序接口函数的时候,WINCE内核会将调用驱动程序接口函数的线程转移到设备管理器的 进程空间然后执行具体的驱动程序代码,应用程序和设备管理器处于两个进程空间,这就造成设备管理器无法访问应用程序传递的指针(虚拟地址),所以当我们在 应用程序中传递指针给流驱动程序接口函数时,WINCE内核从中作了一个地址映射,例如ReadFile、WriteFile、 DeviceIoControl函数的参数凡是指针都经过了映射才传递给驱动程序,所以很多驱动程序开发者并不了解其中的奥秘就可以编程了。但是如果参数 是一个指向一个结构体的指针,而结构体里包括一个或多个指针,那么WINCE内核并不负责映射,所以就需要开发者在驱动程序接口函数中调用API函数 MapPtrToProcess来映射地址。例 如:pPointer_retval = MapPtrToProcess(pPointer, GetCallerProcess());

如何判断可插拔的设备是否存在?
1、 通过查找注册表的值。凡是由API ActivateDeviceEx加载的驱动程序都在[HKEY_LOCAL_MACHINE\Drivers \Active]键下有注册键,通过查找“name”或者其它键值就能够找到。设备管理器就调用这个API。如果是PCI设备,在注册表[HLM \Drivers\BuiltIn\PCI\Instance]下查找关键字,例如[HLM\Drivers\BuiltIn\PCI\Instance \WaveDev1],说明音频驱动已经加载。
2、调用驱动程序接口函数,根据返回值或者执行结果来判断。

如何做到通过串口过来的一个信号启动自己开发的应用程序?
创 建一个线程负责等待串口过来的信号,调用API SetCommMask设置要等待的信号种类,具体可以等待的信号种类参见参数2的说明。然后再调用 API WaitCommEvent函数等待这个信号,接收之后再调用API CreateProcess启动应用程序。

在WINCE中如何只能启动应用程序的一个实例?
常用的两种办法:
1、如果应用程序实例创建了窗口,可通过API FindWindow函数通过窗口类名和窗口标题名称来查找,前提是系统内不会出现窗口名称重复的情况。
2、应用程序初始化的时候创建一个事件或互斥等内核对象,因为内核对象是由内核创建,名称在系统内唯一。

能不能自己编辑一个数字签名文件导入到手机上,这样就可以用这个签名签自己的程序了?
WINCE的内核签名机制的用途是限制非法的可执行模块EXE、DLL等在设备上运行。要求内核的加载模块用公钥验证请求加载的EXE、DLL的签名是否合法,而这个公钥是在定制内核的时候加进去的,所以除内核的定制者以外的人无法修改这个验证机制。

我按照版主的文章《加密WINCE系统》里操作,提示错误如下:
Error 80090016 during CryptSignHash 1!
Error signing hash
这 是因为传递了无效的钥容器名称,使CryptoAPI调用失败。应该在使用signfile工具之前创建一个钥容器,在桌面Windows中调用 API CryptAcquireContext创建一个指定名称的钥容器,接着再创建一个签名密钥对,这时再使用signfile工具就可以了。我在文 章里写成-kfulinlin是因为我创建钥容器的时候没有指定名称,系统就采用当前登录的用户名为容器名。

编译错误:CVTRES : fatal error CVT1102: out of memory; 42 bytes required ?
多 数情况下出现这种错误是因EVC的bug而起,应该在安装EVC之后就立刻安装EVC的SP补丁。另外为了避开BUG,使用EVC编程应该养成一些习惯, 比如定期备份工程所有文件,每次编译时采用Clean + Rebuild All,正调试时不要关闭模拟器等等。

在WINCE下是否能够得到某一进程使用的物理内存总量?
目前没发现有这样一个API能够得到指定进程使用的物理内存总量。只有GlobalMemoryStatus能够得到整个系统使用的物理内存总量。

应用程序如何控制lcd的亮度?如何获得电池的电量?
从 常见的平台如Geode、三星ARM系列来看,的确在驱动方面没有统一的控制LCD或者其它种类屏幕亮度的接口函数,所以只能根据具体平台提供的接口来 做。从帮助文档来看微软的带有DirectDraw功能的显示驱动程序的确有标准的增加亮度的接口函数,关于背景光参见标题为 “Enabling a Backlight”的帮助文档。
获得电池电量有标准的接口函数GetSystemPowerStatusEx,前提是驱动程序和硬件都要支持。

WINCE的socket函数好像不支持发送/接收超时?
是的,最早版本的WINCE支持选项SO_RCVTIMEO、SO_SNDTIMEO,后来却不支持了。

WINCE下如何设置窗口最大化和最小化?
WINCE 的帮助文档在介绍API ShowWindow函数的参数时指出 SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SW_SHOWDEFAULT, SW_SHOWMAXIMIZED, SW_SHOWMINIMIZED, SW_SHOWMINNOACTIVE 都不被支持,但实际上并不完全是这样,具体来说:
SW_MAXIMIZE 比原来窗口大,但不是最大化
SW_MINIMIZE 编译成功,但是不起作用
SW_SHOWMAXIMIZED 最大化
SW_SHOWMINIMIZED 编译出错
SW_RESTORE 能恢复
SW_SHOWDEFAULT 编译出错
SW_SHOWMINNOACTIVE 编译出错
SW_HIDE 能够隐藏

如何用程序调用控制面板的触摸屏校对程序?
两种办法:
1、调用API TouchCalibrate函数
2、调用CreateProcess,参数1为L"\\windows\\ctlpnl.exe",参数2为L"cplmain.cpl,9"。

如何获得U盘或者其它类型的存储器总容量和剩余可用容量?
调用API GetStoreInfo得到扇区数、每扇区字节数,相乘即是总容量。调用API GetDiskFreeSpaceEx得到剩余可用容量。

三星2440头文件定义#define IIC_BASE 0xB1400000 // 54000000,datasheet是54000000,那么怎么转成0xB1400000?
物 理地址映射方法分为两种,一种静态映射另一种为动态映射。在OEMAddressTable中定义了物理地址与虚拟地址的映射关系属于静态映射,用 VirtualCopy映射属于动态映射,采用哪种办法都可以。问题中提到的属于静态映射,2440的BSP在map.a文件中定义了IIC控制寄存器的 物理起始地址和对应的虚拟地址如下:
DCD 0x91400000, 0x54000000, 1 ;
在 OEMAddressTable中定义的虚拟地址范围在0x8000 0000—0x9FFF FFFF,这部分可缓存,适合内核程序和应用程序使用,同 时WINCE内核在0xA000 0000—0xBFFF FFFF中映射了另一份,指向了同样的物理地址,这部分不可缓存,适合驱动程序使用。三星 ARM处理器带有L1级高速缓存,可缓存会提高执行效率。对于特殊的设备寄存器适合映射到不可缓存的虚拟地址。
当驱动程序调用VirtualCopy对0xB1400000地址读写时,WINCE自动将这个地址减去0x2000 0000,也就是0x91400000,对应的物理地址就是0x54000000,也就是IIC控制寄存器的物理起始地址。

基于RAM的注册表如何保存数据?
调用API RegCopyFile备份注册表。调用API RegRestoreFile恢复注册表,然后调用KernelIoControl热启动使恢复生效。

如何隐藏和显示winCE下标准外壳的任务栏?
HANDLE hTaskBar = FindWindow(L"HHTaskBar", NULL);
ShowWindow(hTaskBar, SW_HIDE);
ShowWindow(hTaskBar, SW_SHOWNORMAL);

如果能让WINCE的IE浏览器播放flash动画?
播放flash需要Macromedia Flash Player SDK,参见http://www.adobe.com/products/flashplayer_sdk/。这和real player相似,都需要WINCE平台的SDK,都需要申请。

WINCE下内核模式和用户模式有什么区别?
为了使读者能够详细了解WINCE的地址映射原理还有两种模式,在这里我分几个部分说明:
1、 WINCE内核nk.exe的任务是管理操作系统核心功能。按照OEMAddressTable的映射要求,所有物理地址都映射到0x80000000以 上,所以对于内核程序nk.exe和内核模式下的线程来说,只要访问0x80000000以上的有效虚拟地址经MMU就能够访问物理地址,无需再映射是内 核模式的一个特点。内核模式的第二个特点是没有地址访问限制,内核模式线程可以访问任何有效虚拟地址,所谓有效虚拟地址是指有实际事物对应。
2、 用户模式线程只能访问0x80000000以下的虚拟地址空间,WINCE6.0之前版本的内核为每个进程划分32MB的地址空间,在不调用特殊函数的情 况下不能相互访问,这样的设计使得WINCE系统更安全、更稳定,限制访问地址是用户模式的第一个特点。第二个特点就是需要多一层映射,如果线程要访问物 理内存的话需要先映射到0x80000000以上,再经MMU访问物理内存地址。
WINCE的线程具有转移性(参考 API GetCallerProcess的说明,有一个很好的例子),当应用程序的线程调用API或者调用驱动程序接口函数时,该线程会转移到 gwes.exe、device.exe、filesys.exe等进程中执行,转移是由WINCE内核操作的,它会修改线程的上下文,记录线程的当前进 程、调用者进程、拥有者进程三个值。
3、如果在定制内核的时候选择了“Full Kernel Mode”,那么在这个内核上运行的所有线 程都处于内核模式,即使调用SetKMode(FALSE)后线程仍然具有内核模式的特点,能够访问任何有效的虚拟地址。假设现有一个64MB RAM的 WINCE产品,RAM映射从0x80000000到0x84000000,如果线程处于内核模式,它就直接可以访问这个范围的虚拟地址:
在OnButton1()中编写
DWORD oldMode = SetKMode(FALSE);
volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000)
*piTemp = 12345;
在OnButton2()中编写
DWORD oldMode = SetKMode(FALSE);
volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000)
int iTemp = *piTemp;
先只执行OnButton1()然后关闭程序,再重启程序然后执行OnButton2(),iTemp仍然等于12345。结果说明了两点:内核模式线程可以直接访问0x80000000以上的有效虚拟地址;我们写到RAM中的数据没有丢失,说明虚拟地址有效。
如果在定制内核的时候没有选择“Full Kernel Mode”,那么在这个内核上运行的所有线程都处于用户模式。可以调用SetKMode(TRUE)使调用线程暂时处于内核模式,还是原来的假设环境,我再举个例子:
在OnButton1()中编写
DWORD oldMode = SetKMode(TRUE);
volatile int *piTemp = (volatile int*)(0x20000000+0x84000000-0x00019000); ///或者(0x84000000-0x00019000)
*piTemp = 12345;
在用户模式下,如果不调用SetKMode(TRUE),那么执行*piTemp = 12345一定会弹出对话框,提示地址访问非法,如果调用SetKMode(TRUE)就不会提示地址访问非法,而且在OnButton2()中仍然能得到12345这个值。
通过这两个例子我相信读者能够完全了解两种模式的区别了。
4、 WINCE提供了两个函数SetKMode和SetProcPermissions,其中SetKMode能够把调用线程切换到内核模式,还可以切换回用 户模式。SetProcPermissions + GetCurrentPermissions添加当前进程访问权限给调用线 程,SetProcPermissions (0xFFFFFFFF)能让调用线程访问所有进程空间,但是调用线程仍然处于用户模式。SetKMode和 SetProcPermissions函数使得用户模式的特点不那么明晰。
如上所说一个应用程序的线程可能转移到其它两个进程地址空间中读 写数据,而每一个线程在被创建的时候只有访问创建它的进程地址空间的权限,所以驱动程序开发者必须在驱动程序读写数据前调用SetKMode或者 SetProcPermissions增加调用此函数的线程访问其它进程空间的权限。如果一个应用程序的线程只转移到一个进程地址空间,一般为设备管理器 进程device.exe,这种情况下不必增加线程访问其它进程空间的权限,但如果驱动程序本身创建了一个线程,那还是要调用SetKMode或者 SetProcPermissions增加新的线程访问其它进程的权限的,因为驱动程序创建线程时,当前进程为设备管理器,所以新线程只具有访问设备管理 器进程空间的权限,而不具备访问应用程序进程空间的权限。
5、可能一个编写过简单的流驱动的初学者会很疑惑,因为开发一个简单的流驱动程序 根本不需要调用这些函数,也没有调用过MapPtrToProcess,那是因为如果标准流驱动接口函数的参数为指针(ReadFile、 WriteFile、DeviceIoControl参数都有指针),WINCE内核会自动映射指针包含的地址,但仅此而已,其余任何情况都要求开发者自 行处理,比如流接口函数的参数是一个指向结构体的指针PA,而结构体中包括指针PB,PB指针就必须在流接口函数中映射,映射后才能访问,否则就会造成地 址访问非法。所以结构体中每个指针都要映射。
为了让读者能了解其中的原因,我举个例子:
假设设备管理器被加载到Slot4,应 用程序A被加载到Slot 8,A只有一个主线程T,T开始执行,按照WINCE的规定,正获得CPU的进程必须映射到Slot0,那么在执行代码的时候 A的所有虚拟地址都被减去一个偏移值,也就是8×0x02000000,A调用DeviceIoControl,传递一个指向一个结构体的指针B,而这个 结构体中包含一个指针C,指针C包含的地址假设为0x00030000,当执行DeviceIoControl时WINCE把设备管理器的进程地址空间映 射到Slot0,因为放在注册表[HKLM\Drivers\BuiltIn]下的驱动程序是由设备管理器加载的,自然驱动程序的代码段被加载到设备管理 器进程空间,但是线程仍然是T,此时T的当前所在进程为设备管理器(CurrentProcess),A变成了T的调用者进程 (CallerProcess),T自动具有了访问调用者进程空间的权限。这时访问Slot0中的虚拟地址其实质就是访问设备管理器的进程地址空间,要把 地址加上一个偏移值,也就是4×0x02000000,所以DeviceIoControl访问指针C包含的地址时本应该加上8×0x02000000, 却加上4×0x02000000,结果地址并不是设备管理器的合法区域,系统就会提示地址访问非法。而如果做了一个映射,指针C包含的地址就会被加一个正 确的偏移值,使地址处于A的地址空间Slot 8中,T此时具有访问A进程空间的权限,访问到正确的虚拟地址当然会得到正确的数据了。

为什么WINCE目录下的例子用build+sysgen能够编译成EXE文件,而我添加的例子就不能编译呢?
如 果这个例子是一个应用程序,那么肯定包括代码文件(.h .c .cpp)和资源文件(.rc和其它资源文件),build工具根据source文件内容 把代码文件编译成lib文件,资源文件编译成.res文件,sysgen工具根据makefile文件内容将source文件中列出的需要链接的各个库文 件合并成一个EXE文件。所以说关键在于makefile文件,WINCE目录下凡是能够用build+sysgen编译的都在makefile中有如何 链接的设置,而我们添加的例子当然没有在makefile中找到如何链接的设置,nmake工具就会提示不知道如何创建。

pcienum.exe干什么用的?
如 果你要开发某一个PCI设备的驱动程序,首先要知道这个PCI设备的信息(如VendorID、DeviceID、BaseClass、 SubClass)和PCI总线的信息。运行这个pcienum.exe就能得到相关信息。pcienum.exe提供了源码,位置\Public \Common\Oak\Drivers\Ceddk\Test\Pcienum。

wince下如何让操作系统进入待机模式?又如何把它激活?
通过注册表就可以设置,前提是你的驱动和硬件都支持。注册表项参见标题为“GWES Suspend Time-outs”的帮助文档。
[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Power]
"BattPowerOff"=dword:300
"ExtPowerOff"=dword:0
"WakeupPowerOff"=dword:60
"ScreenPowerOff"=dword:0

现有一个GPRS模块,如何通过GPRS连接到Internet?
1、先在内核中加入WAN下面的几个组件,如RAS/PPP、TAPI。WINCE采用unimodem驱动,所以不必担心没有Modem驱动的支持。
2、WINCE启动后新建一个拨号连接,比如名称叫“gprs1”,输入用户名、密码、电话号码。电话号码不同,所采用的模式不一样,例如“*99#”是GPRS模式,“17201”是普通的数据模式,速度差很多,价钱也差很多。
3、开始连接,连接过程会在对话框中显示,直到显示“连接成功”。
4、打开浏览器或者自己开发的通讯软件测试网络连接情况。
5、关闭连接。
6、保存[HKEY_CURRENT_USER\Comm\RasBook\gprs1]下的所有数据,添加到project.reg中,重新编译后内核中就有了一个拨号连接“gprs1”。
7、 调用RAS函数可以修改拨号连接“gprs1”的参数,如用户名、密码、电话号码,但是不能修改硬件设置,如波特率、串口、数据位、停止位等。RAS函数 还能够拨号、挂断。为了修改波特率可以多保存几个拨号连接,也可以直接调用TAPI开发拨号软件,另外WINCE自带的拨号连接是有源码的,位置 在\PUBLIC\COMMON\OAK\DRIVERS\NETSAMP\CONNMC。

采用基于HIVE的注册表如何删除用户保存在注册表中的数据,恢复到出厂时的注册表?
用 户修改的数据保存在user.hv文件中,直接删除一定失败,所以不能通过删除文件实现恢复出厂设置。微软考虑到了这个问题,在WINCE启动过程中 filesys.exe加载注册表时会调用OEMIoControl函数并传递一个IOCTL,这个IOCTL在pkfuncs.h中定义如下:
#define IOCTL_HAL_GET_HIVE_CLEAN_FLAG CTL_CODE(FILE_DEVICE_HAL, 49, METHOD_BUFFERED, FILE_ANY_ACCESS)
filesys.exe 会分别传递参数HIVECLEANFLAG_SYSTEM和HIVECLEANFLAG_USERS,如果返回值为TRUE那么filesys.exe清 除原来的注册表文件,如果返回值为FALSE那么filesys.exe保留原来的注册表文件。默认WINCE并没有实现这个IOCTL,所以OEM要删 除注册表文件就必须先编写这个IOCTL代码。代码的例子可参考标题为“IOCTL_HAL_GET_HIVE_CLEAN_FLAG”的帮助文档。另外 必须在ioctl.h和ioctl.c两个文件中编写该代码。在ioctl.c文件中找到 const OAL_IOCTL_HANDLER g_oalIoCtlTable[],添加IOCTL和对应的处理函数。要进一步了解这个全局数组,参 见标题为“IOCTL Library”的帮助文档。

如何在不删除必要组件的前提下减小内核文件长度?
要减小内核文件长度首先要在使用PB的定制内核向导中选择自定义,也就是说对于每个组件都由自己来选择,而不是选择PB的标准配置。但减小内核文件长度最有效最直接的办法是缩小字体,尤其对于东亚字体,采用字体压缩技术并且选择合理的字库文件将明显缩小文件长度。
1、在定制内核时选择AGFA AC3 Font Compression组件。SYSGEN变量为SYSGEN_AGFA_FONT。
2、参考标题为“East Asian Font Versions”的帮助文档,从中选择你需要的字库文件加到内核中,从文档可以看出加AC3压缩比不加压缩在文件长度方面差距很大。

如何得到WAV文件播放的总时间?
1、直接读取wav文件头信息,从文件起始地址偏移28个字节长度为4个字节保存的是每秒钟播放的字节数,从文件起始地址偏移40个字节长度为4个字节保存的是声音数据的总的字节数,相除就是播放时间。
2、 调用IGraphBuilder::RenderFile打开一个wav文件,然后通过IGraphBuilder得到IMediaSeeking指针, 再调用IMediaSeeking::GetDuration得到总的时间(结果要除以 10000000),IMediaSeeking::GetCurrentPosition得到当前播放时间。

如何在Dialog-Based程序中加入menubar?
先调用CommandBar_Create再调用CommandBar_InsertMenubar。

请问MultiByteToWideChar与_T、L、TEXT的区别?
MultiByteToWideChar函数转换的对象可以是常量也可以是变量。其它只能转换常量。_T和TEXT会根据当前系统是否定义_UNICODE宏来决定是否转换,而L就是转换成宽字符,当然也包括其他类型常量的转换。

在用UBS线缆通过ActiveSync同步有效的情况下,如何插上USB线缆后WINCE自动与PC同步?
1、新建一个拨号连接,假设名称为“usb1”,选择连接类型为“直接连接”,并在连接设备里选择通过USB线缆连接。
2、将注册表[HKEY_CURRENT_USER\Comm\RasBook\usb1]下的数据添加到project.reg或者platform.reg中。
3、在[HKEY_CURRENT_USER\ControlPanel\Comm]下添加如下:
"AutoCnct"=dword:1 ///直接连接
"Cnct"="usb1" ///连接名称
4、重新编译内核。为了节省编译时间也可以在内核工程下搜索*.reg文件,将2、3步骤中的注册表数据添加其中,然后直接make image。

如何通过进程句柄来获得该进程的主窗口句柄?
好 像没有API能够通过进程句柄直接获得主窗口的句柄,因为并非每个应用程序都带UI。但是可以反过来,先枚举当前系统所有主窗口,然后根据每个窗口的句柄 调用GetWindowThreadProcessId函数得到进程的ID,再调用OpenProcess得到进程句柄,与现有的进程句柄比较。

我做的显示驱动DLL已经编译成功了,但是在加载显示驱动的过程中弹出话框,提示如下:
unhandled exception in gwes.exe (0xc0000005 access violation)
提 示的错误——地址访问非法,表明你的驱动程序代码并没有在读写数据前添加SetKMode(TRUE)或者 SetProcPermissions(0xFFFFFFFF)函数让线程能够访问任何进程的地址空间。你可以调用 IsBadReadPtr和 IsBadWritePtr函数检测地址是否能够合法访问。编写和gwes有关的驱动程序应该首先调用SetKMode(TRUE)或者 SetProcPermissions(0xFFFFFFFF)函数,这是一个好习惯。

请问在嵌入式系统中如何设置GPRS拔号用的APN?
对一个拨号连接比如“我的连接”单击鼠标右键,在弹出的菜单中选择“属性”,然后单击“配置”—“拨号选项”,在“附加设置”中添加AT命令如“+cgdcont=1,"ip","cmnet"”。“cmnet”位置即为APN。

WINCE的IP Phone功能如何?
WINCE的voip需要c-s-c结构,既需要服务器的中转,而skype采用第三代p2p技术就不需要中转,但是在gprs下也做不到语音流畅。skype有pocket pc版本,但是无线方面需要wlan或者cdma。

三星ARM平台如何定义自己的中断ID?
以 S3C2410为例,在oalintr.h文件中定义中断ID,也称SYSINTR,例 如 #define SYSINTR_MYINT (SYSINTR_FIRMWARE+20),最大值不能超过 SYSINTR_FIRMWARE+23。然后在armint.c文件中找到OEMInterruptHandler函数,用 if (IntPendVal == INTSRC_XXX) 判断当前发生的中断源号,然后返回SYSINTR_MYINT。内核分别调用 OEMInterruptDisable(禁止当前中断)、OEMInterruptDone(中断处理结束)、 OEMInterruptEnable(当前中断有效)三个函数,参数都为中断ID,在这三个函数中用 case SYSINTR_MYINT判断当前要 处理的中断。

如何开发软件从PC端复制文件到基于WINCE的设备?
调用 RAPI(Remote Application Programming Interface)函数,此函数集由桌面计算机调用,由基于WINCE的设 备执行。一旦连接上就可以在桌面计算机端调用RAPI。通过注册表还可以限制RAPI能够访问目录的范围。具体参考RAPI和RDP(远程桌面协议)。

请问如何对NandFlash分区、格式化?
你看看WINCE420\PUBLIC\COMMON\OAK\DRIVERS\ETHDBG\BOOTPART\bootpart.cpp,在Eboot中先要调用BP_LowLevelFormat(
DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags) 再flash的一个区域建立空的MBR,然后连续两次调用 BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags) 函数来建立BINFS和FAT分区。建好后,将nk.bin烧入binfs分区中。

要做个弹出对话框具有 always on top 属性,如何实现?
调用SetWindowPos(.. , HWND_TOPMOST, ...., SWP_NOACTIVATE)。

s3c2410+WINCE下网络PING一会就断,如何解决?
原 因在于中断处理程序把已经产生的中断标志清除掉了,这样就丢失一次中断。因为原驱动里配置中断为上升沿触发,一次中断丢失就导致不会再产生中断信号跳变, 因为只有在中断服务中读取了cs8900的 Interrupt status queue寄存器后,才会产生下一次中断!解决办法:
1、在cfw.c文件中全局定义BOOL Inited = FALSE
2、修改OEMInterruptEnable()中case SYSINTR_ETHER: 下面的语句为:
if(Inited == FALSE)
{
s2410IOP->rEINTPEND = 0x200;
s2410INT->rSRCPND = BIT_EINT8_23;
if (s2410INT->rINTPND & BIT_EINT8_23)
s2410INT->rINTPND = BIT_EINT8_23;
Inited = TRUE;
}
s2410IOP->rEINTMASK &= ~0x200;
s2410INT->rINTMSK &= ~BIT_EINT8_23;
break;
注:本解决办法转载于http://stoned.blogchina.com/stoned/3083045.html,非我本人研究成果。

已经搜索到文件,如何用CListBox以图标形式显示出来?
CListCtrl ListCtrl;
CImageList ImageList;
ImageList.Create(IDB_BITMAP, 48, 2, RGB(0,0,0));
ListCtrl.SetImageList(&ImageList, LVSIL_NORMAL);
ListCtrl.InsertItem(iListIndex, strItem, 1);

如何改变控制面板中电源属性对话框的尺寸?
1、需要修改对话框的尺寸是因为对话框是以资源方式加载的,不会根据当前系统显示分辨率而自我调节尺寸。
2、 安装WINCE后有一些组件(feature)的资源文件*.res就已经有了,如果你不改变,那么build内核的时候PB只是把这些.res复制到工 程目录下,然后与*.obj合并成EXE、DLL、CPL。所以修改了.rc文件里面的对话框尺寸后要重新编译.rc文件为.res文件,然后再覆盖原来 WINCE自带的.res文件。
3、改变对话框尺寸有两种办法:一种方法是更改系统字体字号,系统字体的字号变化会影响对话框的尺寸,但是 缺点是所有系统字体有关的UI都会改变。另一种是在.rc文件中调整对话框尺寸,然后编译成.res文件,再将.res复制到对应的语言目录里,比如目录 名为0804(中文),再执行Rebuild命令重新编译内核,或者执行sysgen+build。在研究中我发现.res文件虽然能够直接用EVC打 开、修改、保存,但是和其它Obj链接成EXE、DLL、CPL后并不能运行,所以还是建议读者用CE自带的rc工具编译最好。读者可在PB的命令行中键 入“rc /?”了解rc.exe工具的用途和参数。

使用EVC build之后连接模拟器的时候,提示download file等了一会又出现download failed?
一般这样的问题从下面几个步骤解决:
1、如果之前能启动模拟器而现在不能,那么先clean然后重启计算机再build。
2、如果开发的主机为WINXP+SP2,可能存在与EVC模拟器不兼容的情况,检查C:\boot.ini,将/noexecute=optin改为/execute=optin。
3、 检查你的模拟器是否能运行,假设你正用的SDK名称为MYSDK,单击菜单tools—configure platform manager,选择 MYSDK—MYSDK emulator,再单击properties—test,看看模拟器是否能够启动,如果能启动那问题就不大。
4、单击菜单build—update remote output files,看看模拟器是否能够启动。
5、如果上述办法均不行,关闭EVC然后重新建立一个新的工程,编译,看看模拟器是否能够启动,如果能启动说明原来工程出了问题,最好恢复原工程的备份。

如何设置能够自动拨号、禁止自动拨号?
在[HKEY_LOCAL_MACHINE\Comm\Autodial]下是自动拨号的注册表设置。
Enabled=DWORD:1 ///是否能够自动拨号
FailRetryWaitMS=DWORD ///如果失败再次拨号的等待时间
RasEntryName1= REG_SZ ///自动拨号采用的拨号连接名称

2008年8月11日星期一

CSDN被和谐了。。。。

CSDN被和谐了。。。唉。。。。。

2008年8月5日星期二

北京奥运会安排



Google 文档 - BeiJing Olmpyc Game Order


















.





.


2008 年夏季奥林匹克运动会赛程表

.





.


按项目名称

.


射箭皮划艇/激流回旋

.


田径皮划艇/静水

.


羽毛球现代五项

.


棒球山地自行车

.


篮球赛艇

.


沙滩排球帆船

.


拳击射击

.


开闭幕式垒球

.


小轮车越野游泳

.


公路自行车花样游泳

.


场地自行车乒乓球

.


跳水跆拳道

.


马术网球

.


击剑铁人三项

.


足球排球

.


体操水球





.


手球举重

.


曲棍球摔跤

.


柔道

.


按日期进入

.


*所有时间均为北京当地时间





2008年8月1日星期五

彻底无语了。。看日食竟然还有广告

网易的日食直播还有广告!无语

[转帖]水煮TCPMP(不得不转的好文)

这段时间在研究TCPMP(The Core Pocket Media Player),这是一个应用于智能设备上的开源媒体播放软件。
TCPMP是一个功能强大开放式的开源多媒体播放器,
播放器主要由核心框架模块(common工程)和解码器分离器插件组成。
TCPMP的插件非常多,我们联合几个最常用的插件(ffmpeg、splitter)来说明,其中interface插件实现TCPMP的界面,由于他和媒体播放没有什么关系,这部分可以完全被替换掉,替换成自己的界面。
ffmpeg 工程是系统主要的音视频解码模块,ffmpeg是一个集录制、转换、音/视频编码解码功能为一体的完整的开源解决方案。FFmpeg的开发是基于 Linux操作系统,但是可以在大多数操作系统中编译和使用。ffmpeg支持MPEG、DivX、MPEG4、AC3、DV、FLV等40多种编 码,AVI、MPEG、OGG、Matroska、ASF等90多种解码。很多开源播放器都用到了ffmpeg。但是ffmpeg程序解码效率不是很高, 系统仅仅使用了FFmpeg的部分解码功能。
ffmpeg主目录下主要有libavcodec、libavformat和libavutil等子 目录。其中libavcodec用于存放各个encode/decode模块,libavformat用于存放muxer/demuxer模 块,libavutil用于存放内存操作等常用模块。本系统的媒体文件分离器有单独的splitter模块完成所以不需要libavformat子目录。 ffmpeg目录下libavcodec、libavutil保留子目录。

libmad工程用于MP3文件解码,该工程包含两个功能模块,一个负责解析MP3文件格式,包括MPEG1音频文件 (MP1,MP2,MP3,MPA),读取每一帧音频数据;另一个负责解码MPEG1音频数据,解码代码在libmad子目录中。
libmad 是一个开源的高精度 MPEG1音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII,也就是 MP3)。 libmad提供 24-bit 的 PCM 输出,完全是定点计算,非常适合没有浮点支持的平台上使用。使用 libmad 提供的一系列 API,就 可以非常简单地实现 MP3 数据解码工作。在 libmad 的源代码文件目录下的 mad.h 文件中,可以看到绝大部分该库的数据结构 和 API 等。libmad是用的fixed-integer,通过整数模拟小数计算的,精度只能保证到小数点后第9位(大于0的最小 值 0.00000000372529),虽然解码精度会有损失,但是极大提高了解码效率,特别是在嵌入式设备上也可以实现高码率MP3文件的解码。

splitter 工程用于解析多种音视频文件格式。可以解析的文件格式包括:ASF媒体文件,视频文件 (AVI,DIVX),Windows波形文 件 (WAV,RMP),MPEG电影文件 (MPEG,MPG,MPV),MPEG4文件 (MP4,3GP,M4A,M4B,K3G)。以上格式可以 被解析但是数据编码不一定能正确解码,需要依赖系统的解码器。

common工程是核心模块,是一个开放的集数据输入、转换、音/视频解 码、信号输出等功能为一体的完整的多媒体播放框架。这个框架自身不包含任何的Decode和Split功能,这些功能由插件实现,核心模块以一个树状结构 管理所有的功能模块和插件模块,实现数据Render功能,对输入、转换、输出流程的控制,接受播放过程中的操作和对事件进行处理,同时也实现系统运行中 经常使用的一些共用函数,比如解码过程中经常使用的逆离散余弦变换,内存操作,界面中需要使用的多语言字符处理等。common工程的主目录下主要 有:blit、dyncode、overlay、pcm、softidct、win32、zlib等子目录。其中blit和overlay存放是视频信号 渲染模块,pcm存放PCM音频信号转换模块,softidct存放逆离散余弦变换函数,win32存放内存操作等常用模块,dyncode这个目录的代 码比较晦涩,存放的是程序运行是动态生成代码模块,针对不同的CPU指令集,PCM数据数据声道和采样率不同,视频渲染数据格式和色深等不同情况动态生成 不同的优化代码(这段代码非常精彩,不能不让人佩服TCPMP作者的高超水平)。核心模块有一个上下文对象context,该对象在初始化函数 bool_t Context_Init(……)中候创建了一个该对象实例。该对象实例记录管理各个功能模块,用户界面可以通过该对象和核心模块交互,管 理控制播放过程。
Context对象说明:
typedef struct context
{
int Version; //版本信息
uint32_t ProgramId;
const tchar_t* ProgramName; //应用程序名称
const tchar_t* ProgramVersion; //程序版本号,字符串
const tchar_t* CmdLine; //程序命令行信息
void* Wnd; //视频渲染窗口句柄
void* NodeLock; //功能模块访问临界区互斥变量
array Node; //功能模块数据对象数组
array NodeClass; //功能模块定义对象数组,按照系统逻辑关系组织
array NodeClassPri; //功能模块定义对象数组,按照系统逻辑关系和模块优先级排列
array NodeModule; //外部插件模块数组
int LoadModuleNo; //当前正在装载的外部插件序号
void* LoadModule;
array StrTable[2]; //字符串资源数组,字符串分为
//给底层使用的标准字符串资源和
//给界面使用的显示字符串资源,两种资源用两个数组表示
array StrBuffer;
array StrModule; //未使用
void* StrLock; //字符串数组访问临界区互斥变量
uint32_t Lang; //当前使用语言标志
int CodePage; //当前使用代码页标志
struct pcm_soft* PCM; //PCM音频信号转换模块
struct blitpack* Blit; //视频信号渲染模块
struct node* Platform; //得到平台相关信息
struct node* Advanced; //得到播放模块高级信息
struct node* Player; //播放控制模块
notify Error; //信息错误回调函数
//屏幕旋转信息,在某些系统中屏幕可以旋转90度或180度
int (*HwOrientation)(void*);
void *HwOrientationContext;
bool_t TryDynamic; //未使用
int SettingsPage; //未使用
size_t StartUpMemory; //可以使用的有效内存数
bool_t InHibernate; //是否进入休眠状态
bool_t WaitDisable; //未使用
int FtrId; //未使用
bool_t LowMemory; //可以使用的有效内存数是否小于系统要求的最低要求
//动态代码生成中间状态及数据
bool_t CodeFailed;
bool_t CodeMoveBack;
bool_t CodeDelaySlot;
void* CodeLock;
void* CodeInstBegin;
void* CodeInstEnd;
int NextCond;
bool_t NextSet;
bool_t NextByte;
bool_t NextHalf;
bool_t NextSign;

uint32_t* FlushCache; //未使用
void* CharConvertUTF8; //未使用
void* CharConvertCustom; //未使用
int CustomCodePage; //未使用
void* CharConvertAscii; //未使用
void* Application;
void* Logger; //未使用
bool_t KeepDisplay; //是否保持背光长亮
int DisableOutOfMemory; //未使用

} context;
核心模块上下文指针可以通过全局函数获得context* Context();
初 始化上下文对象的全局函数是 bool_t Context_Init(const tchar_t* Name,const tchar_t* Version,int Id,const tchar_t* CmdLine,void* Application); 其中Name参数为应用程序名称,Version为版本信息字符串。
释放上下文对象的全局函数是void Context_Done();。
void Context_Wnd(void*);函数将视频播放窗口句柄初始化给设备上下文。

功能模块包含定义对象和数据对象,定义对象描述功能模块相互间的逻辑结构,数据对象记录模块属性和方法。
所有的功能模块结构按一个树状结构来组织,结构关系如下,NODE是整个结构的根结点,其下为子节点,节点按类型可分为实节点,全局节点,设置节点,抽象节点。
#define CF_SIZE 0x00FFFFFF
#define CF_GLOBAL 0x01000000
#define CF_SETTINGS 0x02000000
#define CF_ABSTRACT 0x08000000
抽 象节点没有对应的对象实例,类似C++的抽象基类,为了按照逻辑关系组织系统结构而存在,例如NODE就是抽象节点。全局节点全局只有一个对象的实例,如 播放控制模块PLAYER_ID。设置节点表示和系统播放设置相关,比如声音均衡器模块EQUALIZER_ID,颜色控制模块COLOR_ID。实节点 与抽象节点不同,指可以生成对象实例的节点,实节点没有特殊标识,一般以数据对象占用内存大小表示是否是一个实节点,创建节点时要根据该信息分配内存单 元,实节点也可以有子节点,例如:MMS_ID的父节点是HTTP_ID。全局节点,设置节点和实节点可以相互组合,比如播放控制节点同时是全局节点,设 置节点和实节点。节点名称后带_ID的就是实节点,否则就是抽象节点。

NODE (根节点)
├─FLOW (流控制模块)
│ ├─CODEC (解码模块)
│ │ ├─EQUALIZER_ID (声音均衡器模块)
│ │ ├─VBUFFER_ID (视频缓冲模块)
│ │ ├─DMO (DirectX Media Object)
│ │ │ ├─WMV_ID
│ │ │ ├─WMS_ID
│ │ │ ├─WMVA_ID
│ │ │ ├─WMA_ID
│ │ │ └─WMAV_ID
│ │ ├─FFMPEG VIDEO (FFMpeg 解码模块)
│ │ └─LIBMAD_ID (Libmad Mp3解码模块)
│ ├─OUT (信号渲染模块)
│ │ ├─AOUT (音频信号渲染)
│ │ │ ├─NULLAUDIO_ID
│ │ │ └─WAVEOUT_ID
│ │ └─VOUT (视频信号渲染)
│ │ ├─NULLVIDEO_ID
│ │ └─OVERLAY
│ ├─IDCT (离散余弦解码模块)
│ │ └─SOFTIDCT_ID
│ └─CODECIDCT(离散余弦解码模块,函数比IDCT要少)
│ └─MPEG1_ID
├─MEDIA (媒体文件格式编码解析模块)
│ ├─FORMAT (格式解析模块)
│ │ └─FORMATBASE
│ │ ├─RAWAUDIO
│ │ │ └─MP3_ID
│ │ ├─RAWIMAGE
│ │ ├─ASF_ID
│ │ ├─AVI_ID
│ │ ├─MP4_ID
│ │ ├─MPG_ID
│ │ ├─NSV_ID
│ │ └─WAV_ID
│ ├─PLAYLIST (播放列表模块)
│ │ ├─ASX_ID
│ │ ├─M3U_ID
│ │ └─PLS_ID
│ └─STREAMPROCESS (数据流处理模块)
├─STREAM (数据输入模块)
│ ├─MEMSTREAM_ID (内存数据流模块)
│ ├─FILE_ID (文件IO模块)
│ └─HTTP_ID (网络数据获取模块)
├─TIMER (定时器模块)
│ └─SYSTIMER_ID
├─ASSOCIATION_ID (文件扩展名自动关联模块)
├─ADVANCED_ID (高级设置模块)
├─COLOR_ID (颜色控制模块)
├─PLATFORM_ID (平台信息模块)
├─XSCALEDRIVER_ID (Intel XScale CPU 信息模块)
├─PLAYER_ID (播放控制模块)
└─PLAYER_BUFFER_ID (播放缓冲模块)

节点树状结构由若干个静态定义对象(nodedef)实例实现,
typedef struct nodedef
{
int Flags;
int Class;
int ParentClass;
int Priority;
nodecreate Create;
nodedelete Delete;
} nodedef;
Flags表示当前节点的类型:抽象、实节点、全局、设置。
Class表示当前节点的标识,如MEDIA_CLASS或ASF_ID等等。
ParentClass表示当前节点的父节点标识,如SYSTIMER_ID对象的父节点是TIMER_CLASS。
Priority表示当前节点优先级。
Create和Delete是两个函数指针,表示该节点的创建函数和销毁函数。
如播放控制模块的结构定义是
static const nodedef Player =
{
sizeof(player_base)|CF_GLOBAL|CF_SETTINGS,
PLAYER_ID,
NODE_CLASS,
PRI_MAXIMUM+600,
(nodecreate)Create,
(nodedelete)Delete,
};

绝 大多数节点都有一个对应的数据对象,记录该节点的数据和方法,每一个子节点对象都是以父节点对象作为该节点一个元素,类似C++的封装继承机制。如果子节 点的父节点没有数据对象,该节点可以从node节点直接继承。每一个节点都可以看成Node节点的直接或间接子节点,所以所有节点头以一个相同的node 结构开头,子节点可能还有自己的属性,在继承父对象后就是子节点自己的元素。
typedef struct node
{
int Class;
nodeenum Enum;
nodeget Get;
nodeset Set;
} node;
Class表示该对象的标识,如PLAYER_ID。
Enum是一个函数指针,指向一个函数用于枚举当前节点的属性。
Get是一个函数指针,得到当前节点某一属性值。
Set是一个函数指针,设置当前节点的某一属性数值。

节点的属性值数据特性在一个static const datatable xxxParams[] = {……};的静态数组里定义。
typedef struct datatable
{
int No;
int Type;
int Flags;
int Format1;
int Format2;
} datatable;

No表示属性的标识,如播放控制模块的#define PLAYER_PLAY 0x32 就表示控制播放器播放或暂停。
Type表示属性的数据类型,可用值在node.h中定义。
Flags是属性数据的标志,表示该数据是不是只读数据,是否有最大最小值等等,可用值在node.h中定义,如果该标志包含DF_SETUP同时不包含DF_NOSAVE和DF_RDONLY属性,该属性会被记录在注册表中,下次启动时用注册表的数据初始化该属性。
Format1和Format2是可选标志与Flags配合使用,比如如果Flags表示该属性存在最大最小值,Format1和Format2可以分别表示最小和最大数值。

在在系统上下文对象中有两个元素记录节点信息array Node;和array NodeClass;,array是数组数据类型,Node是节点数据对象的数组,NodeClass节点对象的数组,按照系统逻辑关系组织。
创建节点时传入nodedef对象到节点创建函数,函数会根据nodedef信息生成对应nodeclass对象添加到NodeClass数组,同时根据nodedef信息分配数据对象的内存空间。在该节点的Create函数里面再初始化该节点的数据对象。

在所有功能模块中和界面加交互的主要就是播放控制模块struct node* Player;使用方法如下:
context* p = Context();
player* myplayer = NULL;
if(p) myplayer = (player*)(p->Player);
控 制播放参数使用Set(void* This,int No,const void* Data,int Size);函数,第一个参数是播放模块指针, 第二个参数是控制代码,即要进行什么操作,第三个参数是需要赋值给控制代码的数值,最后一个参数是所赋数值的占用内存的大小。
例如开始播放的代码是:
myplayer->Set(myplayer,PLAYER_PLAY,1,sizeof(int));
PLAYER_PLAY为控制代码,表示当前控制的是播放暂停功能,数值为1表示播放为0表示暂停。
得到某一控制属性使用Get(void* This,int No,void* Data,int Size);函数,参数含义和Set函数相同。
控制代码是一组宏,定义在player.h文件中。比较重要的控制参数有
// play or pause (bool_t)
#define PLAYER_PLAY 0x32
// position in fraction (fraction)
#define PLAYER_PERCENT 0x25
// position in time (tick_t)
#define PLAYER_POSITION 0x28
// current format (format*)
#define PLAYER_FORMAT 0x2B
// current file in playlist (int)
#define PLAYER_LIST_CURRENT 0x2F
// current file index (suffled) in playlist (int)
#define PLAYER_LIST_CURRIDX 0xA2
// fullscreen mode (bool_t)
#define PLAYER_FULLSCREEN 0x3E
// stop
#define PLAYER_STOP 0xB2
// skin viewport rectangle (rect)
#define PLAYER_SKIN_VIEWPORT 0x3C
播放控制模块所有可用参数见static const datatable PlayerParams[]结构。

添加一个媒体文件到播放模块使用int PlayerAdd(player* Player,int Index, const tchar_t* Path, const tchar_t* Title);
第一个参数为播放模块指针,第二个参数是添加到播放模块文件队列的序号,如果是使文件成为第一个文件该参数设为0,第三个参数是媒体文件的目录和名称,第四个参数为媒体文件标题,该参数可以忽略。

核 心模块也管理多语言字符串,使用函数const tchar_t* LangStr(int Class, int Id);和 const tchar_t* LangStrDef(int Class, int Id)可以得到对应字符串,系统字符串资源有两种,标准字符串和特 殊字符集字符串。标准字符串资源文件是工程目录下的lang_std.txt文件,该文件字符串为ASCII字符,可与其他代码页字符兼容。该文件记录的 是核心模块运行时需要使用的字符串,Decode和Splite模块可以处理的编码格式和文件格式也在这个文件中记录,例如lang_std.txt文件 中的
MP3_0001=audio/mpeg
MP3_0002=mp1:A;mp2:A;mp3:A;mpa:A
MP3_0200=acodec/0x0055
纪录了MP3文件分离器对应的文件类型、扩展名和文件特征码。
要得到标准字符串使用函数LangStrDef,第一个参数表示字符类别,第二个参数表示字符ID。界面相关的是特殊字符集的字符串,使用函数LangStr,第一个参数表示字符类别,第二个参数表示字符ID。关于字符串资源文件结构含义将在以后的文档中说明。

[转贴]Windows CE 繪圖流程

BeginPaint 的動作
1.將無效區域 變成有效區域
2.傳送WM_ERASEBACKGROUND訊息,重新繪製背景
3.只能在WM_PAINT中呼叫

4.和EndPaint(hWnd,&ps) 成雙成對

// Message dispatch table for MainWindowProc

WM_PAINT, DoPaintMain,

in ,h 檔

LRESULT DoPaintMain (HWND, UINT, WPARAM, LPARAM);

//設定點的結構

typedef struct tagPOINTS2
{
SHORT x;
SHORT y;
} POINTS2;

LRESULT DoPaintMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {


//*********************貼圖***********************//
//http://genewince.blogspot.com/2008/03/evc-4-resource.html 如何加入bmp資源擋
DWORD a;
ULONG b;
LPVOID c;
PUCHAR d;
HANDLE e;
PAINTSTRUCT ps;
RECT rect;
HDC hdc;
BITMAP bm;


GetUpdateRect(hWnd,&rect,1);
HBITMAP hBitmap2 = SHLoadDIBitmap(TEXT("\\Storage Card\\33332.bmp"));
//HBITMAP hBitmap2;
//hBitmap2 = LoadBitmap(hInst,(LPCTSTR)IDB_BITMAP1);

GetClientRect (hWnd, &rect);//取得用戶視窗矩形大小
hdc = BeginPaint(hWnd,&ps);

if (Pressing){ Rectangle(hdc,pt.x,pt.y,cur_pt.x,cur_pt.y); // 繪畫選取矩形
old_pt.x=cur_pt.x;
old_pt.y=cur_pt.y;
}
if(old_pt.x==cur_pt.x && old_pt.y==cur_pt.y){
Rectangle(hdc,pt.x,pt.y,cur_pt.x,cur_pt.y);
}

HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap2);

GetObject(hBitmap2, sizeof(BITMAP), &bm);
//取得圖片大小資訊

// BitBlt(hdc , rect.left , rect.top , bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);//SRCCOPY
StretchBlt(hdc , rect.left , rect.top , (bm.bmWidth)/1, (bm.bmHeight)/1, hdcMem, 0, 0, bm.bmWidth,bm.bmHeight, SRCCOPY);//SRCCOPY
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);


// EndPaint(hWnd, &ps);
// return 0;
//*********************貼圖***********************//

//*********************畫點***********************//
SetPixel(hdc,400,400,RGB(0x00,0x00,0xFF));
//*********************畫點***********************//

//*********************畫線***********************//
//
POINT pts[2];
pts[0].x=20;
pts[0].y=20;
pts[1].x=200;
pts[1].y=150;
Polyline(hdc, pts ,2);
HPEN hPen = CreatePen(PS_DASH,1,RGB(0xff,0x88,0x0));
SelectObject(hdc, hPen);
MoveToEx(hdc,150,150,NULL);
LineTo(hdc,500,160);

//*********************畫線***********************//

//*********************畫形狀********************//

HBRUSH hBrush;
hBrush = CreateSolidBrush(RGB(0xAA,0x55,0x55));
SelectObject(hdc, hBrush);
Rectangle(hdc,200,200,550,500);//方
hBrush = CreateSolidBrush(RGB(0x22,0xAA,0x33));
SelectObject(hdc, hBrush);
Ellipse(hdc,300,100,500,300);//圓
hBrush = CreateSolidBrush(RGB(0x22,0x2A,0xAA));
SelectObject(hdc, hBrush);
RoundRect(hdc,0,300,200,500,50,30);//圓角方
hBrush = CreateSolidBrush(RGB(0xdd,0x6A,0xAA));
SelectObject(hdc, hBrush);
POINT ppt[3];
ppt[0].x=60;
ppt[0].y=60;
ppt[1].x=20;
ppt[1].y=100;
ppt[2].x=100;
ppt[2].y=100;
Polygon(hdc,ppt,3);//多邊三角形

TRIVERTEX vert[2];
GRADIENT_RECT gRect;
RECT prect = {100 , 300 , 300 ,500};

vert[0].x=prect.left;
vert[0].y=prect.top;
vert[0].Red=0xAC00;
vert[0].Green=0xF300;
vert[0].Blue=0x8100;
vert[0].Alpha=0x0000;

vert[1].x=prect.right;
vert[1].y=prect.bottom;
vert[1].Red=0xA300;
vert[1].Green=0x5700;
vert[1].Blue=0xD500;
vert[1].Alpha=0x0000;

gRect.UpperLeft=1;
gRect.LowerRight=0;

GradientFill(hdc,vert,2,&gRect,1,GRADIENT_FILL_RECT_H);

//*********************畫形狀********************//


//****************顯示有變數的文字**************//

TCHAR szOut[256];
a=sizeof(DOUBLE);
wsprintf(szOut,TEXT("a=%d"),a);
ExtTextOut(hdc,200,200,0,NULL,szOut,lstrlen(szOut),NULL);
//****************顯示有變數的文字***************//
// PAINTSTRUCT ps;
// RECT rect;
// HDC hdc;
RECT rectText = rect;
rectText.left=0;
rectText.top=0;
// Get the size of the client rectangle
GetClientRect (hWnd, &rect);
SetBkMode (hdc, TRANSPARENT);
hdc = BeginPaint (hWnd, &ps);

DrawText (hdc, TEXT ("馬"), -1, &rectText, DT_SINGLELINE);


EndPaint (hWnd, &ps);

return 0;

}

WINCE应用层设计经验总结-关于当前时间显示和当前时间获取

//=========================================================================//

//题目:关于当前时间显示和当前时间获取

//描述:在wince下获取当前系统时间和现实当前系统时间

//作者:Mercury Xu

//日期:2008-07-12

//编译环境:VS2005 VC++ /EVC均可

//=========================================================================//

正文:

这个并不是很麻烦的问题。去年的这个时候已经做出来了。今年再一次用到收集整理了一下放到这里

这次应用地方是蓝牙电话接播电话的时间记录。为制作电话本而特别设计的。

电话本的设计其实主要控制好关键字的问题,我使用了INI文件作为电话本存储的方式(以后上SQLite以后整体

的结构还是不会变)。时间是一个很好的关键字。永远不会重复,同时为电话记录提供了一个很好的标准和查

询的办法。具体的代码很简单。就几句话。

  1. void CiniRWtestDlg::OnTimer(UINT_PTR nIDEvent)
  2. {
  3. // TODO: 在此添加消息处理程序代码和/或调用默认值
  4. SYSTEMTIME showNowTime;
  5. //获取系统时间类
  6. GetLocalTime(&showNowTime);
  7. //获取本地时间
  8. CString TimeString;
  9. //转换
  10. CString temp,temp1,temp2,str1,str2;
  11. TimeString.Format(_T("%4d-%2d-%2d %2d:%2d:%2d")
  12. ,showNowTime.wYear
  13. ,showNowTime.wMonth
  14. ,showNowTime.wDay
  15. ,showNowTime.wHour
  16. ,showNowTime.wMinute
  17. ,showNowTime.wSecond);
  18. //定义时间格式
  19. //当前系统时间准确时间_tandow_2007-10-10_by_MercuryXu
  20. // other.....
  21. UpdateData(TRUE);//作用是实现数据的实时更新有效性
  22. m_timeshow = TimeString;
  23. UpdateData(FALSE);
  24. CDialog::OnTimer(nIDEvent);
  25. }
以上为获取时间的部分。

接下来就让时间循环下去。到OnInitDialog()中加一个SetTimer(1,1000,NULL);

你的时间就会在你定义的m_timeshow中跑起来了。另外

  1. m_timeshow可以是静态文本,可以是编辑框,这个随便你自己定义了。在VALUE中定义一个CString的就好了
  2. 很简单的。
 
Copyright © 阿肆 Mercury Xu