若我的小家

-编程,读书,感悟,旅游,设计
posts - 21, comments - 0, trackbacks - 0, articles - 0

Q 在NT/2000/XP中,我想用VC编写应用程序访问硬件设备,如获取磁盘参数、读写绝对扇区数据、测试光驱实际速度等,该从哪里入手呢?

A 在NT/2000/XP中,应用程序可以通过API函数DeviceIoControl来实现对设备的访问—获取信息,发送命令,交换数据等。利用该接口函数向指定的设备驱动发送正确的控制码及数据,然后分析它的响应,就可以达到我们的目的。

DeviceIoControl的函数原型为

BOOL DeviceIoControl(
HANDLE hDevice,              // 设备句柄
DWORD dwIoControlCode,       // 控制码
LPVOID lpInBuffer,           // 输入数据缓冲区指针
DWORD nInBufferSize,         // 输入数据缓冲区长度
LPVOID lpOutBuffer,          // 输出数据缓冲区指针
DWORD nOutBufferSize,        // 输出数据缓冲区长度
LPDWORD lpBytesReturned,     // 输出数据实际长度单元长度
LPOVERLAPPED lpOverlapped    // 重叠操作结构指针
);

设备句柄用来标识你所访问的设备。

发送不同的控制码,可以调用设备驱动程序的不同类型的功能。在头文件winioctl.h中,预定义的标准设备控制码,都以IOCTL或FSCTL开头。例如,IOCTL_DISK_GET_DRIVE_GEOMETRY是对物理驱动器取结构参数(介质类型、柱面数、每柱面磁道数、每磁道扇区数等)的控制码,FSCTL_LOCK_VOLUME是对逻辑驱动器的卷加锁的控制码。

输入输出数据缓冲区是否需要,是何种结构,以及占多少字节空间,完全由不同设备的不同操作类型决定。在头文件winioctl.h中,已经为标准设备预定义了一些输入输出数据结构。重叠操作结构指针设置为NULL,DeviceIoControl将进行阻塞调用;否则,应在编程时按异步操作设计。

Q 设备句柄是从哪里获得的?

A 设备句柄可以用API函数CreateFile获得。它的原型为

HANDLE CreateFile(
LPCTSTR lpFileName,                         // 文件名/设备路径
DWORD dwDesiredAccess,                      // 访问方式
DWORD dwShareMode,                          // 共享方式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全描述符指针
DWORD dwCreationDisposition,                // 创建方式
DWORD dwFlagsAndAttributes,                 // 文件属性及标志
HANDLE hTemplateFile                        // 模板文件的句柄
);

CreateFile这个函数用处很多,这里我们用它“打开”设备驱动程序,得到设备的句柄。操作完成后用CloseHandle关闭设备句柄。

与普通文件名有所不同,设备驱动的“文件名”(常称为“设备路径”)形式固定为“\\.\DeviceName”(注意在C程序中该字符串写法为“\\\\.\\DeviceName”),DeviceName必须与设备驱动程序内定义的设备名称一致。

一般地,调用CreateFile获得设备句柄时,访问方式参数设置为0或GENERIC_READ|GENERIC_WRITE,共享方式参数设置为FILE_SHARE_READ|FILE_SHARE_WRITE,创建方式参数设置为OPEN_EXISTING,其它参数设置为0或NULL。

Q 可是,我怎么知道设备名称是什么呢?

A 一些存储设备的名称是微软定义好的,不可能有什么变化。大体列出如下
软盘驱动器 A:, B:
硬盘逻辑分区 C:, D:, E:, ...
物理驱动器 PHYSICALDRIVEx
CD-ROM, DVD/ROM CDROMx
磁带机 TAPEx

其中,物理驱动器不包括软驱和光驱。逻辑驱动器可以是IDE/SCSI/PCMCIA/USB接口的硬盘分区(卷)、光驱、MO、CF卡等,甚至是虚拟盘。x=0,1,2 ……

其它的设备名称需通过驱动接口的GUID调用设备管理函数族取得,这里暂不讨论。

Q 请举一个简单的例子说明如何通过DeviceIoControl访问设备驱动程序。

