posts - 62,  comments - 19,  trackbacks - 0
[问题]
通常我们按下CTRL+ATL+DEL组合键后,可以看到正在运行的程序或者进程,有没有办法让程序从CTRL+ATL+DEL消失掉呢?也就是说让正在运行的程序对CTRL+ATL+DEL不可见。
[解答]
答案是肯定的,办法如下:
使用Win32 API 函数RegisterServiceProcess,但是这个API函数的文档你是很难找到的。这里我们要用一下汇编。

#include <windows.h>

HINSTANCE hLibrary;
void *regproc;

void CADInit(void);
void HideApp(void);
void ShowApp(void);
void CADClean(void);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  CADInit(); //加载 DLL 并创建一指向它指针
  HideApp(); //隐藏程序
  //ShowApp(); //显示程序

  //其他处理或调用
  
  CADClean(); //卸载 DLL
  return 0; //retrun 0 因为没有进入消息循环
}

void CADInit(void)
{
  //加载 kernel32.dll
  hLibrary = LoadLibrary("kernel32.dll");
  //获取函数RegisterServiceProcess的地址
  regproc = GetProcAddress(hLibrary, "RegisterServiceProcess");
}

void HideApp(void)
{
  //实现程序的隐藏
  __asm
  {
   push 1
   push 0
   call regproc
  }
  return;
}

void ShowApp(void)
{
  //恢复状态
  __asm
  {
      push 0
      push 0
      call regproc
  }
  return;
}

void CADClean(void)
{
  //卸载 DLL
  FreeLibrary(hLibrary);
  return;
}
本程序在W2K和Win9x测试通过。
posted @ 2007-04-09 14:51 乔栋 阅读(735) | 评论 (0)编辑 收藏
一、数字音频基础知识
  • 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位的采样大小。



posted @ 2007-04-09 14:50 乔栋 阅读(649) | 评论 (0)编辑 收藏

问题:
对button,我直接用WM_COMMAND是可以的。 现在我想尝试使用VC的ON_NOTIFY,怎么试也不起作用。

解答:
ON_NOTIFY是针对WM_NOTIFY的消息宏,而WM_NOTIFY是针对 
ListCtrl,TreeCtrl,TabCtrl等通用控件使用的消息 
button,listbox等基本控件是不会用到这个消息的 .

 

posted @ 2007-04-09 10:12 乔栋 阅读(4377) | 评论 (0)编辑 收藏




http://blog.csdn.net/ruibird/archive/2007/03/31/1547882.aspx




posted @ 2007-04-05 11:18 乔栋 阅读(233) | 评论 (0)编辑 收藏


http://www.vckbase.com/document/viewdoc/?id=957




posted @ 2007-04-05 11:16 乔栋 阅读(155) | 评论 (0)编辑 收藏

DICOM 标准包括以下内容:
PS 3.1: Introduction and Overview (引言和概述);
PS 3.2: Conformance(一致性);
PS 3.3: Information Object Defini-tions(信息对象定义);
PS 3.4: Service Class Specifications (服务类规范);
PS 3.5: Data Structure and Encod-ing: (数据结构和编码规定);
PS 3.6: Data Dictionary(数据字典);
PS 3.7: Message Exchange(信息交换);
PS 3.8: Network Communication Support for Message Exchange(信息交换的网络通讯支持);
PS 3.9: Point-to-Point Communi-cation Support for Message Exchange (信息交换的点对点通讯支持);
PS 3.10: Media Storage and File Format for Data Interchange(便于数据交换的介质存储方式和文件格式);
PS 3.11: Media Storage Application Profiles(介质存储应用框架);
PS 3.12: Storage Functions and Media Formats for Data Interchange(便于数据交换的存储方案和介质格式);
PS 3.13: Print Management Point-to-Point Communication Support(打印管理的点对点通讯支持)。



