St.Dix的日记本

Hey! I am St.Dix, 3DGameProgramer, thankyou.

C++博客 首页 新随笔 联系 聚合 管理
  10 Posts :: 1 Stories :: 0 Comments :: 0 Trackbacks

2006年7月16日 #

动态连接库

在Win32环境下开发动态连接库(dlls)是不能简单的等同于Windows 3.x的。这是初始化和终止例程的区别:他们调用的频繁程度,传输的什么,和有多少代码必须用汇编语言编写。
‘在Win32 dll中,初始化和终止使用同样的一个函数句柄。在Windows 3.x中,必须提供初始化函数,并且如果提供了终止函数必须命名为WEP。
‘Win32初始化函数是一个新进程在任意时间或者一个附加线程第一次调用该DLL,并且当一个进程或线程终止时调用。而在Windows 3.x中,初始化和终止函数在DLL的生命期中仅能调用一次。
‘在Win32中,可以用c语言编写整个DLL(就像一个其他处理器的接口帮助推荐的那样)。在Windows 3.x中,链接成一个目标文件的启动代码是用汇编语言编写的。一个目标文件中的微软c/c++链接,LIBENTRY.OBJ,存取寄存器中信息和叫做LibMain的c代码的信息。在win32中,你不需要这个文件。
在Win32中,DLL初始化函数和终止函数相同。根据协议这个函数命名为DllMain。一个DWORD(32比特)类型的参数,dwReason,通知函数是初始化还是终止,和进程还是和线程有关。当一个进程第一次访问一个DLL,初始化函数通过process-atach被调用:这是假定一个进程有一个线程。如果这个存取来自另外的线程,函数通过thread-attach被调用。无论如何,在Win32下有通知仅仅因为线程绑定和分离。
Win32 DLL初始化函数应该返回1表示成功。返回NULL表示失败。Windows 3.x DLL初始化函数是使用下面的信息:
‘DLL的实例句柄
‘DLL数据段
‘DLL'DEF文件指定的堆大小
‘命令行
win32 Dll使用以下信息:
‘hModule参数,模块句柄
‘dwReason参数,一个枚举类型,表示LibMain程序被调用的四个原因:进程绑定,线程绑定,进程断开,线程断开。
‘lpRrserved参数,没有使用
定义Win32初始化函数应该像下面的代码:
BOOL APIENTRY DllMain( HANDLE hModule,
      DWORD dwReason,
      LPVOID lpReserved )
{
 switch( dwReason) {
 case DLL_PROCESS_ATTACH:
 ...
 case DLL_THREAD_ATTACH:
 ...
 case DLL_THREAD_DETACH:
 ...
 case DLL_PROCESS_DETACH:
 ...
 }
}
Win32模块句柄和Windows 3.x实例句柄有相同的用途。另外,Win32 DLL初始化函数不包括Windows 3.x的初始化参数。
DLL出口类
当你声明了一个类dllexport,它所有的成员函数和静态数据成员都被导出。你必须在同一个程序中提供所有这些成员的说明。另外,一个连接器错误产生。这个规则一个例外是纯虚函数。
译者注:声明一个dll函数的方法:
返回类型 APIENTRY 函数名(参数)
{……}

调用DLL函数
一旦你获得了dll函数的地址指针,你就可以用CallProcEx32W 或 CallProc32W从16位应用程序中调用他。你无法为 CallProc32W 创建一个原型,除非你做到了如下中的一点:
 ……
LoadLibraryEx函数
该函数将指定的可执行模块映射到调用进程的地址空间。可执行模块可以是.dll或.exe文件。该指定模块可能引起其他模块映射到这个地址空间。
HINSTANCE LoadLibraryEx(

    LPCTSTR lpLibFileName, //可执行模块的名称
    HANDLE hFile, // 保留,必须为NULL
    DWORD dwFlags  // 入口点执行标志
   );