A 这里有一个从MSDN上摘抄来的demo程序,演示在NT/2000/XP中如何通过DeviceIoControl获取硬盘的基本参数。

/* The code of interest is in the subroutine GetDriveGeometry. The
                code in main shows how to interpret the results of the IOCTL call. */
                #include <windows.h>
                #include <winioctl.h>
                BOOL GetDriveGeometry(DISK_GEOMETRY *pdg)
                {
                HANDLE hDevice;               // handle to the drive to be examined
                BOOL bResult;                 // results flag
                DWORD junk;                   // discard results
                hDevice = CreateFile("\\\\.\\PhysicalDrive0",  // drive to open
                0,                // no access to the drive
                FILE_SHARE_READ | // share mode
                FILE_SHARE_WRITE,
                NULL,             // default security attributes
                OPEN_EXISTING,    // disposition
                0,                // file attributes
                NULL);            // do not copy file attributes
                if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
                {
                return (FALSE);
                }
                bResult = DeviceIoControl(hDevice,     // device to be queried
                IOCTL_DISK_GET_DRIVE_GEOMETRY,     // operation to perform
                NULL, 0,               // no input buffer
                pdg, sizeof(*pdg),     // output buffer
                &junk,                 // # bytes returned
                (LPOVERLAPPED) NULL);  // synchronous I/O
                CloseHandle(hDevice);
                return (bResult);
                }
                int main(int argc, char *argv[])
                {
                DISK_GEOMETRY pdg;            // disk drive geometry structure
                BOOL bResult;                 // generic results flag
                ULONGLONG DiskSize;           // size of the drive, in bytes
                bResult = GetDriveGeometry (&pdg);
                if (bResult)
                {
                printf("Cylinders = %I64d\n", pdg.Cylinders);
                printf("Tracks per cylinder = %ld\n", (ULONG) pdg.TracksPerCylinder);
                printf("Sectors per track = %ld\n", (ULONG) pdg.SectorsPerTrack);
                printf("Bytes per sector = %ld\n", (ULONG) pdg.BytesPerSector);
                DiskSize = pdg.Cylinders.QuadPart * (ULONG)pdg.TracksPerCylinder *
                (ULONG)pdg.SectorsPerTrack * (ULONG)pdg.BytesPerSector;
                printf("Disk size = %I64d (Bytes) = %I64d (Mb)\n", DiskSize,
                DiskSize / (1024 * 1024));
                }
                else
                {
                printf("GetDriveGeometry failed. Error %ld.\n", GetLastError());
                }
                return ((int)bResult);
                }
                

posted @ 2008-09-23 13:04 若我 阅读(117) | 评论 (0)编辑 收藏

C++位操作包括两种:传统的C语言方式的位操作和C++中利用bitset容器的位操作
   
一、传统的C方式位操作:
1.基本操作:
   使用一个unsigned int变量来作为位容器。
2.操作符:
|   按位或操作符:result=exp1|exp2;当exp1和exp2中对应位中至少有一个为1时,result中对应位为1,否则为0。
&  按位与操作符::result=exp1&exp2;当exp1和exp2中对应位全为1时,result中对应位为1,否则为0。
^  按位异或或操作符:result=exp1^exp2;当exp1和exp2中对应位不相同时,result中对应位为1,否则为0。
~  反转操作符:将位容器中的所有位都反转,1变为0,0变为1。
<< 按位左移操作符:exp<<n,将容器中所有的位向左移n位,空出的位用0填充。
>> 按位右移操作符:exp>>n,将容器中所有的位向右移n位,空出的位用0填充。
|=,&=,^= 分别对应|&^三种操作符的复合操作符。
3.常用操作
   这里我们假设有一个result的unsigned int变量用来储存32个学生的成绩(通过和不通过分别用0和1),这样result就有33位(result从右至左,从0开始计算位数,在这个例子中0位被浪费)。
(a) 将第27位设置为及格(设作1)其他位不变:
   result|=(1<<27) //任意的位值与1作按位或操作其值为1,而与0作按位与操作其值不变