DICOM 涵盖了数字图像信息构成和通信两个领域,内容极其烦琐、庞大,目前没有任何医学系统可以
支持所有的DICOM 服务,每一种设备都是只针对自己最需要的部分提供支持。我们也根据核医学的需
要,制定了自己的符合DICOM 标准的图像文件格式。其中核医学图像文件结构部分主要参阅了DICOM
标准的PS 3.3~PS 3.6 和PS 3.10。

其中规定了Patient、Study、Series、Image 四个层次的医学图像
信息结构,以及由它们组成的信息对象(Informa-tion Object); 采用服务类客户/服务类提供者(Service
Class User/Service Class Provider)概念组成的服务—对象对(Service-Object Pair); 支持点对点(PPP)和
TCP/IP 网络通信协议。

DICOM 文件一般由一个DICOM 文件头和一个DICOM 数据集合组成。DICOM 数据集合是按照DICOM 标准的PS 3.5 部分来编码组成的.

在DICOM 文件中最基本的单元是数据元素(Data Element)。DICOM 数据集合就是由DICOM 数据元素
按照一定的顺序排列组成的。
DICOM 数据元素的组成主要由四个部分组成: 标签、VR (Value Representation,数据描述)、数据长度和数据域。
(1) 标签是一个4 字节的无符号整数。DICOM 所有的数据元素都可以用标签来唯一表示,各个标签对
应什么数据元素可以查阅DICOM 标准PS 3.6 部分—数据字典。
在DICOM 中人为地将标签分为两个部分: 组号(高位2 字节)和元素号(低位2 字节),在数据字典中所有
的元素都是用“(组号,元素号)”这种方式来表示的。
(2) VR 指明了该数据元素中的数据是哪种类型的。在DICOM 文件中,它是一个长度为2 的字符串,例
如,如果一个数据元素的VR 为“DA”,则表示该数据元素中存储的数据为日期型数据,如果一个数据
元素的VR 为“FL”则表示该数据元素中存储的数据为浮点型数据。关于VR 的详细取值和说明可以参阅
DICOM 标准PS 3.5 部分第15~21 页的表6.2-1。
在数据元素中,VR 是可选的,它取决于协商的传输数据格式。DICOM 中规定了显式(Explicit VR)和隐
式(Inexplicit VR)两种传输格式,其中在显式传输时,VR 必须存在; 在隐式传输时,VR 必须省略。表1
和表2 是显式传输时数据元素的格式,表3 为隐式传输时数据元素的格式。
(3) 数据长度指明该数据元素的数据域中数据的长度(字节数)。
(4) 数据域中包含了该数据元素的数值。

DICOM 文件头
DICOM 文件头(DICOM File Meta Information)包含了标识数据集合的相关信息。每个DICOM 文件都必
须包括该文件头。文件头的最开始是文件前言,它由128 个00H 字节组成,接下来是DICOM 前缀,它
是一个长度为4 字节的字符串“DICM”,可以根据该值来判断一个文件是不是DICOM 文件。
文件头中
还包括其它一些非常有用的信息,如文件的传输格式、生成该文件的应用程序等等,关于文件头详细的
说明请参阅DICOM 标准PS 3.10 的13~14 页表7.1-1。
说明:
(1) 除了128 字节的文件前言和4 字节的DICOM 前缀外,所有其它的文件头元素都必须采用上面介绍
的显示格式编码,各个数据元素排列的顺序按照标签数值从小到大的传输格式(Little Endian)编码。
(2) 每个文件头元素的长度必须为偶数,否则应该按照规定补充一个字节。
(3) 所有(0002,****)类的标签都为DICOM 所保留。为了兼容后续版本,如果发现文件中有目前尚未
规定的(0002,****)类标签,则应该忽略它。

DICOM 数据集合
DICOM 文件主要组成部分就是数据集合。这不仅包括医学图像,还包括许多和医学图像有关的信息,
如病人姓名、图像大小等。

表中“使用”列为“M”时表示该模块必须存在,“U”表示可选,“C”表示在特定的情况下必须存在。
例如在制定Patient 模块时,查阅DICOM 标准PS 3.3 部分的C.7.1.1 小节,可以查到的病人模块属性表.


&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&