参数说明
lpLibFileName
指向以null结尾的字符串,表示Win32可执行模块的名字。这个名字特指文件名。
dwFlags
可能是DONT_RESOLVE_DLL_REFERENCES LOAD_LIBRARY_AS_DATAFILE LOAD_WITH_ALTERED_SEARCH_PATH
该死的blog,没什么好写的,烦死了。

posted @ 2006-07-16 07:55 St.Dix 阅读(324) | 评论 (0)编辑 收藏

2006年6月14日 #

一、数字音频基础知识
Fourier级数:
任何周期的波形可以分解成多个正弦波,这些正弦波的频率都是整数倍。级数中其他正线波的频率是基础频率的整数倍。基础频率称为一级谐波。

PCM:
pulse code modulation,脉冲编码调制,即对波形按照固定周期频率采样。为了保证采样后数据质量,采样频率必须是样本声音最高频率的两倍,这就是Nyquist频率。
样本大小:采样后用于存储振幅级的位数,实际就是脉冲编码的阶梯数,位数越大表明精度越高,这一点学过数字逻辑电路的应该清楚。

声音强度:
波形振幅的平方。两个声音强度上的差常以分贝(db)为单位来度量,

计算公式如下:
20*log(A1/A2)分贝。A1,A2为两个声音的振幅。如果采样大小为8位,则采样的动态范围为20*log(256)分贝=48db。如果样本大小为16位,则采样动态范围为20*log(65536)大约是96分贝,接近了人听觉极限和痛苦极限,是再线音乐的理想范围。windows同时支持8位和16位的采样大小。

二、相关API函数,结构,消息
对于录音设备来说,windows 提供了一组wave***的函数,比较重要的有以下几个:

打开录音设备函数
MMRESULT waveInOpen(
LPHWAVEIN phwi, //输入设备句柄
UINT uDeviceID, //输入设备ID
LPWAVEFORMATEX pwfx, //录音格式指针
DWORD dwCallback, //处理MM_WIM_***消息的回调函数或窗口句柄,线程ID
DWORD dwCallbackInstance,
DWORD fdwOpen //处理消息方式的符号位
);
为录音设备准备缓存函数
MMRESULT waveInPrepareHeader( HWAVEIN hwi, LPWAVEHDR pwh, UINT bwh );
给输入设备增加一个缓存
MMRESULT waveInAddBuffer( HWAVEIN hwi, LPWAVEHDR pwh, UINT cbwh );
开始录音
MMRESULT waveInStart( HWAVEIN hwi );
清除缓存
MMRESULT waveInUnprepareHeader( HWAVEIN hwi,LPWAVEHDR pwh, UINT cbwh);
停止录音
MMRESULT waveInReset( HWAVEIN hwi );
关闭录音设备
MMRESULT waveInClose( HWAVEIN hwi );
Wave_audio数据格式
typedef struct {
WORD wFormatTag; //数据格式,一般为WAVE_FORMAT_PCM即脉冲编码
WORD nChannels; //声道
DWORD nSamplesPerSec; //采样频率
DWORD nAvgBytesPerSec; //每秒数据量
WORD nBlockAlign;
WORD wBitsPerSample;//样本大小
WORD cbSize;
} WAVEFORMATEX;
waveform-audio 缓存格式 
typedef struct {
LPSTR lpData; //内存指针
DWORD dwBufferLength;//长度
DWORD dwBytesRecorded; //已录音的字节长度
DWORD dwUser;
DWORD dwFlags;
DWORD dwLoops; //循环次数
struct wavehdr_tag * lpNext;
DWORD reserved;
} WAVEHDR;
相关消息 
MM_WIM_OPEN:打开设备时消息,在此期间我们可以进行一些初始化工作
MM_WIM_DATA:当缓存已满或者停止录音时的消息,处理这个消息可以对缓存进行重新分配,实现不限长度录音
MM_WIM_CLOSE:关闭录音设备时的消息。
相对于录音来说,回放就简单的多了,用到的函数主要有以下几个:
打开回放设备 
MMRESULT waveOutOpen(LPHWAVEOUT phwo, UINT uDeviceID, LPWAVEFORMATEX pwfx, DWORD dwCallback, DWORD dwCallbackInstance, DWORD fdwOpen );
为回放设备准备内存块 
MMRESULT waveOutPrepareHeader(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh );

写数据(放音) 
MMRESULT waveOutWrite(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh );
相应的也有三个消息,用法跟录音的类似:

三、程序设计

一个录音程序的简单流程: 打开录音设备waveInOpen===>准备wave数据头waveInPrepareHeader===>
准备数据块waveInAddBuffer===>开始录音waveInStart===>停止录音(waveInReset) ===>
关闭录音设备(waveInClose)
当开始录音后当buffer已满时,将收到MM_WIM_DATA消息,处理该消息可以保存已录好数据。

回放程序比这个要简单的多: 打开回放设备waveOutOpen===>准备wave数据头waveOutPrepareHeader===>写wave数据waveOutWrite===>
停止放音(waveOutRest) ===>关闭回放设备(waveOutClose)
如何处理MM消息: MSDN告诉我们主要有 CALLBACK_FUNCTION、CALL_BACKTHREAD、CALLBACK_WINDOW 三种方式,常用的是
Thread,window方式。
线程模式
waveInOpen(&hWaveIn,WAVE_MAPPER,&waveform,m_ThreadID,NULL,CALLBACK_THREAD),我们可以继承MFC的CwinThread类,只要相应的处理线程消息即可。
MFC线程消息的宏为:

ON_THREAD_MESSAGE,
可以这样添加消息映射: ON_THREAD_MESSAGE(MM_WIM_CLOSE, OnMM_WIM_CLOSE)
窗口模式
类似于线程模式,参见源程序即可

55555555 忘记是哪位大哥的作品了,不好意思.如果对该转载有异议,请速与本人联系.

posted @ 2006-06-14 18:29 St.Dix 阅读(427) | 评论 (0)编辑 收藏

2006年5月11日 #

今天跟Derek大哥讨论一道题,从一个DWORD里面提取后面三个char值。要求是,不能用汇编。我第一时间想到的是,memcpy()。然而,这仅仅是一个指针就能解决的问题。由于交叉存储,只需:
DWORD m;
char* pm;
pm=(char*)&m;
char a[3];
a[1]=*pm;
a[2]=*(++pm);
pm++;
a[0]=*(++pm);
其实,memcpy只是一个额外的函数调用,内部工作机制是相同的。
 *(char *)dst = *(char *)src;
 dst = (char *)dst + 1;
 src = (char *)src + 1;
这给我了n多的启示,在c++时代,人们都已经习惯了调用别人的函数,很少自己写算法了,这个习惯使我在不用汇编的情况下变得迟钝了很多,远离系统底层。我对内存结构,汇编等等还算是有些了解的,这些不应该不知道啊?!我们离那个底层透明的时代,真的是太远了,汗汗。
posted @ 2006-05-11 09:03 St.Dix 阅读(259) | 评论 (0)编辑 收藏

2006年5月8日 #

好久没有写过关于rendertosurface的程序,好怀念阿。
这个东东主要还是要用一个com接口,sdk说的很清楚,不过很可惜没有中文的。
ID3DXRenderToSurface 接口
该接口用来扩展渲染到表面的方法。
方法列表:
1,BeginScene 开始一个场景
HRESULT BeginScene(          LPDIRECT3DSURFACE9 pSurface,
    CONST D3DVIEWPORT9 *pViewport
);
第一个参数是指向IDirect3DSurface9接口的指针,第二个参数是指向D3DVIEWPORT9结构的指针。
这里需要具体说一下IDirect3DSurface9接口,应用程序通过它使用表面(surface)。
该接口的方法有:
GetContainer 这个方法在该表面作为cubemap或者mipmap贴图时使用,这里不再讨论。
GetDC 这个方法获得设备环境,可以将GDI方法应用在这里。
GetDesc 找回表面的描述。
LockRect 这是最重要的方法,锁定表面上的一个矩形区,然后就可以对这个区域进行读写操作。
HRESULT LockRect(          D3DLOCKED_RECT *pLockedRect,
    const RECT *pRect,
    DWORD Flags
);