(b) 将第27位设置成不及格(设为0)。
   result&=~(1<<27) //任意的位值与0作按位与操作其值为0,而与1作按位与操作其值不变
(c) 反转第27位的值。
   result^=(1<<27) //任意的位值与1作按位异或操作其值为1,而与0作按位异与操作其值不变
 
二、C++中的bitset容器
1.头文件:
  #include <bitset>
2.声明一个容器:
 (a)声明一个指定位数的空容器(所有位设为0): bitset<int> bits;
 (b)声明一个指定位数并将指定的几个位初始化为相应值的容器: bitset<n> bits(int);
     bitdet<int> bits(string&)
总结:bitset模板类中类型参数传递容器的位数,而构造函数参数通过一个int或一个string&值来从右至左初始化容器中的相应值。
3.bitset的基本用法:
4.bitset与传统C位操作及字符串的转换
   可以通过to_string()成员将容器转输出为一个string字符串,另外还可以用to_long()成员将容器输出到传统的用于C风格的位容器中。如:
  unsigned long bits = bits.to_long();
  sting str(bits.to_string());
5.bitset支持所有的位操作符。

posted @ 2008-09-22 16:58 若我 阅读(139) | 评论 (0)编辑 收藏

Installing Ubuntu 8.04 under Microsoft Virtual PC 2007

I’m pleased to say that Ubuntu 8.04 is probably the easiest install I’ve had to do with VPC yet! One quick reminder before we begin, when working inside the VPC your mouse will get “trapped” or captured by the virtual computer. You won’t be able to move outside of it. To get it released, just press the RIGHT side ALT key. Left side won’t work, has to be the RIGHT side of your keyboard.

To start with, create a new Virtual PC. For a tutorial, see either my step by step tutorial or the video tutorial if you need more instructions. Since I had the space, I was using 768 meg of ram, and left the disk space at the default of 16 gig. If you can, try and use at least 512 meg of ram for good performance. Use the CD menu option to capture the desktop ISO you downloaded from Ubuntu, or if you have a real CD put it in the drive and capture that. When it launches, you’ll see this screen. (By the way, you can click on any of the screens to see the full size graphic, these have been resized slightly to fit in with most common browser sizes).

[image - Select Language]

Pick your language, I just took the default of English.

[image - Safe graphics mode]

Now press F4 to select an alternate starting mode. When it pops up, change to Safe graphics mode, as you see above, and press Enter. Now pick “Try Ubuntu…” (should already be selected) and press enter. Do NOT pick the Install Ubuntu option, I kept getting VPC errors when trying to install directly.

Additionally, don’t be alarmed if the screen goes black for a while, then you see some garbled graphics. This is perfectly normal, it is just passing through and will be OK when Ubuntu gets done doing it’s thing. It took me about 7 minutes to get from the previous screen to the next one.

[image - live environment]

After it boots you should be in the live session trial environment. Double click the Install icon to begin the install process.

[image - Installer welcome screen]

Screen 1 is just a welcome screen, although you can change your language here if you need to. Press Forward to continue.

[image - Installer Set Time Zone]

Next it wants to know where you are, at least time zone wise. I’m in the central time zone, but set yours appropriately and click Forward.

[image - Installer Pick your Keyboard]

Next you can specify your keyboard. Since I’m using a typical USA style keyboard, I just clicked Forward.

[image - Installer Prepare Disk Space]

Next it asks how you want your disk space partitioned. Since we’re in a virtual environment, it made the most sense to just take the defaults and click Forward.

Be aware, after clicking forward my mouse went into the “I’m busy” mode, and there was a delay while the disks were prepared. Mine went about five minutes. Don’t be alarmed, just wait a few minutes and you’ll then proceed to the next screen.

[image - Installer Who Are You]

On this screen, first supply your name; this will be used in documents and the like. The next text box is the important one - it is for your Ubuntu user name. By default it uses your first name, now is your chance to change it. I rather like mine so will accept it. Next you’ll need to key in a good password and confirm, and finally name the computer. When you are happy, click Forward.

Now is where you may get confused. In the screen above, you are on step 5 of 7. When you click forward, you are suddenly on step 7 of 7. I’m not sure what happened to step 6, I even ran the installer yet one more time just to make sure it was gone. Perhaps it was kidnapped by space aliens?