posted @ 2007-04-03 10:02 乔栋 阅读(1315) | 评论 (2)编辑 收藏
   技术类:                                                                    非技术类:
   深入浅出MFC                                                         余秋雨
   规定每天看够30~50页.至少看够30页               <<千年一叹>>

    .NET框架                                                                  茅于轼
    等待上本看完后再定进度.                                    <<生活中的经济学>>


    重构(优化现有代码设计)                                       <<张居正>>
     等待上奔看完后再定进度
posted @ 2007-04-02 11:05 乔栋 阅读(91) | 评论 (0)编辑 收藏

  @echo off

  echo 正在清除系统垃圾文件,请稍等......

  del /f /s /q %systemdrive%\*.tmp

  del /f /s /q %systemdrive%\*._mp

  del /f /s /q %systemdrive%\*.log

  del /f /s /q %systemdrive%\*.gid

  del /f /s /q %systemdrive%\*.chk

  del /f /s /q %systemdrive%\*.old

  del /f /s /q %systemdrive%\recycled\*.*

  del /f /s /q %windir%\*.bak

  del /f /s /q %windir%\prefetch\*.*

  rd /s /q %windir%\temp & md %windir%\temp

  del /f /q %userprofile%\COOKIES s\*.*

  del /f /q %userprofile%\recent\*.*

  del /f /s /q "%userprofile%\Local Settings\Temporary Internet Files\*.*"

  del /f /s /q "%userprofile%\Local Settings\Temp\*.*"

  del /f /s /q "%userprofile%\recent\*.*"

  sfc /purgecache '清理系统盘无用文件

  defrag %systemdrive% -b '优化预读信息

  echo 清除系统LJ完成!

  echo. & pause






posted @ 2007-03-30 17:18 乔栋 阅读(397) | 评论 (0)编辑 收藏
作为程序员,平时最担心见到的事情就是程序发生了崩溃,无论是指针越界还是非法操作,都将给我们的应用系统造成巨大的损失。但在一个大型系统的测试过程中,初期出现程序崩溃似乎成了不可避免的事。其实测试中出现程序崩溃并不可怕,反而是测试的成功。我们更为关心的是程序中的哪一行导致了系统崩溃,这样我们才能有针对性的进行改正。
  在VC中,我们可以利用出现程序崩溃时VC的自动跳转,定位到出错代码行。但在大量的压力测试时,尤其是多线程测试时,同时出现几十个错,这时VC本身的出错跳转往往会失灵。
  在这里我们介绍一种辅助查找程序崩溃代码行的好方法,它的核心就是利用编译时生成MAP文件中的信息来定位代码行。
下面就开始我们的介绍。
  首先我们必须生成程序的MAP文件。那么什么是 MAP 文件呢?简单地讲, MAP 文件是程序的全局符号、源文件和代码行号信息的唯一的文本表示方法,是整个程序工程信息的静态文本。它可以在任何地方、任何时候使用,不需要有额外的程序进行支持,仅仅通过一个文本阅读工具如Ultra Edit就可以打开了。而且,这是唯一能找出程序崩溃代码行的救星。
  那么我们应该如何生成MAP文件呢?在 VC 中,我们可以按下 Alt+F7,打开“Project Settings”选项页,选择 C/C++ 选项卡,并在最下面的 Project Options 里面输入:/Zd ,然后要选择 Link 选项卡,选中“Generate mapfile”复选框,并在最下面的 Project Options 里面输入:/mapinfo:lines,表示生成 MAP 文件时,加入行信息。最后按下 F7 来编译生成 EXE 可执行文件和 MAP 文件,此时可以在工程的Debug目录下找到刚刚生成的MAP文件,文件名为“工程名.map”。
  通过上面的步骤,已经得到了 MAP 文件,那么我们该如何利用它呢?让我们从一个简单的实例入手,一步一步演示使用MAP文件定位程序崩溃行的过程。
首先假设我们的VC工程中有下面这个文件:
//*****************************************************
// 程序名称:演示如何通过崩溃地址找出源代码的出错行
// 作者:刘可
// 日期:2003-6-19
// 本程序会产生“除0错误”,所以会导致
// 程序崩溃,弹出“非法操作”对话框。
//******************************************************
#include