关于Rect的详细定义:
typedef struct _D3DLOCKED_RECT {
    INT Pitch;
    void *pBits;
} D3DLOCKED_RECT;

RECT实际上是GDI的常用结构。
第三个参数是锁定标记,比较多,所有的数据区锁定都用这个标志。
ReleaseDC 释放设备环境。
UnlockRect 这个应该不用说,解锁表面。
这也是一个COM接口,需要包含d3d9.h。
2,EndScene 结束一个场景
3,GetDesc  找回渲染表面的参数
4,GetDevice 找回渲染表面相关的Microsoft® Direct3D®设备联合
5,OnLostDevice 释放所有涉及的视频内存资源并删除所有的状态块
6,OnResetDevice 重新设置之后必须调用
备注:
表面能够有许多方法使用包括作为渲染目标,离屏渲染,或者渲染成贴图。一个表面可以通过一个

特殊的视口初始化。 LPD3DXRENDERTOSURFACE 为指向该接口的指针。
typedef interface ID3DXRenderToSurface* LPD3DXRENDERTOSURFACE;
使用该接口需要包含d3dx9core.h并连接d3d9.lib,并且要在windows98以上操作系统运行。
那么如何渲染到这个表面呢?
哈哈,只要在BeginScene和EndScene之间加入普通的渲染函数,就一切ok。
可爱的rendertosurface可以制作动态贴图,可以实时生成立方体贴图,等等一堆超级cool的效果,哈哈。

posted @ 2006-05-08 17:40 St.Dix 阅读(1295) | 评论 (0)编辑 收藏

2006年5月7日 #

一次在qq群里面闲聊,讨论到了标准库的源代码,于是便仔细的看了看。
原来,VC里面就有这些源代码!而我竟然不知道,汗。
目录是vc安装目录:/vc98/crt/src目录,超级复杂。里面不但有标准库的C/C++源代码,还有一些VC自带的特殊函数。
比较有意思的有:memcpy函数的
/***
*memcpy.c - contains memcpy routine
*
*       Copyright (c) 1988-1997, Microsoft Corporation. All right reserved.
*
*Purpose:
*       memcpy() copies a source memory buffer to a destination buffer.
*       Overlapping buffers are not treated specially, so propogation may occur.
*
*******************************************************************************/

#include <cruntime.h>
#include <string.h>

#ifdef _MSC_VER
#pragma function(memcpy)
#endif  /* _MSC_VER */

void * __cdecl memcpy (
        void * dst,
        const void * src,
        size_t count
        )
{
        void * ret = dst;

#if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
        {
        extern void RtlMoveMemory( void *, const void *, size_t count );

        RtlMoveMemory( dst, src, count );
        }
#else  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }
#endif  /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */

        return(ret);
}
呵呵,非常有意思。但是,编译器在编译时,一般都会对这些函数作特殊的优化,基本都跟这些代码有着很大的不同了。

posted @ 2006-05-07 17:16 St.Dix 阅读(2285) | 评论 (0)编辑 收藏

2006年5月5日 #

依然是先看图
black_cat_互操作.jpg

域操作是重要内容.虽然看起来很复杂.但是实际上没这么困难的啦.无非是多加入一个列表,可以用密码访问公共信息罢了.

posted @ 2006-05-05 07:51 St.Dix 阅读(190) | 评论 (0)编辑 收藏

还是先看图
black_cat_.jpg