[image - Installer is Ready]

Apparently even without the missing step 6, the installer has everything it needs. Just click Install to begin the install process. Kick back and wait. Don’t be alarmed if the screen goes black during the process, it’s just the screen saver kicking in. Just click in the VPC and wiggle your mouse and your display will return. I had it kick in several times during the 45 (or so) minutes it took to get everything installed.

[image - Install complete time to reboot]

Eventually Ubuntu will complete it’s install, then give you the above message. On the Virtual PC menu click CD, then release the cd. Then click on the big Restart now button inside VPC.

This was the only real snag I hit in the whole install process, I waited a while and it never did restart on its own. I gave it about five minutes, then in the Virtual PC menu I clicked Action, Reset. I figured since it’s already installed, I wouldn’t lose anything, and I was right.

The boot process does take a few minutes; you’ll see some text then a black screen for about 90 seconds. Then it comes up to the big Ubuntu logo and the orange bar as it loads. You’ll see some garbled graphics for a few seconds, then the login screen finally appeared. I gave it my user id and password, and minutes later I was in Ubuntu.

One last piece of business, fixing the networking. First make sure the network card is mapped to a real network card in your computer. For more instructions on this, see my video, Virtual PC Advanced Settings. After that, click on the network icon in the upper right side of the toolbar, as you see below.

[image - Fix Networking]

Then just pick Wired Network. Once connected you’ll be free to visit your favorite websites!

[image - Ubuntu open for business]

I haven’t had much time to check out other features, or get the sound working so if anyone has a quick fix for that by all means leave a comment below.

posted @ 2008-09-17 10:20 若我 阅读(375) | 评论 (0)编辑 收藏

C Run-Time Libraries 

This topic discusses the various .lib files that comprise the C run-time libraries as well as their associated compiler options and preprocessor directives.

The following libraries contain the C run-time library functions.

C run-time library (without iostream or standard C++ library) Associated DLL Characteristics Option Preprocessor directives

libcmt.lib

None, static link.

Multithreaded, static link

/MT

_MT

msvcrt.lib

msvcr80.dll

Multithreaded, dynamic link (import library for MSVCR80.DLL). Be aware that if you use the Standard C++ Library, your program will need MSVCP80.DLL to run.

/MD

_MT, _DLL

libcmtd.lib

None, static link

Multithreaded, static link (debug)

/MTd

_DEBUG, _MT

msvcrtd.lib

msvcr80d.dll

Multithreaded, dynamic link (import library for MSVCR80D.DLL) (debug).

/MDd

_DEBUG, _MT, _DLL

msvcmrt.lib

msvcm80.dll

C Runtime import library. Used for mixed managed/native code.

/clr

 

msvcurt.lib

msvcm80.dll

C Runtime import library compiled as 100% pure MSIL code. All code complies with the ECMA URT spec for MSIL.

/clr:pure

 

NoteNote

The single-threaded CRT (libc.lib, libcd.lib) (formerly the /ML or /MLd options) is no longer available. Instead, use the multithreaded CRT. See Multithreaded Libraries Performance.

If you link your program from the command line without a compiler option that specifies a C run-time library, the linker will use LIBCMT.LIB. This is different from previous versions of Visual C++ which used LIBC.LIB, the single-threaded library, instead.

Using the statically linked CRT implies that any state information saved by the C runtime library will be local to that instance of the CRT. For example, if you use strtok, _strtok_l, wcstok, _wcstok_l, _mbstok, _mbstok_l when using a statically linked CRT, the position of the strtok parser is unrelated to the strtok state used in code in the same process (but in a different DLL or EXE) that is linked to another instance of the static CRT. In contrast, the dynamically linked CRT shares state for all code within a process that is dynamically linked to the CRT. This concern does not apply if you use the new more secure versions of these functions; for example, strtok_s does not have this problem.