int crashtest(int a,int b)
{
int c;
c = a/b;
return c;
}

void main(void)
{
int a = 30;
int b = 0;
int ret;
printf("let's begin crash test...\n");
ret = crashtest(a,b);
}

很显然本程序有“除0错误”,在 Debug 方式下编译,运行时会产生“非法操作”。我们记录下产生崩溃的地址——在我的机器上是 0x0040102f 。这个在不同的机器上可能地址不同,但记下这个地址我们下面将要使用。
我们打开它的 MAP 文件:(这里列出我们比较关心的内容,其他的就略过了)

abort(工程名)

Timestamp is 3ef16533 (Thu Jun 19 15:24:35 2003)

Preferred load address is 00400000

Start    Length    Name        Class
0001:00000000 0001081dH .text        CODE
0002:00000000 000013baH .rdata        DATA
0002:000013ba 00000000H .edata        DATA
0003:00000000 00000104H .CRT$XCA       DATA
0003:00000104 00000104H .CRT$XCZ       DATA
0003:00000208 00000104H .CRT$XIA       DATA
0003:0000030c 00000109H .CRT$XIC       DATA
0003:00000418 00000104H .CRT$XIZ       DATA
0003:0000051c 00000104H .CRT$XPA       DATA
0003:00000620 00000104H .CRT$XPX       DATA
0003:00000724 00000104H .CRT$XPZ       DATA
0003:00000828  00000104H .CRT$XTA       DATA
0003:0000092c  00000104H .CRT$XTZ       DATA
0003:00000a30  00003236H .data        DATA
0003:00003c68  000019c8H .bss        DATA
0004:00000000  00000014H .idata$2       DATA
0004:00000014  00000014H .idata$3       DATA
0004:00000028  00000120H .idata$       DATA
0004:00000148  00000120H .idata$5        DATA
0004:00000268  000004f4H .idata$6       DATA

Address Publics by Value Rva+Base Lib:Object

0001:00000020 ?crashtest@@YAHHH@Z 00401020 f main.obj
0001:0000003c _main 0040103c f main.obj
0001:000000b0 _printf 004010b0 f LIBCD:printf.obj
0001:00000130 __chkesp 00401130 f LIBCD:chkesp.obj
0001:00000170 _mainCRTStartup 00401170 f LIBCD:crt0.obj
0001:000002a0 __amsg_exit 004012a0 f LIBCD:crt0.obj
0001:00000300 __stbuf 00401300 f LIBCD:_sftbuf.obj
0001:00000460 __ftbuf 00401460 f LIBCD:_sftbuf.obj
0001:00000520 __output 00401520 f LIBCD:output.obj
0001:000013c0 ___initstdio 004023c0 f LIBCD:_file.obj
0001:000014f0 ___endstdio 004024f0 f LIBCD:_file.obj
0001:00001510 __CrtDbgBreak 00402510 f LIBCD:dbgrpt.obj
0001:00001520 __CrtSetReportMode 00402520 f LIBCD:dbgrpt.obj
0001:00001580 __CrtSetReportFile 00402580 f LIBCD:dbgrpt.obj
0001:00001600 __CrtSetReportHook 00402600 f LIBCD:dbgrpt.obj
0001:00001620 __CrtDbgReport 00402620 f LIBCD:dbgrpt.obj

  如果仔细浏览 Rva+Base 这栏,我们可以发现第一个比崩溃地址 0x0040102f 大的函数地址是 0x0040103c ,所以在 0x0040103c 这个地址之前的那个入口就是产生崩溃的函数,也就是这行:

0001:00000020 ?crashtest@@YAHHH@Z 00401020 f main.obj

  因此,发生崩溃的函数就是 ?crashtest@@YAHHH@Z,所有以问号开头的函数名称都是 C++ 修饰的名称。所以在我们的源程序中,这个发生崩溃的函数就是 crashtest ()!

  现在我们便轻而易举地知道了发生崩溃的函数名称。把它记下来,然后我们将要直接定位发生崩溃的代码行了。我们注意 MAP 文件的最后部分——代码行信息(Line numbers information),它是以这样的形式显示的:

Line numbers for .\Debug\main.obj(D:\我的工作\技术\出异常例子abort\main.cpp) segment .text

12 0001:00000020 14 0001:0000002b 15 0001:00000035 16 0001:00000038
19 0001:0000003c 20 0001:00000057 21 0001:0000005e 23 0001:00000065
24 0001:00000072 25 0001:00000085

  第一个数字代表在源代码中的代码行号,第二个数是该代码行在所属的代码段中的偏移量。如果要查找代码行号,需要使用下面的公式做一些十六进制的减法运算:

崩溃行偏移 = 崩溃地址(Crash Address)- 基地址(ImageBase Address)- 0x1000

  为什么要这样做呢?因为我们得到的崩溃地址都是由 偏移地址(Rva)+ 基地址(Base)得来的,所以在计算行号的时候要把基地址减去。一般情况下,基地址的值是 0x00400000 。另外,由于一般的 PE 文件的代码段都是从 0x1000 偏移开始的,所以也必须减去 0x1000 。
  所以我们的:崩溃行偏移 = 0x0040102f - 0x00400000 - 0x1000 = 0x2f
我们在MAP 文件的中的代码行信息里查找不超过计算结果0x2f,但却最接近的数。发现是 main.cpp 文件中的:

14 0001:0000002b

  也就意味着在源代码中的第 14 行!让我们来看看源代码,注意注释行和空行也要计算在内,程序的第14行为:

c = a/b;

果然就是第 14 行啊,它发生了“除0异常”!

  方法已经介绍完了,从今以后,我们就可以精确地定位到源代码中的崩溃行,而且只要编译器可以生成 MAP 文件,无论在WIN平台还是UNIX平台,本方法都是适用的。
  本文我们只是列举了一个非常简单的“除0异常”例子,使用MAP文件的效力或许还不十分明显。但相信在我们的大型应用系统调试中,使用MAP文件的辅助方法来快速定位发生程序崩溃的函数以及代码行,将会为我们的程序调试工作节省大量时间和精力,提高我们的调试质量。我们甚至可以要求远地用户直接提供程序崩溃的地址,然后就可以在自己机器上利用MAP文件静态地找到出错的那行,并在程序中进行相应修正了。

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

VC7下运行OK.


posted @ 2007-03-26 10:37 乔栋 阅读(776) | 评论 (0)编辑 收藏
从前,现在,将来

从前的我,热衷于收集网络上所有我可能会用到的技巧,并为能在自己的作品中出现这样的技巧而兴奋不已.

现在的我,热衷于看别人写下的文章,并尝试理解它的意义,迅速的记录下来,并且更加迅速的忘掉.

将来的我......

我想,将来应该尝试去写一些这样的文章,去以一个书写者的角度来观感别人的作品,或许更有收获.


从前的我,不知道自己是不是能当一个好程序员.

现在的我,知道自己可以作一个好程序员,但是不知道下来怎么办.

将来的我.......

不知道.

从前的我,热衷社交,喜欢琢磨穿着饮食.

现在的我,更加喜欢耐脏而朴素的衣服,更加顺口健康的食品,当然,越廉价越好

将来的我.......

也许,会追求时装会品位美食,也可能会更喜欢朴素的衣服,和健康而廉价的食品.

从前,我没有这样的文字.

现在,我尝试将这样劈为横枝竖条的烂木头一样文字组合起来,却为其轰然倒塌而沮丧不已.

将来,我会写出更好的更满意的文字去记录这些历程,像大厦一样坚固.
posted @ 2007-03-25 22:57 乔栋 阅读(897) | 评论 (2)编辑 收藏
仅列出标题
共7页: 1 2 3 4 5 6 7 
<2007年8月>
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(6)

随笔分类

随笔档案

文章分类

文章档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜


My blog is worth $0.00.
How much is your blog worth?