跳跃次数限制,指的是从自己开始,经过一个节点转发一次.这个呈几何级数增长.设置大了只能让你自己搜索延迟.没有更多的好处.偏离了范围内有效搜索的主题.而且结果往往会是你"得不到的"
所以做好限制是有必要的.除了跳跃次数限制之外,还有一个超时设置.结果集大小限制.都是为了方便快速得到"想要的"数据.这一部分可以更加详细的优化,提供更多的可选参数来描述.

导出结果,形式,方法,接口 都是统一的.因为我们做的是一个平台.可以继续为其他软件提供文件检索服务.
posted @ 2006-05-05 07:47 St.Dix 阅读(230) | 评论 (0)编辑 收藏

先看图black_cat.jpg


红色的惊叹号表示前期要完成的任务,电灯泡表示留下接口,以后完善.

这个已经很明显了,说明我们的搜索,搜索哪些内容.如果脱机工作.只能搜索永久性媒体.
一旦联网,我们可以提供虚拟目录发布共享信息,提供给他人检索(包括自己,比如bt种子列表)
如果你的好友或者您所在的组织都有类似的共享信息,那么你可以添加到搜索列表去那个组织寻找结果

posted @ 2006-05-05 07:23 St.Dix 阅读(208) | 评论 (0)编辑 收藏

让我恰当的描述这个是什么还有些困难.因为不知道从哪里开始说起
一开始想的是<<光盘搜索系统>>但是这个名字怎么听怎么像小学生毕业设计里的内容.前期还有一个叫<<DVD Library>>的Project,但是跟它重复,就流产了.

它的主要功能:
      在指定的范围内建立文件索引,提供文件搜索服务.并且以多种结果集反馈给请求提交者.

面向的使用对象:
      个人,好友之间,各种同好会,以及公司企业.

搜索范围:
      个人单机,好友之间,有管理组织的群.

目标:
      建立一个统一的开房的平台,其他程序可以直接利用它的搜索功能实现资源定位.它将会支持web搜索,webService接口,以及RSS.等.

主要用途:
      个人光盘管理,FTP索引,BT ED资源索引,为下载工具提供有效源参考

与其他搜索有什么不同:
      Windows的搜索主要侧重本机,而且由于操作系统对安全隐私有很大的限制,而且配置复杂,不适合交流,而且基本上不能管理光盘信息
      Google桌面搜索.虽然搜索丰富了很多.但是还是侧重本机.没有交流的部分
      其他光盘管理软件 没有交流部分,不提供多种源,单用户.

它做的是什么搜索:
      首先,它做的不是爬虫!没有那么多资源提供给他爬!我们是想做一个个人收藏文件的索引,可以知道我这个文件放在了哪里.或者我想要的文件,我的朋友们有没有,如何得到它.比如我是字幕组成员,可能需要一个视频文件,而且还必须是最新的清晰版本.现在这个文件在谁那里?FTP有没有?或者是否有人刻录到光盘了?如何得到它?或者BT ED是不是能得到相同的东西? 这个是我们解决的问题.

为什么叫"黑猫"?
      本来叫<<光盘管理系统>>但是.....但是.....
      为了体现它的特色,不能叫上面那个名字.我们面向的是多用户,群组,多方式.最终目标是找到所需的文件.往往这些文件的人工检索会耗费一定大脑跟时间的.所以聊天的时候用 猫捉老鼠 来形容发现比较合适.你描述一下想要的特点,提交给黑猫, 发现一个有效源,成为发现一只"老鼠" ,不光自己这里,也可以联系"猫猫工会" 去搜索这样的老鼠......

临时添加这些内容,以后可能会添加附加功能,但是基本功能一般不会变了.至少对于用户感受来说
posted @ 2006-05-05 07:17 St.Dix 阅读(271) | 评论 (0)编辑 收藏

2006年5月4日 #

   好像我说过不写Blog的,不过不小心,就把项目Blog写错了。为了不给人家添麻烦,我就努力一点,写写这个东东,哈哈。

posted @ 2006-05-04 15:30 St.Dix 阅读(230) | 评论 (0)编辑 收藏

仅列出标题