Because a DLL built by linking to a static CRT will have its own CRT state, it is not recommended to link statically to the CRT in a DLL unless the consequences of this are specifically desired and understood. For example, if you call _set_se_translator in an executable that loads the DLL linked to its own static CRT, any hardware exceptions generated by the code in the DLL will not be caught by the translator, but hardware exceptions generated by code in the main executable will be caught.

If you are using the /clr compiler switch, your code will be linked with an import library, msvcmrt.lib. The import library references a new library, msvcm80.dll, which provides a proxy between your managed code and the native CRT. You cannot use the statically linked CRT ( /MT or /MTd options) with /clr. Use the dynamically-linked libraries (/MD or /MDd) instead.

If you are using the /clr:pure compiler switch, your code will be linked with the import library msvcurt.lib, which also references msvcm80.dll. As with /clr, you cannot link with the statically linked library.

For more information on using the CRT with /clr, see Mixed (Native and Managed) Assemblies; for /clr:pure, see Pure and Verifiable Code.

To build a debug version of your application, the _DEBUG flag must be defined and the application must be linked with a debug version of one of these libraries. For more information about using the debug versions of the library files, see CRT Debugging Techniques.

This version of Visual C++ is not conformant with the C99 standard.

Standard C++ Library Characteristics Option Preprocessor directives

LIBCPMT.LIB

Multithreaded, static link

/MT

_MT

MSVCPRT.LIB

Multithreaded, dynamic link (import library for MSVCP80.dll)

/MD

_MT, _DLL

LIBCPMTD.LIB

Multithreaded, static link

/MTd

_DEBUG, _MT

MSVCPRTD.LIB

Multithreaded, dynamic link (import library for MSVCP80D.DLL)

/MDd

_DEBUG, _MT, _DLL

Note   Starting in Visual C++ 2005, LIBCP.LIB and LIBCPD.LIB (via the old /ML and /MLd options) have been removed. Use LIBCPMT.LIB and LIBCPMTD.LIB instead via the /MT and /MTd options.

When you build a release version of your project, one of the basic C run-time libraries (LIBCMT.LIB, MSVCMRT.LIB, MSVCRT.LIB) is linked by default, depending on the compiler option you choose (multithreaded, DLL, /clr). If you include one of the Standard C++ Library Header Files in your code, a Standard C++ Library will be linked in automatically by Visual C++ at compile time. For example:

#include <ios> 

The msvcrt.dll is now a "known DLL," meaning that it is a system component owned and built by Windows. It is intended for future use only by system-level components.

If you have a .lib or .obj file that needs to link to msvcrt.lib, then you should not have to recompile it to work with the new msvcrt.lib in Visual C++ 2005. The .lib or .obj file may rely on the sizes, field offsets, or member function names of various CRT classes or variables, and those should all still exist in a compatible way. When you relink against msvcrt.lib, your final EXE and DLL image will now have a dependency on msvcr80.dll instead of msvcrt.dll.

If you have more than one DLL or EXE, then you may have more than one CRT, whether or not you are using different versions of Visual C++. For example, statically linking the CRT into multiple DLLs can present the same problem. Developers encountering this problem with static CRTs have been instructed to compile with /MD to use the CRT DLL. Now that the CRT DLL has been renamed to msvcr80.dll, applications may have some components linked to msvcrt.dll and others to msvcr80.dll. If your DLLs pass CRT resources across the msvcrt.dll and msvcr80.dll boundary, you will encounter issues with mismatched CRTs and need to recompile your project with Visual C++ 2005.

If your program is using more than one version of the CRT, some care is needed when passing certain CRT objects (such as file handles, locales and environment variables) across DLL boundaries. For more information on the issues involved and how to resolve them, see Potential Errors Passing CRT Objects Across DLL Boundaries.

posted @ 2008-09-16 22:13 若我 阅读(356) | 评论 (0)编辑 收藏

原文链接:http://www.cnblogs.com/smartstone/archive/2005/12/22/302457.html
如果在 ATL 组件程序中调用了 CRT 的运行时刻库函数,比如开平方 sqrt() ,那么编译的时候可能会报错“error LNK2001: unresolved external symbol _main”。怎么办?删除预定义宏“_ATL_MIN_CRT”!操作方法也见图一、图二。(vc.net 2003 中的这个项目属性叫“在 ATL 中最小使用 CRT”)

 

学习VC++时经常会遇到链接错误LNK2001,该错误非常讨厌,因为对于编程者来说,最好改的错误莫过于编译错误,而一般说来发生连接错误时,编译都已通过。产生连接错误的原因非常多,尤其LNK2001错误,常常使人不明其所以然。如果不深入地学习和理解VC++,要想改正连接错误LNK2001非常困难。

  初学者在学习VC++的过程中,遇到的LNK2001错误的错误消息主要为:

  unresolved external symbol “symbol”(不确定的外部“符号”)。

  如果连接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误消息。一般来说,发生错误的原因有两个:一是所引用的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不同版本的连接库。

  以下是可能产生LNK2001错误的原因:

  一.由于编码错误导致的LNK2001

  1.不相匹配的程序代码或模块定义(.DEF)文件能导致LNK2001。例如, 如果在C++源文件内声明了一变量“var1”,却试图在另一文件内以变量“VAR1”访问该变量,将发生该错误。

  2.如果使用的内联函数是在.CPP文件内定义的,而不是在头文件内定义将导致LNK2001错误。

  3.调用函数时如果所用的参数类型同函数声明时的类型不符将会产生LNK2001。

  4.试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001。

  5.要注意函数和变量的可公用性,只有全局变量、函数是可公用的。静态函数和静态变量具有相同的使用范围限制。当试图从文件外部访问任何没有在该文件内声明的静态变量时将导致编译错误或LNK2001。

  函数内声明的变量(局部变量) 只能在该函数的范围内使用。

C++ 的全局常量只有静态连接性能。这不同于C,如果试图在C++的多个文件内使用全局变量也会产生LNK2001错误。一种解决的方法是需要时在头文件中加入该常量的初始化代码,并在.CPP文件中包含该头文件;另一种方法是使用时给该变量赋以常数。

  二.由于编译和链接的设置而造成的LNK2001

  1.如果编译时使用的是/NOD(/NODEFAULTLIB)选项,程序所需要的运行库和MFC库在连接时由编译器写入目标文件模块, 但除非在文件中明确包含这些库名,否则这些库不会被链接进工程文件。在这种情况下使用/NOD将导致错误LNK2001。

  2.如果没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时将得到“unresolved external on _WinMain@16”的LNK2001错误信息。

  3.使用/MD选项编译时,既然所有的运行库都被保留在动态链接库之内,源文件中对“func”的引用,在目标文件里即对“__imp__func” 的引用。如果试图使用静态库LIBC.LIB或LIBCMT.LIB进行连接,将在__imp__func上发生LNK2001;如果不使用/MD选项编
  译,在使用MSVCxx.LIB连接时也会发生LNK2001。

  4.使用/ML选项编译时,如用LIBCMT.LIB链接会在_errno上发生LNK2001。

  5.当编译调试版的应用程序时,如果采用发行版模态库进行连接也会产生LNK2001;同样,使用调试版模态库连接发行版应用程序时也会产生相同的问题。

  6.不同版本的库和编译器的混合使用也能产生问题,因为新版的库里可能包含早先的版本没有的符号和说明。

  编程时打开了函数内联(/Ob1或/Ob2),但是在描述该函数的相应头文件里却关闭了函数内联(没有inline关键字),这时将得到该错误信息。为避免该问题的发生,应该在相应的头文件中用inline关键字标志内联函数。

  8.不正确的/SUBSYSTEM或/ENTRY设置也能导致LNK2001。

posted @ 2008-09-16 22:12 若我 阅读(221) | 评论 (0)编辑 收藏

图像增强是指将图像的部分信息利用某种方式(在频域或者空域)将以增强,从而有利于某种服务的操作。一般将空域的图像增强分为线性灰度增强和非线性灰度增强。

线性灰度增强:

设源图像的灰度范围在[a-b]的范围内,我们打算将这个范围内的像素灰度增强到范围[c-d],设函数f(x,y)表示坐标为(x,y)点处的原始灰度值,g(x,y)表示增强后的图像的灰度值:
那么:

g(x,y)=(d-c)*(f(x,y)-a)/(b-a)+c

下面是GDI+实现的线性灰度增强的代码:

void GrayEnhance(Bitmap *bmp,char minR,char maxR,char minG,char maxG, char minB, char maxB)
{
 if(minR>=maxR)
 {
  return;
 }
 if(minG>=maxG)
 {
  return;
 }
 if(minB>maxB)
 {
  return;
 }
 BitmapData bmpData;
 bmp->LockBits(&rec,ImageLockModeRead|ImageLockModeWrite ,PixelFormat32bppARGB,&bmpData);
 char *pStar=(char*)bmpData.Scan0;
 UINT width=bmp->GetWidth();
 UINT height=bmp->GetHeight();

 char mR=pStart[0],maR=pStart[0],mG=pStart[1],maG=pStart[1],mB=pStart[2],maB=pStart[2];

 for(int i=0;i<height;i++)
 {
  for(int j=0;j<width;j++)
  {
   if(pStart[0]<mR)
   {
    mR=pStart[0];
   }
   else if(pStart[0]>maR)
   {
    maR=pStart[0];
   }

   if(pStart[1]<mG)
   {
    mG=pStart[1];
   }
   else if(pStart[1]>maG)
   {
    maG=pStart[1];
   }

   if(pStart[2]<mB)
   {
    mB=pStart[2];
   }
   else if(pStart[2]>maB)
   {
    maB=pStart[2];
   }
   pStart+=3;
  }
  p+=bmpData.Stride-3*width;
 }

 pStar=(char*)bmpData.Scan0;
 for(int i=0;i<height;i++)
 {
  for(int j=0;j<width;j++)
  {
   pStart[0]=(char)((maxR-minR)*(pStart[0]-mR)/(maR-mR)+minR);
   pStart[1]=(char)((maxG-minG)*(pStart[0]-mG)/(maG-mG)+minG);
   pStart[2]=(char)((maxB-minB)*(pStart[0]-mB)/(maB-mB)+minB);
   pStart+=3;
  }
  p+=bmpData.Stride-3*width;
 }
 bmp->UnlockBits(&bmpData);
}

posted @ 2008-06-27 16:22 若我 阅读(575) | 评论 (0)编辑 收藏

在GDI里面,你要想开始自己的绘图工作,必须先获取一个device context handle,然后把这个handle作为绘图复方法的一个参数,才能完成任务。同时,device context handle是同一定的绘图属性绑定在一起的,诸如画笔、话刷等等,你必须在画线之前创建自己的画笔,然后使用selectObject方法把这个画笔同已经获取的device context handle绑定,才能使用LineTo等方法开始画线。不然,你画出来的线使用的是默认的属性:宽度(1),颜色(黑色)。
但是,在GDI+里面,画线方法DrawLine把画笔Pen直接作为一个参数,这样,一定的画笔就不需要同device context handle 直接绑定了。

下面是GDI和GDI+两者画线代码的演示:

GDI:

HDC          hdc;
PAINTSTRUCT  ps;
HPEN         hPen;
HPEN         hPenOld;
hdc = BeginPaint(hWnd, &ps);
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
hPenOld = (HPEN)SelectObject(hdc, hPen);
MoveToEx(hdc, 20, 10, NULL);
LineTo(hdc, 200, 100);
SelectObject(hdc, hPenOld);
DeleteObject(hPen);
EndPaint(hWnd, &ps);
 
GDI+:
 
HDC          hdc;
PAINTSTRUCT  ps;
Pen*         myPen;
Graphics*    myGraphics;
hdc = BeginPaint(hWnd, &ps);
myPen = new Pen(Color(255, 255, 0, 0), 3);
myGraphics = new Graphics(hdc);
myGraphics->DrawLine(myPen, 20, 10, 200, 100);
delete myGraphics;
delete myPen;
EndPaint(hWnd, &ps);

posted @ 2008-06-27 13:51 若我 阅读(1111) | 评论 (0)编辑 收藏

显示位图,你应该使用GDI+里面的Bitmap类或者Image类,这两个类都提供了方法从硬盘上的一个文件打开文件,创建相应的内存中的位图对象的工作。然后你可以使用Graphics类的DrawImage方法来绘制该位图。
下面的代码初始化GDI+,显示一个打开文件对话框并且创建Bitmap对象,显示位图:

GdiplusStartupInput input;
 ULONG_PTR gdiPlusToken;
 if(GdiplusStartup(&gdiPlusToken,&input,NULL)!=Ok)
 {
  return -1;
 }

char fileName[200];
     OPENFILENAME openStruct;
     memset(&openStruct,0,sizeof(OPENFILENAME));
     openStruct.lStructSize=sizeof(OPENFILENAME);
     openStruct.Flags=OFN_EXPLORER;
     openStruct.lpstrFilter="Jpeg files(*.jpg)\0*.jpg\0\0";
     openStruct.lpstrFile=fileName;
     openStruct.nMaxFile=200;
     if(GetOpenFileName(&openStruct))
     {
      imageFileName=fileName;
      }

HDC hdc=GetDC(hPicWnd);
   if(hdc==NULL)
   {
    MessageBox(NULL,"","",MB_OK);
   }
   Graphics *g=new Graphics(hdc);
   WCHAR tmpFileName[100];
   size_t numOfChars;
   if(/*mbstowcs_s(&numOfChars,tmpFileName,100,fileName,199)*/MultiByteToWideChar(CP_ACP,MB_COMPOSITE,imageFileName.c_str(),200,tmpFileName,100)/*==-1*/)
   {
    MessageBox(NULL,"Error occured in string convertion!","Error!",MB_OK);       
    return wParam;
   }

HWND hPicWnd;
   RECT rc;
   GetWindowRect(hPicWnd,&rc);

   RectF drawRect(rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top);
    Bitmap *bmp=new Bitmap(tmpFileName);
   bmpMain=bmp;
   g->DrawImage(bmp,drawRect);
   delete g;

   ReleaseDC(hwnd,hdc);

GdiplusShutdown(gdiPlusToken);

posted @ 2008-06-27 13:32 若我 阅读(1406) | 评论 (0)编辑 收藏

在我理解看来,Graphics是一个device context和你的drawing conetent之间的一个中介。它存储了device context的相关属性,以及drawing content的属性。这样,它就能用自己的方法把drawing content“映射”到device content 之上。

GDI中的绘图工作是直接在device context之上进行的。在GDI—+中,你因该在device context之上再建立一个graphics,然后调用graphics的相关方法完成绘图等工作。

Graphics类有四个构造函数:
(1)Graphics(      

    Image* image );
(2)Graphics(      

    HDC hdc );
(3)Graphics(      

    HDC hdc,     HANDLE hdevice );
(4)Graphics(      

    HWND hwnd,     BOOL icm );
 
 
构造函数1从image对象创建一个Graphics类。这种方式允许你在打开某张,或者生成某张,位图之后,应用Grapgics的方法对改位图进行操作。
构造函数2从一个传统的HDC获取一个Graphics对象,把传统的在HDC完成的操作接手过来。
构造函数3允许你创建一个绑定于某个特定设备的Graphics类实例。
构造函数4允许你直接从特定的窗口hwnd直接获取一个Graphics类实例。
 

posted @ 2008-06-27 13:25 若我 阅读(952) | 评论 (0)编辑 收藏

GDI+提供了GdiplusStartup和 GdiplusShutdown 函数来进行初始化和完成清理工作。你必须在调用其他的GDI+函数之前,调用GdiplusStartup函数,在完成GDI+工作后调用GdiplusShutdown 。
具体的可以看下面的MSDN上的例子:

#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
INT main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
Image* image = new Image(L"FakePhoto.jpg");
printf("The width of the image is %u.\n", image->GetWidth());
printf("The height of the image is %u.\n", image->GetHeight());
delete image;
GdiplusShutdown(gdiplusToken);
return 0;
}
 
具体的使用方法,可以参考MSDN的说明。
 

posted @ 2008-06-27 11:47 若我 阅读(977) | 评论 (0)编辑 收藏

仅列出标题
共3页: 1 2 3