├── Stub ├── info.h ├── aplib.lib ├── stdafx.h ├── dllmain.cpp ├── msvcrt.lib ├── stdafx.cpp ├── targetver.h ├── Stub.vcxproj.user ├── Stub.vcxproj.filters ├── aplib.h └── Stub.vcxproj ├── Packer ├── Task.h ├── info.h ├── LoadIng.h ├── Packer.h ├── Packer.rc ├── Stub.dll ├── Task.cpp ├── aplib.lib ├── stdafx.h ├── util.cpp ├── InputInfo.h ├── LoadIng.cpp ├── Packer.aps ├── Packer.cpp ├── PackerDlg.h ├── res │ ├── timg.gif │ ├── Packer.ico │ ├── Packer.rc2 │ └── icon1.ico ├── resource.h ├── stdafx.cpp ├── targetver.h ├── InputInfo.cpp ├── PackerDlg.cpp ├── Packer.vcxproj.user ├── util.h ├── aplib.h ├── Packer.vcxproj.filters ├── PictureEx.h ├── Packer.vcxproj └── PictureEx.cpp ├── ScreenShot ├── 1.PNG ├── 1.jpg ├── 2.PNG ├── 2.jpg ├── 3.PNG ├── 3.jpg ├── 4.PNG ├── 4.jpg └── 5.PNG ├── .gitignore ├── README.md └── Packer.sln /Stub/info.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Stub/info.h -------------------------------------------------------------------------------- /Packer/Task.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/Task.h -------------------------------------------------------------------------------- /Packer/info.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/info.h -------------------------------------------------------------------------------- /Stub/aplib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Stub/aplib.lib -------------------------------------------------------------------------------- /Stub/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Stub/stdafx.h -------------------------------------------------------------------------------- /Packer/LoadIng.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/LoadIng.h -------------------------------------------------------------------------------- /Packer/Packer.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/Packer.h -------------------------------------------------------------------------------- /Packer/Packer.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/Packer.rc -------------------------------------------------------------------------------- /Packer/Stub.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/Stub.dll -------------------------------------------------------------------------------- /Packer/Task.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/Task.cpp -------------------------------------------------------------------------------- /Packer/aplib.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/aplib.lib -------------------------------------------------------------------------------- /Packer/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/stdafx.h -------------------------------------------------------------------------------- /Packer/util.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/util.cpp -------------------------------------------------------------------------------- /ScreenShot/1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/1.PNG -------------------------------------------------------------------------------- /ScreenShot/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/1.jpg -------------------------------------------------------------------------------- /ScreenShot/2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/2.PNG -------------------------------------------------------------------------------- /ScreenShot/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/2.jpg -------------------------------------------------------------------------------- /ScreenShot/3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/3.PNG -------------------------------------------------------------------------------- /ScreenShot/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/3.jpg -------------------------------------------------------------------------------- /ScreenShot/4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/4.PNG -------------------------------------------------------------------------------- /ScreenShot/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/4.jpg -------------------------------------------------------------------------------- /ScreenShot/5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/ScreenShot/5.PNG -------------------------------------------------------------------------------- /Stub/dllmain.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Stub/dllmain.cpp -------------------------------------------------------------------------------- /Stub/msvcrt.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Stub/msvcrt.lib -------------------------------------------------------------------------------- /Stub/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Stub/stdafx.cpp -------------------------------------------------------------------------------- /Stub/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Stub/targetver.h -------------------------------------------------------------------------------- /Packer/InputInfo.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/InputInfo.h -------------------------------------------------------------------------------- /Packer/LoadIng.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/LoadIng.cpp -------------------------------------------------------------------------------- /Packer/Packer.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/Packer.aps -------------------------------------------------------------------------------- /Packer/Packer.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/Packer.cpp -------------------------------------------------------------------------------- /Packer/PackerDlg.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/PackerDlg.h -------------------------------------------------------------------------------- /Packer/res/timg.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/res/timg.gif -------------------------------------------------------------------------------- /Packer/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/resource.h -------------------------------------------------------------------------------- /Packer/stdafx.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/stdafx.cpp -------------------------------------------------------------------------------- /Packer/targetver.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/targetver.h -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /Debug 2 | *.db 3 | *.opendb 4 | /ipch 5 | /Release 6 | /Packer/Debug 7 | *.tmp -------------------------------------------------------------------------------- /Packer/InputInfo.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/InputInfo.cpp -------------------------------------------------------------------------------- /Packer/PackerDlg.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/PackerDlg.cpp -------------------------------------------------------------------------------- /Packer/res/Packer.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/res/Packer.ico -------------------------------------------------------------------------------- /Packer/res/Packer.rc2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/res/Packer.rc2 -------------------------------------------------------------------------------- /Packer/res/icon1.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/longqun/Packer/HEAD/Packer/res/icon1.ico -------------------------------------------------------------------------------- /Stub/Stub.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Packer/Packer.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Packer/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "info.h" 3 | #include "string" 4 | bool CreateFileMapStruct(const char*path, FileMapStruct & fileMapStruct); 5 | bool isPEEXE32(const char *fileData); 6 | void replaceStringA(std::string & path); 7 | int __cdecl ProgressCallBack(unsigned int insize, unsigned int inpos, unsigned int outpos, void *cbparam); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 这里是PE文件加壳程序。 2 | === 3 | 4 |
5 | 1:目前支持源程序16个区段的压缩。对于超过16个的区段可以修改数据结构实现。 6 |
7 | 2:不支持加过其他壳的程序加壳,目前只支持exe文件。 8 |
9 | 3:支持Windows10下执行,对于重定位进行了处理,可以支持随机地址的执行。 10 |
11 | 12 | 编译流程: 13 | ------- 14 | 将Packer和Stub都设置成x86 release下编译即可 15 |
16 | 17 | 文件运行截图: 18 | ------- 19 |
20 | ![image](https://github.com/longqun/Packer/raw/master/ScreenShot/5.PNG) 21 | 22 | 程序处理流程: 23 | ------- 24 | 1读取加壳文件,外壳DLL 25 |
26 | 2:选择加壳文件需要压缩的地方,对于资源段选择不压缩,其他区段都进行压缩。 27 |
28 | 3:重新构造区段表,分别有这么几个区段 .OldDat(原始压缩的数据) .Shell(外壳DLL代码) .tls(用来支持加壳tls程序) .CRT(用来支持加壳tls程序) .reloc(外壳DLL重定位信息) .rcsc(资源如果有的话) 29 |
30 | 4:利用aPLib进行压缩,将压缩之后的数据复制到目标文件.OldDat区段缓冲区。 31 |
32 | 5:对于外壳DLL进行重定位,资源数据修复 33 |
34 | 6:设置导出变量的数据,在外壳DLL中将使用到的变量 35 |
36 | 7:写入文件 37 |
38 | 39 | 原始区段信息 40 |
41 | ![image](https://github.com/longqun/Packer/raw/master/ScreenShot/1.jpg) 42 |
43 | 原始目录 44 |
45 | ![image](https://github.com/longqun/Packer/raw/master/ScreenShot/2.jpg) 46 |
47 | 加壳后的区段信息 48 |
49 | ![image](https://github.com/longqun/Packer/raw/master/ScreenShot/3.jpg) 50 |
51 | 加壳之后的目录表 52 |
53 | ![image](https://github.com/longqun/Packer/raw/master/ScreenShot/4.jpg) -------------------------------------------------------------------------------- /Stub/Stub.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 头文件 19 | 20 | 21 | 头文件 22 | 23 | 24 | 头文件 25 | 26 | 27 | 头文件 28 | 29 | 30 | 31 | 32 | 源文件 33 | 34 | 35 | 源文件 36 | 37 | 38 | -------------------------------------------------------------------------------- /Packer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Packer", "Packer\Packer.vcxproj", "{68DB45A6-D30C-4515-9C74-39514C4CB54E}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stub", "Stub\Stub.vcxproj", "{C296FD25-9FED-404A-9784-D0CA4F5FC1E8}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Debug|x64.ActiveCfg = Debug|x64 19 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Debug|x64.Build.0 = Debug|x64 20 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Debug|x86.ActiveCfg = Debug|Win32 21 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Debug|x86.Build.0 = Debug|Win32 22 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Release|x64.ActiveCfg = Release|x64 23 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Release|x64.Build.0 = Release|x64 24 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Release|x86.ActiveCfg = Release|Win32 25 | {68DB45A6-D30C-4515-9C74-39514C4CB54E}.Release|x86.Build.0 = Release|Win32 26 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Debug|x64.ActiveCfg = Debug|x64 27 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Debug|x64.Build.0 = Debug|x64 28 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Debug|x86.ActiveCfg = Debug|Win32 29 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Debug|x86.Build.0 = Debug|Win32 30 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Release|x64.ActiveCfg = Release|x64 31 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Release|x64.Build.0 = Release|x64 32 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Release|x86.ActiveCfg = Release|Win32 33 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8}.Release|x86.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /Stub/aplib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * aPLib compression library - the smaller the better :) 3 | * 4 | * MS COFF format header file 5 | * 6 | * Copyright (c) 1998-2005 by Joergen Ibsen / Jibz 7 | * All Rights Reserved 8 | * 9 | * http://www.ibsensoftware.com/ 10 | */ 11 | 12 | #ifndef APLIB_H_INCLUDED 13 | #define APLIB_H_INCLUDED 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #ifndef APLIB_ERROR 20 | # define APLIB_ERROR (-1) 21 | #endif 22 | 23 | unsigned int __cdecl aP_pack(const void *source, 24 | void *destination, 25 | unsigned int length, 26 | void *workmem, 27 | int (__cdecl *callback)(unsigned int, unsigned int, unsigned int, void *), 28 | void *cbparam); 29 | 30 | unsigned int __cdecl aP_workmem_size(unsigned int inputsize); 31 | 32 | unsigned int __cdecl aP_max_packed_size(unsigned int inputsize); 33 | 34 | unsigned int __cdecl aP_depack_asm(const void *source, void *destination); 35 | 36 | unsigned int __cdecl aP_depack_asm_fast(const void *source, void *destination); 37 | 38 | unsigned int __cdecl aP_depack_asm_safe(const void *source, 39 | unsigned int srclen, 40 | void *destination, 41 | unsigned int dstlen); 42 | 43 | unsigned int __cdecl aP_crc32(const void *source, unsigned int length); 44 | 45 | unsigned int __cdecl aPsafe_pack(const void *source, 46 | void *destination, 47 | unsigned int length, 48 | void *workmem, 49 | int (__cdecl *callback)(unsigned int, unsigned int, unsigned int, void *), 50 | void *cbparam); 51 | 52 | unsigned int __cdecl aPsafe_check(const void *source); 53 | 54 | unsigned int __cdecl aPsafe_get_orig_size(const void *source); 55 | 56 | unsigned int __cdecl aPsafe_depack(const void *source, 57 | unsigned int srclen, 58 | void *destination, 59 | unsigned int dstlen); 60 | 61 | #ifdef __cplusplus 62 | } /* extern "C" */ 63 | #endif 64 | 65 | #endif /* APLIB_H_INCLUDED */ 66 | -------------------------------------------------------------------------------- /Packer/aplib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * aPLib compression library - the smaller the better :) 3 | * 4 | * MS COFF format header file 5 | * 6 | * Copyright (c) 1998-2005 by Joergen Ibsen / Jibz 7 | * All Rights Reserved 8 | * 9 | * http://www.ibsensoftware.com/ 10 | */ 11 | 12 | #ifndef APLIB_H_INCLUDED 13 | #define APLIB_H_INCLUDED 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #ifndef APLIB_ERROR 20 | # define APLIB_ERROR (-1) 21 | #endif 22 | 23 | unsigned int __cdecl aP_pack(const void *source, 24 | void *destination, 25 | unsigned int length, 26 | void *workmem, 27 | int (__cdecl *callback)(unsigned int, unsigned int, unsigned int, void *), 28 | void *cbparam); 29 | 30 | unsigned int __cdecl aP_workmem_size(unsigned int inputsize); 31 | 32 | unsigned int __cdecl aP_max_packed_size(unsigned int inputsize); 33 | 34 | unsigned int __cdecl aP_depack_asm(const void *source, void *destination); 35 | 36 | unsigned int __cdecl aP_depack_asm_fast(const void *source, void *destination); 37 | 38 | unsigned int __cdecl aP_depack_asm_safe(const void *source, 39 | unsigned int srclen, 40 | void *destination, 41 | unsigned int dstlen); 42 | 43 | unsigned int __cdecl aP_crc32(const void *source, unsigned int length); 44 | 45 | unsigned int __cdecl aPsafe_pack(const void *source, 46 | void *destination, 47 | unsigned int length, 48 | void *workmem, 49 | int (__cdecl *callback)(unsigned int, unsigned int, unsigned int, void *), 50 | void *cbparam); 51 | 52 | unsigned int __cdecl aPsafe_check(const void *source); 53 | 54 | unsigned int __cdecl aPsafe_get_orig_size(const void *source); 55 | 56 | unsigned int __cdecl aPsafe_depack(const void *source, 57 | unsigned int srclen, 58 | void *destination, 59 | unsigned int dstlen); 60 | 61 | #ifdef __cplusplus 62 | } /* extern "C" */ 63 | #endif 64 | 65 | #endif /* APLIB_H_INCLUDED */ 66 | -------------------------------------------------------------------------------- /Packer/Packer.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 头文件 23 | 24 | 25 | 头文件 26 | 27 | 28 | 头文件 29 | 30 | 31 | 头文件 32 | 33 | 34 | 头文件 35 | 36 | 37 | 头文件 38 | 39 | 40 | 头文件 41 | 42 | 43 | 头文件 44 | 45 | 46 | 头文件 47 | 48 | 49 | 头文件 50 | 51 | 52 | 头文件 53 | 54 | 55 | 头文件 56 | 57 | 58 | 59 | 60 | 源文件 61 | 62 | 63 | 源文件 64 | 65 | 66 | 源文件 67 | 68 | 69 | 源文件 70 | 71 | 72 | 源文件 73 | 74 | 75 | 源文件 76 | 77 | 78 | 源文件 79 | 80 | 81 | 源文件 82 | 83 | 84 | 85 | 86 | 资源文件 87 | 88 | 89 | 90 | 91 | 资源文件 92 | 93 | 94 | 95 | 96 | 资源文件 97 | 98 | 99 | 资源文件 100 | 101 | 102 | -------------------------------------------------------------------------------- /Stub/Stub.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {C296FD25-9FED-404A-9784-D0CA4F5FC1E8} 23 | Win32Proj 24 | Stub 25 | 8.1 26 | 27 | 28 | 29 | DynamicLibrary 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | DynamicLibrary 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | DynamicLibrary 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | DynamicLibrary 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | 84 | 85 | 86 | Use 87 | Level3 88 | Disabled 89 | WIN32;_DEBUG;_WINDOWS;_USRDLL;STUB_EXPORTS;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Windows 94 | true 95 | 96 | 97 | 98 | 99 | Use 100 | Level3 101 | Disabled 102 | _DEBUG;_WINDOWS;_USRDLL;STUB_EXPORTS;%(PreprocessorDefinitions) 103 | true 104 | 105 | 106 | Windows 107 | true 108 | 109 | 110 | 111 | 112 | Level3 113 | Use 114 | Disabled 115 | true 116 | true 117 | WIN32;NDEBUG;_WINDOWS;_USRDLL;STUB_EXPORTS;%(PreprocessorDefinitions) 118 | true 119 | false 120 | MultiThreadedDLL 121 | 122 | 123 | Windows 124 | true 125 | true 126 | true 127 | /SAFESEH:NO %(AdditionalOptions) 128 | kernel32.lib 129 | false 130 | 131 | 132 | 133 | 134 | Level3 135 | Use 136 | MaxSpeed 137 | true 138 | true 139 | NDEBUG;_WINDOWS;_USRDLL;STUB_EXPORTS;%(PreprocessorDefinitions) 140 | true 141 | 142 | 143 | Windows 144 | true 145 | true 146 | true 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | false 161 | 162 | 163 | false 164 | 165 | 166 | false 167 | 168 | 169 | false 170 | 171 | 172 | 173 | 174 | Create 175 | Create 176 | Create 177 | Create 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /Packer/PictureEx.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // PictureEx.cpp: implementation of the CPictureEx class. 3 | // 4 | // Picture displaying control with support for the following formats: 5 | // GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR 6 | // 7 | // Written by Oleg Bykov (oleg_bykoff@rsdn.ru) 8 | // Copyright (c) 2001 9 | // 10 | // To use CPictureEx, follow these steps: 11 | // - place a static control on your dialog (either a text or a bitmap) 12 | // - change its identifier to something else (e.g. IDC_MYPIC) 13 | // - associate a CStatic with it using ClassWizard 14 | // - in your dialog's header file replace CStatic with CPictureEx 15 | // (don't forget to #include "PictureEx.h" and add 16 | // PictureEx.h and PictureEx.cpp to your project) 17 | // - call one of the overloaded CPictureEx::Load() functions somewhere 18 | // (OnInitDialog is a good place to start) 19 | // - if the preceding Load() succeeded call Draw() 20 | // 21 | // You can also add the control by defining a member variable of type 22 | // CPictureEx, calling CPictureEx::Create (derived from CStatic), then 23 | // CPictureEx::Load and CPictureEx::Draw. 24 | // 25 | // By default, the control initializes its background to COLOR_3DFACE 26 | // (see CPictureEx::PrepareDC()). You can change the background by 27 | // calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load(). 28 | // 29 | // I decided to leave in the class the functions to write separate frames from 30 | // animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING 31 | // and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions 32 | // won't be compiled and linked to your project unless you uncomment #define GIF_TRACING, 33 | // so you don't have to worry. 34 | // 35 | // Warning: this code hasn't been subject to a heavy testing, so 36 | // use it on your own risk. The author accepts no liability for the 37 | // possible damage caused by this code. 38 | // 39 | // Version 1.0 7 Aug 2001 40 | // Initial release 41 | // 42 | // Version 1.1 6 Sept 2001 43 | // ATL version of the class 44 | // 45 | // Version 1.2 14 Oct 2001 46 | // - Fixed a problem with loading GIFs from resources 47 | // in MFC-version of the class for multi-modules apps. 48 | // Thanks to Ruben Avila-Carretero for finding this out. 49 | // 50 | // - Got rid of waitable timer in ThreadAnimation() 51 | // Now CPictureEx[Wnd] works in Win95 too. 52 | // Thanks to Alex Egiazarov and Wayne King for the idea. 53 | // 54 | // - Fixed a visual glitch of using SetBkColor. 55 | // Thanks to Kwangjin Lee for finding this out. 56 | // 57 | // Version 1.3 10 Nov 2001 58 | // - Fixed a DC leak. One DC leaked per each UnLoad() 59 | // (forgot to put a ReleaseDC() in the end of 60 | // CPictureExWnd::PrepareDC() function). 61 | // 62 | // - Now it is possible to set a clipping rectangle using 63 | // CPictureEx[Wnd]::SetPaintRect(const LPRECT) function. 64 | // The LPRECT parameter tells the class what portion of 65 | // a picture should it display. If the clipping rect is 66 | // not set, the whole picture is shown. 67 | // Thanks to Fabrice Rodriguez for the idea. 68 | // 69 | // - Added support for Stop/Draw. Now you can Stop() an 70 | // animated GIF, then Draw() it again, it will continue 71 | // animation from the frame it was stopped on. You can 72 | // also know if a GIF is currently playing with the 73 | // IsPlaying() function. 74 | // 75 | // - Got rid of math.h and made m_bExitThread volatile. 76 | // Thanks to Piotr Sawicki for the suggestion. 77 | // 78 | ////////////////////////////////////////////////////////////////////// 79 | 80 | #if !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_) 81 | #define AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_ 82 | 83 | #if _MSC_VER > 1000 84 | #pragma once 85 | #endif // _MSC_VER > 1000 86 | 87 | #include 88 | 89 | //#define GIF_TRACING // uncomment it if you want detailed TRACEs 90 | 91 | class CPictureEx : public CStatic 92 | { 93 | public: 94 | 95 | struct TFrame // structure that keeps a single frame info 96 | { 97 | IPicture *m_pPicture; // pointer to the interface used for drawing 98 | SIZE m_frameSize; 99 | SIZE m_frameOffset; 100 | UINT m_nDelay; // delay (in 1/100s of a second) 101 | UINT m_nDisposal; // disposal method 102 | }; 103 | 104 | #pragma pack(1) // turn byte alignment on 105 | 106 | enum GIFBlockTypes 107 | { 108 | BLOCK_UNKNOWN, 109 | BLOCK_APPEXT, 110 | BLOCK_COMMEXT, 111 | BLOCK_CONTROLEXT, 112 | BLOCK_PLAINTEXT, 113 | BLOCK_IMAGE, 114 | BLOCK_TRAILER 115 | }; 116 | 117 | enum ControlExtValues // graphic control extension packed field values 118 | { 119 | GCX_PACKED_DISPOSAL, // disposal method 120 | GCX_PACKED_USERINPUT, 121 | GCX_PACKED_TRANSPCOLOR 122 | }; 123 | 124 | enum LSDPackedValues // logical screen descriptor packed field values 125 | { 126 | LSD_PACKED_GLOBALCT, 127 | LSD_PACKED_CRESOLUTION, 128 | LSD_PACKED_SORT, 129 | LSD_PACKED_GLOBALCTSIZE 130 | }; 131 | 132 | enum IDPackedValues // image descriptor packed field values 133 | { 134 | ID_PACKED_LOCALCT, 135 | ID_PACKED_INTERLACE, 136 | ID_PACKED_SORT, 137 | ID_PACKED_LOCALCTSIZE 138 | }; 139 | 140 | struct TGIFHeader // GIF header 141 | { 142 | char m_cSignature[3]; // Signature - Identifies the GIF Data Stream 143 | // This field contains the fixed value 'GIF' 144 | char m_cVersion[3]; // Version number. May be one of the following: 145 | // "87a" or "89a" 146 | }; 147 | 148 | struct TGIFLSDescriptor // Logical Screen Descriptor 149 | { 150 | WORD m_wWidth; // 2 bytes. Logical screen width 151 | WORD m_wHeight; // 2 bytes. Logical screen height 152 | 153 | unsigned char m_cPacked; // packed field 154 | 155 | unsigned char m_cBkIndex; // 1 byte. Background color index 156 | unsigned char m_cPixelAspect; // 1 byte. Pixel aspect ratio 157 | inline int GetPackedValue(enum LSDPackedValues Value); 158 | }; 159 | 160 | struct TGIFAppExtension // application extension block 161 | { 162 | unsigned char m_cExtIntroducer; // extension introducer (0x21) 163 | unsigned char m_cExtLabel; // app. extension label (0xFF) 164 | unsigned char m_cBlockSize; // fixed value of 11 165 | char m_cAppIdentifier[8]; // application identifier 166 | char m_cAppAuth[3]; // application authentication code 167 | }; 168 | 169 | struct TGIFControlExt // graphic control extension block 170 | { 171 | unsigned char m_cExtIntroducer; // extension introducer (0x21) 172 | unsigned char m_cControlLabel; // control extension label (0xF9) 173 | unsigned char m_cBlockSize; // fixed value of 4 174 | unsigned char m_cPacked; // packed field 175 | WORD m_wDelayTime; // delay time 176 | unsigned char m_cTColorIndex; // transparent color index 177 | unsigned char m_cBlockTerm; // block terminator (0x00) 178 | public: 179 | inline int GetPackedValue(enum ControlExtValues Value); 180 | }; 181 | 182 | struct TGIFCommentExt // comment extension block 183 | { 184 | unsigned char m_cExtIntroducer; // extension introducer (0x21) 185 | unsigned char m_cCommentLabel; // comment extension label (0xFE) 186 | }; 187 | 188 | struct TGIFPlainTextExt // plain text extension block 189 | { 190 | unsigned char m_cExtIntroducer; // extension introducer (0x21) 191 | unsigned char m_cPlainTextLabel; // text extension label (0x01) 192 | unsigned char m_cBlockSize; // fixed value of 12 193 | WORD m_wLeftPos; // text grid left position 194 | WORD m_wTopPos; // text grid top position 195 | WORD m_wGridWidth; // text grid width 196 | WORD m_wGridHeight; // text grid height 197 | unsigned char m_cCellWidth; // character cell width 198 | unsigned char m_cCellHeight; // character cell height 199 | unsigned char m_cFgColor; // text foreground color index 200 | unsigned char m_cBkColor; // text background color index 201 | }; 202 | 203 | struct TGIFImageDescriptor // image descriptor block 204 | { 205 | unsigned char m_cImageSeparator; // image separator byte (0x2C) 206 | WORD m_wLeftPos; // image left position 207 | WORD m_wTopPos; // image top position 208 | WORD m_wWidth; // image width 209 | WORD m_wHeight; // image height 210 | unsigned char m_cPacked; // packed field 211 | inline int GetPackedValue(enum IDPackedValues Value); 212 | }; 213 | 214 | #pragma pack() // turn byte alignment off 215 | 216 | public: 217 | BOOL GetPaintRect(RECT *lpRect); 218 | BOOL SetPaintRect(const RECT *lpRect); 219 | CPictureEx(); 220 | virtual ~CPictureEx(); 221 | void Stop(); // stops animation 222 | void UnLoad(); // stops animation plus releases all resources 223 | 224 | BOOL IsGIF() const; 225 | BOOL IsPlaying() const; 226 | BOOL IsAnimatedGIF() const; 227 | SIZE GetSize() const; 228 | int GetFrameCount() const; 229 | COLORREF GetBkColor() const; 230 | void SetBkColor(COLORREF clr); 231 | 232 | // draws the picture (starts an animation thread if needed) 233 | // if an animation was previously stopped by Stop(), 234 | // continues it from the last displayed frame 235 | BOOL Draw(); 236 | 237 | // loads a picture from a file 238 | // i.e. Load(_T("mypic.gif")); 239 | BOOL Load(LPCTSTR szFileName); 240 | 241 | // loads a picture from a global memory block (allocated by GlobalAlloc) 242 | // Warning: this function DOES NOT free the global memory, pointed to by hGlobal 243 | BOOL Load(HGLOBAL hGlobal, DWORD dwSize); 244 | 245 | // loads a picture from a program resource 246 | // i.e. Load(MAKEINTRESOURCE(IDR_MYPIC),_T("GIFTYPE")); 247 | BOOL Load(LPCTSTR szResourceName,LPCTSTR szResourceType); 248 | 249 | protected: 250 | 251 | #ifdef GIF_TRACING 252 | void EnumGIFBlocks(); 253 | void WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize); 254 | #endif // GIF_TRACING 255 | 256 | RECT m_PaintRect; 257 | SIZE m_PictureSize; 258 | COLORREF m_clrBackground; 259 | UINT m_nCurrFrame; 260 | UINT m_nDataSize; 261 | UINT m_nCurrOffset; 262 | UINT m_nGlobalCTSize; 263 | BOOL m_bIsGIF; 264 | BOOL m_bIsPlaying; 265 | volatile BOOL m_bExitThread; 266 | BOOL m_bIsInitialized; 267 | HDC m_hMemDC; 268 | 269 | HDC m_hDispMemDC; 270 | HBITMAP m_hDispMemBM; 271 | HBITMAP m_hDispOldBM; 272 | 273 | HBITMAP m_hBitmap; 274 | HBITMAP m_hOldBitmap; 275 | HANDLE m_hThread; 276 | HANDLE m_hExitEvent; 277 | IPicture * m_pPicture; 278 | TGIFHeader * m_pGIFHeader; 279 | unsigned char * m_pRawData; 280 | TGIFLSDescriptor * m_pGIFLSDescriptor; 281 | std::vector m_arrFrames; 282 | 283 | void ThreadAnimation(); 284 | static UINT WINAPI _ThreadAnimation(LPVOID pParam); 285 | 286 | int GetNextBlockLen() const; 287 | BOOL SkipNextBlock(); 288 | BOOL SkipNextGraphicBlock(); 289 | BOOL PrepareDC(int nWidth, int nHeight); 290 | void ResetDataPointer(); 291 | enum GIFBlockTypes GetNextBlock() const; 292 | UINT GetSubBlocksLen(UINT nStartingOffset) const; 293 | HGLOBAL GetNextGraphicBlock(UINT *pBlockLen, UINT *pDelay, 294 | SIZE *pBlockSize, SIZE *pBlockOffset, UINT *pDisposal); 295 | 296 | // Generated message map functions 297 | //{{AFX_MSG(CPictureEx) 298 | afx_msg void OnDestroy(); 299 | afx_msg void OnPaint(); 300 | //}}AFX_MSG 301 | 302 | DECLARE_MESSAGE_MAP() 303 | }; 304 | 305 | #endif // !defined(AFX_PICTUREEX_H__0EFE5DE0_7B68_4DB7_8B34_5DC634948438__INCLUDED_) 306 | -------------------------------------------------------------------------------- /Packer/Packer.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {68DB45A6-D30C-4515-9C74-39514C4CB54E} 23 | Packer 24 | 8.1 25 | MFCProj 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | MultiByte 33 | Dynamic 34 | 35 | 36 | Application 37 | false 38 | v140 39 | true 40 | MultiByte 41 | Dynamic 42 | 43 | 44 | Application 45 | true 46 | v140 47 | Unicode 48 | Dynamic 49 | 50 | 51 | Application 52 | false 53 | v140 54 | true 55 | Unicode 56 | Dynamic 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | true 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | false 87 | 88 | 89 | 90 | Use 91 | Level3 92 | Disabled 93 | WIN32;_WINDOWS;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Windows 98 | 99 | 100 | false 101 | true 102 | _DEBUG;%(PreprocessorDefinitions) 103 | 104 | 105 | 0x0804 106 | _DEBUG;%(PreprocessorDefinitions) 107 | $(IntDir);%(AdditionalIncludeDirectories) 108 | 109 | 110 | 111 | 112 | Use 113 | Level3 114 | Disabled 115 | _WINDOWS;_DEBUG;%(PreprocessorDefinitions) 116 | true 117 | 118 | 119 | Windows 120 | 121 | 122 | false 123 | true 124 | _DEBUG;%(PreprocessorDefinitions) 125 | 126 | 127 | 0x0804 128 | _DEBUG;%(PreprocessorDefinitions) 129 | $(IntDir);%(AdditionalIncludeDirectories) 130 | 131 | 132 | 133 | 134 | Level3 135 | Use 136 | MaxSpeed 137 | true 138 | true 139 | WIN32;_WINDOWS;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 140 | true 141 | 142 | 143 | Windows 144 | true 145 | true 146 | /SAFESEH:NO %(AdditionalOptions) 147 | 148 | 149 | false 150 | true 151 | NDEBUG;%(PreprocessorDefinitions) 152 | 153 | 154 | 0x0804 155 | NDEBUG;%(PreprocessorDefinitions) 156 | $(IntDir);%(AdditionalIncludeDirectories) 157 | 158 | 159 | 160 | 161 | Level3 162 | Use 163 | MaxSpeed 164 | true 165 | true 166 | _WINDOWS;NDEBUG;%(PreprocessorDefinitions) 167 | true 168 | 169 | 170 | Windows 171 | true 172 | true 173 | 174 | 175 | false 176 | true 177 | NDEBUG;%(PreprocessorDefinitions) 178 | 179 | 180 | 0x0804 181 | NDEBUG;%(PreprocessorDefinitions) 182 | $(IntDir);%(AdditionalIncludeDirectories) 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | Create 210 | Create 211 | Create 212 | Create 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /Packer/PictureEx.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////// 2 | // PictureEx.cpp: implementation of the CPictureEx class. 3 | // 4 | // Picture displaying control with support for the following formats: 5 | // GIF (including animated GIF87a and GIF89a), JPEG, BMP, WMF, ICO, CUR 6 | // 7 | // Written by Oleg Bykov (oleg_bykoff@rsdn.ru) 8 | // Copyright (c) 2001 9 | // 10 | // To use CPictureEx, follow these steps: 11 | // - place a static control on your dialog (either a text or a bitmap) 12 | // - change its identifier to something else (e.g. IDC_MYPIC) 13 | // - associate a CStatic with it using ClassWizard 14 | // - in your dialog's header file replace CStatic with CPictureEx 15 | // (don't forget to #include "PictureEx.h" and add 16 | // PictureEx.h and PictureEx.cpp to your project) 17 | // - call one of the overloaded CPictureEx::Load() functions somewhere 18 | // (OnInitDialog is a good place to start) 19 | // - if the preceding Load() succeeded call Draw() 20 | // 21 | // You can also add the control by defining a member variable of type 22 | // CPictureEx, calling CPictureEx::Create (derived from CStatic), then 23 | // CPictureEx::Load and CPictureEx::Draw. 24 | // 25 | // By default, the control initializes its background to COLOR_3DFACE 26 | // (see CPictureEx::PrepareDC()). You can change the background by 27 | // calling CPictureEx::SetBkColor(COLORREF) after CPictureEx::Load(). 28 | // 29 | // I decided to leave in the class the functions to write separate frames from 30 | // animated GIF to disk. If you want to use them, uncomment #define GIF_TRACING 31 | // and an appropriate section in CPictureEx::Load(HGLOBAL, DWORD). These functions 32 | // won't be compiled and linked to your project unless you uncomment #define GIF_TRACING, 33 | // so you don't have to worry. 34 | // 35 | // Warning: this code hasn't been subject to a heavy testing, so 36 | // use it on your own risk. The author accepts no liability for the 37 | // possible damage caused by this code. 38 | // 39 | // Version 1.0 7 Aug 2001 40 | // Initial release 41 | // 42 | // Version 1.1 6 Sept 2001 43 | // ATL version of the class 44 | // 45 | // Version 1.2 14 Oct 2001 46 | // - Fixed a problem with loading GIFs from resources 47 | // in MFC-version of the class for multi-modules apps. 48 | // Thanks to Ruben Avila-Carretero for finding this out. 49 | // 50 | // - Got rid of waitable timer in ThreadAnimation() 51 | // Now CPictureEx[Wnd] works in Win95 too. 52 | // Thanks to Alex Egiazarov and Wayne King for the idea. 53 | // 54 | // - Fixed a visual glitch of using SetBkColor. 55 | // Thanks to Kwangjin Lee for finding this out. 56 | // 57 | // Version 1.3 10 Nov 2001 58 | // - Fixed a DC leak. One DC leaked per each UnLoad() 59 | // (forgot to put a ReleaseDC() in the end of 60 | // CPictureExWnd::PrepareDC() function). 61 | // 62 | // - Now it is possible to set a clipping rectangle using 63 | // CPictureEx[Wnd]::SetPaintRect(const LPRECT) function. 64 | // The LPRECT parameter tells the class what portion of 65 | // a picture should it display. If the clipping rect is 66 | // not set, the whole picture is shown. 67 | // Thanks to Fabrice Rodriguez for the idea. 68 | // 69 | // - Added support for Stop/Draw. Now you can Stop() an 70 | // animated GIF, then Draw() it again, it will continue 71 | // animation from the frame it was stopped on. You can 72 | // also know if a GIF is currently playing with the 73 | // IsPlaying() function. 74 | // 75 | // - Got rid of math.h and made m_bExitThread volatile. 76 | // Thanks to Piotr Sawicki for the suggestion. 77 | // 78 | ////////////////////////////////////////////////////////////////////// 79 | 80 | #include "stdafx.h" 81 | #include "PictureEx.h" 82 | #include 83 | 84 | #ifdef _DEBUG 85 | #undef THIS_FILE 86 | static char THIS_FILE[]=__FILE__; 87 | #define new DEBUG_NEW 88 | #endif 89 | 90 | ////////////////////////////////////////////////////////////////////// 91 | // Nested structures member functions 92 | ////////////////////////////////////////////////////////////////////// 93 | 94 | inline int CPictureEx::TGIFControlExt::GetPackedValue(enum ControlExtValues Value) 95 | { 96 | int nRet = (int)m_cPacked; 97 | switch (Value) 98 | { 99 | case GCX_PACKED_DISPOSAL: 100 | nRet = (nRet & 28) >> 2; 101 | break; 102 | 103 | case GCX_PACKED_USERINPUT: 104 | nRet = (nRet & 2) >> 1; 105 | break; 106 | 107 | case GCX_PACKED_TRANSPCOLOR: 108 | nRet &= 1; 109 | break; 110 | }; 111 | 112 | return nRet; 113 | } 114 | 115 | inline int CPictureEx::TGIFLSDescriptor::GetPackedValue(enum LSDPackedValues Value) 116 | { 117 | int nRet = (int)m_cPacked; 118 | 119 | switch (Value) 120 | { 121 | case LSD_PACKED_GLOBALCT: 122 | nRet = nRet >> 7; 123 | break; 124 | 125 | case LSD_PACKED_CRESOLUTION: 126 | nRet = ((nRet & 0x70) >> 4) + 1; 127 | break; 128 | 129 | case LSD_PACKED_SORT: 130 | nRet = (nRet & 8) >> 3; 131 | break; 132 | 133 | case LSD_PACKED_GLOBALCTSIZE: 134 | nRet &= 7; 135 | break; 136 | }; 137 | 138 | return nRet; 139 | } 140 | 141 | inline int CPictureEx::TGIFImageDescriptor::GetPackedValue(enum IDPackedValues Value) 142 | { 143 | int nRet = (int)m_cPacked; 144 | 145 | switch (Value) 146 | { 147 | case ID_PACKED_LOCALCT: 148 | nRet >>= 7; 149 | break; 150 | 151 | case ID_PACKED_INTERLACE: 152 | nRet = ((nRet & 0x40) >> 6); 153 | break; 154 | 155 | case ID_PACKED_SORT: 156 | nRet = (nRet & 0x20) >> 5; 157 | break; 158 | 159 | case ID_PACKED_LOCALCTSIZE: 160 | nRet &= 7; 161 | break; 162 | }; 163 | 164 | return nRet; 165 | } 166 | 167 | 168 | ////////////////////////////////////////////////////////////////////// 169 | // Construction/Destruction 170 | ////////////////////////////////////////////////////////////////////// 171 | 172 | CPictureEx::CPictureEx() 173 | { 174 | // check structures size 175 | ASSERT(sizeof(TGIFImageDescriptor) == 10); 176 | ASSERT(sizeof(TGIFAppExtension) == 14); 177 | ASSERT(sizeof(TGIFPlainTextExt) == 15); 178 | ASSERT(sizeof(TGIFLSDescriptor) == 7); 179 | ASSERT(sizeof(TGIFControlExt) == 8); 180 | ASSERT(sizeof(TGIFCommentExt) == 2); 181 | ASSERT(sizeof(TGIFHeader) == 6); 182 | 183 | m_pGIFLSDescriptor = NULL; 184 | m_pGIFHeader = NULL; 185 | m_pPicture = NULL; 186 | m_pRawData = NULL; 187 | m_hThread = NULL; 188 | m_hBitmap = NULL; 189 | m_hMemDC = NULL; 190 | 191 | m_hDispMemDC = NULL; 192 | m_hDispMemBM = NULL; 193 | m_hDispOldBM = NULL; 194 | 195 | m_bIsInitialized = FALSE; 196 | m_bExitThread = FALSE; 197 | m_bIsPlaying = FALSE; 198 | m_bIsGIF = FALSE; 199 | m_clrBackground = RGB(255,255,255); // white by default 200 | m_nGlobalCTSize = 0; 201 | m_nCurrOffset = 0; 202 | m_nCurrFrame = 0; 203 | m_nDataSize = 0; 204 | m_PictureSize.cx = m_PictureSize.cy = 0; 205 | SetRect(&m_PaintRect,0,0,0,0); 206 | 207 | m_hExitEvent = CreateEvent(NULL,TRUE,FALSE,NULL); 208 | } 209 | 210 | CPictureEx::~CPictureEx() 211 | { 212 | UnLoad(); 213 | CloseHandle(m_hExitEvent); 214 | } 215 | 216 | BEGIN_MESSAGE_MAP(CPictureEx, CStatic) 217 | //{{AFX_MSG_MAP(CPictureEx) 218 | ON_WM_DESTROY() 219 | ON_WM_PAINT() 220 | //}}AFX_MSG_MAP 221 | END_MESSAGE_MAP() 222 | 223 | BOOL CPictureEx::Load(HGLOBAL hGlobal, DWORD dwSize) 224 | { 225 | IStream *pStream = NULL; 226 | UnLoad(); 227 | 228 | if (!(m_pRawData = reinterpret_cast (GlobalLock(hGlobal))) ) 229 | { 230 | TRACE(_T("Load: Error locking memory\n")); 231 | return FALSE; 232 | }; 233 | 234 | m_nDataSize = dwSize; 235 | m_pGIFHeader = reinterpret_cast (m_pRawData); 236 | 237 | if ((memcmp(&m_pGIFHeader->m_cSignature,"GIF",3) != 0) && 238 | ((memcmp(&m_pGIFHeader->m_cVersion,"87a",3) != 0) || 239 | (memcmp(&m_pGIFHeader->m_cVersion,"89a",3) != 0)) ) 240 | { 241 | // it's neither GIF87a nor GIF89a 242 | // do the default processing 243 | 244 | // clear GIF variables 245 | m_pRawData = NULL; 246 | GlobalUnlock(hGlobal); 247 | 248 | // don't delete memory on object's release 249 | if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK) 250 | return FALSE; 251 | 252 | if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture, 253 | reinterpret_cast(&m_pPicture)) != S_OK) 254 | { 255 | pStream->Release(); 256 | return FALSE; 257 | }; 258 | pStream->Release(); 259 | 260 | // store picture's size 261 | 262 | long hmWidth; 263 | long hmHeight; 264 | m_pPicture->get_Width(&hmWidth); 265 | m_pPicture->get_Height(&hmHeight); 266 | 267 | HDC hDC = ::GetDC(m_hWnd); 268 | m_PictureSize.cx = MulDiv(hmWidth, GetDeviceCaps(hDC,LOGPIXELSX), 2540); 269 | m_PictureSize.cy = MulDiv(hmHeight, GetDeviceCaps(hDC,LOGPIXELSY), 2540); 270 | ::ReleaseDC(m_hWnd,hDC); 271 | } 272 | else 273 | { 274 | // it's a GIF 275 | m_bIsGIF = TRUE; 276 | m_pGIFLSDescriptor = reinterpret_cast 277 | (m_pRawData + sizeof(TGIFHeader)); 278 | if (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT) == 1) 279 | { 280 | // calculate the globat color table size 281 | m_nGlobalCTSize = static_cast 282 | (3* (1 << (m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE)+1))); 283 | // get the background color if GCT is present 284 | unsigned char *pBkClr = m_pRawData + sizeof(TGIFHeader) + 285 | sizeof(TGIFLSDescriptor) + 3*m_pGIFLSDescriptor->m_cBkIndex; 286 | m_clrBackground = RGB(pBkClr[0],pBkClr[1],pBkClr[2]); 287 | }; 288 | 289 | // store the picture's size 290 | m_PictureSize.cx = m_pGIFLSDescriptor->m_wWidth; 291 | m_PictureSize.cy = m_pGIFLSDescriptor->m_wHeight; 292 | 293 | // determine frame count for this picture 294 | UINT nFrameCount=0; 295 | ResetDataPointer(); 296 | while (SkipNextGraphicBlock()) 297 | nFrameCount++; 298 | 299 | #ifdef GIF_TRACING 300 | TRACE( 301 | _T(" -= GIF encountered\n" 302 | "Logical Screen dimensions = %dx%d\n" 303 | "Global color table = %d\n" 304 | "Color depth = %d\n" 305 | "Sort flag = %d\n" 306 | "Size of Global Color Table = %d\n" 307 | "Background color index = %d\n" 308 | "Pixel aspect ratio = %d\n" 309 | "Frame count = %d\n" 310 | "Background color = %06Xh\n\n" 311 | ), 312 | m_pGIFLSDescriptor->m_wWidth, 313 | m_pGIFLSDescriptor->m_wHeight, 314 | m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCT), 315 | m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_CRESOLUTION), 316 | m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_SORT), 317 | m_pGIFLSDescriptor->GetPackedValue(LSD_PACKED_GLOBALCTSIZE), 318 | m_pGIFLSDescriptor->m_cBkIndex, 319 | m_pGIFLSDescriptor->m_cPixelAspect, 320 | nFrameCount, 321 | m_clrBackground 322 | ); 323 | EnumGIFBlocks(); 324 | #endif 325 | 326 | if (nFrameCount == 0) // it's an empty GIF! 327 | { 328 | m_pRawData = NULL; 329 | GlobalUnlock(hGlobal); 330 | return FALSE; 331 | }; 332 | 333 | // now check the frame count 334 | // if there's only one frame, no need to animate this GIF 335 | // therefore, treat it like any other pic 336 | 337 | if (nFrameCount == 1) 338 | { 339 | // clear GIF variables 340 | m_pRawData = NULL; 341 | GlobalUnlock(hGlobal); 342 | 343 | // don't delete memory on object's release 344 | if (CreateStreamOnHGlobal(hGlobal,FALSE,&pStream) != S_OK) 345 | return FALSE; 346 | 347 | if (OleLoadPicture(pStream,dwSize,FALSE,IID_IPicture, 348 | (LPVOID *)&m_pPicture) != S_OK) 349 | { 350 | pStream->Release(); 351 | return FALSE; 352 | }; 353 | 354 | pStream->Release(); 355 | } 356 | else 357 | { 358 | // if, on the contrary, there are several frames 359 | // then store separate frames in an array 360 | 361 | TFrame frame; 362 | UINT nBlockLen; 363 | HGLOBAL hFrameData; 364 | UINT nCurFrame = 0; 365 | 366 | ResetDataPointer(); 367 | while (hFrameData = GetNextGraphicBlock(&nBlockLen, 368 | &frame.m_nDelay, &frame.m_frameSize, 369 | &frame.m_frameOffset, &frame.m_nDisposal) ) 370 | { 371 | #ifdef GIF_TRACING 372 | ////////////////////////////////////////////// 373 | // uncomment the following strings if you want 374 | // to write separate frames on disk 375 | // 376 | // CString szName; 377 | // szName.Format(_T("%.4d.gif"),nCurFrame); 378 | // WriteDataOnDisk(szName,hFrameData,nBlockLen); 379 | // nCurFrame++; 380 | #endif // GIF_TRACING 381 | 382 | IStream *pStream = NULL; 383 | 384 | // delete memory on object's release 385 | if (CreateStreamOnHGlobal(hFrameData,TRUE,&pStream) != S_OK) 386 | { 387 | GlobalFree(hFrameData); 388 | continue; 389 | }; 390 | 391 | if (OleLoadPicture(pStream,nBlockLen,FALSE, 392 | IID_IPicture, 393 | reinterpret_cast(&frame.m_pPicture)) != S_OK) 394 | { 395 | pStream->Release(); 396 | continue; 397 | }; 398 | pStream->Release(); 399 | 400 | // everything went well, add this frame 401 | m_arrFrames.push_back(frame); 402 | }; 403 | 404 | // clean after ourselves 405 | m_pRawData = NULL; 406 | GlobalUnlock(hGlobal); 407 | 408 | if (m_arrFrames.empty()) // couldn't load any frames 409 | return FALSE; 410 | }; 411 | }; // if (!IsGIF... 412 | 413 | return PrepareDC(m_PictureSize.cx,m_PictureSize.cy); 414 | } 415 | 416 | void CPictureEx::UnLoad() 417 | { 418 | Stop(); 419 | if (m_pPicture) 420 | { 421 | m_pPicture->Release(); 422 | m_pPicture = NULL; 423 | }; 424 | 425 | std::vector::iterator it; 426 | for (it=m_arrFrames.begin();itRelease(); 428 | m_arrFrames.clear(); 429 | 430 | if (m_hMemDC) 431 | { 432 | SelectObject(m_hMemDC,m_hOldBitmap); 433 | ::DeleteDC(m_hMemDC); 434 | ::DeleteObject(m_hBitmap); 435 | m_hMemDC = NULL; 436 | m_hBitmap = NULL; 437 | }; 438 | 439 | if (m_hDispMemDC) 440 | { 441 | SelectObject(m_hDispMemDC,m_hDispOldBM); 442 | ::DeleteDC(m_hDispMemDC); 443 | ::DeleteObject(m_hDispMemBM); 444 | m_hDispMemDC = NULL; 445 | m_hDispMemBM = NULL; 446 | }; 447 | 448 | SetRect(&m_PaintRect,0,0,0,0); 449 | m_pGIFLSDescriptor = NULL; 450 | m_pGIFHeader = NULL; 451 | m_pRawData = NULL; 452 | m_hThread = NULL; 453 | m_bIsInitialized = FALSE; 454 | m_bExitThread = FALSE; 455 | m_bIsGIF = FALSE; 456 | m_clrBackground = RGB(255,255,255); // white by default 457 | m_nGlobalCTSize = 0; 458 | m_nCurrOffset = 0; 459 | m_nCurrFrame = 0; 460 | m_nDataSize = 0; 461 | } 462 | 463 | BOOL CPictureEx::Draw() 464 | { 465 | if (!m_bIsInitialized) 466 | { 467 | TRACE(_T("Call one of the CPictureEx::Load() member functions before calling Draw()\n")); 468 | return FALSE; 469 | }; 470 | 471 | if (IsAnimatedGIF()) 472 | { 473 | // the picture needs animation 474 | // we'll start the thread that will handle it for us 475 | 476 | unsigned int nDummy; 477 | m_hThread = (HANDLE) _beginthreadex(NULL,0,_ThreadAnimation,this, 478 | CREATE_SUSPENDED,&nDummy); 479 | if (!m_hThread) 480 | { 481 | TRACE(_T("Draw: Couldn't start a GIF animation thread\n")); 482 | return FALSE; 483 | } 484 | else 485 | ResumeThread(m_hThread); 486 | } 487 | else 488 | { 489 | if (m_pPicture) 490 | { 491 | long hmWidth; 492 | long hmHeight; 493 | m_pPicture->get_Width(&hmWidth); 494 | m_pPicture->get_Height(&hmHeight); 495 | if (m_pPicture->Render(m_hMemDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy, 496 | 0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK) 497 | { 498 | Invalidate(FALSE); 499 | return TRUE; 500 | }; 501 | }; 502 | }; 503 | 504 | return FALSE; 505 | } 506 | 507 | SIZE CPictureEx::GetSize() const 508 | { 509 | return m_PictureSize; 510 | } 511 | 512 | BOOL CPictureEx::Load(LPCTSTR szFileName) 513 | { 514 | ASSERT(szFileName); 515 | 516 | CFile file; 517 | HGLOBAL hGlobal; 518 | DWORD dwSize; 519 | 520 | if (!file.Open(szFileName, 521 | CFile::modeRead | 522 | CFile::shareDenyWrite) ) 523 | { 524 | TRACE(_T("Load (file): Error opening file %s\n"),szFileName); 525 | return FALSE; 526 | }; 527 | 528 | dwSize = file.GetLength(); 529 | hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize); 530 | if (!hGlobal) 531 | { 532 | TRACE(_T("Load (file): Error allocating memory\n")); 533 | return FALSE; 534 | }; 535 | 536 | char *pData = reinterpret_cast(GlobalLock(hGlobal)); 537 | if (!pData) 538 | { 539 | TRACE(_T("Load (file): Error locking memory\n")); 540 | GlobalFree(hGlobal); 541 | return FALSE; 542 | }; 543 | 544 | TRY 545 | { 546 | file.Read(pData,dwSize); 547 | } 548 | CATCH(CFileException, e); 549 | { 550 | TRACE(_T("Load (file): An exception occured while reading the file %s\n"), 551 | szFileName); 552 | GlobalFree(hGlobal); 553 | e->Delete(); 554 | file.Close(); 555 | return FALSE; 556 | } 557 | END_CATCH 558 | GlobalUnlock(hGlobal); 559 | file.Close(); 560 | 561 | BOOL bRetValue = Load(hGlobal,dwSize); 562 | GlobalFree(hGlobal); 563 | return bRetValue; 564 | } 565 | 566 | BOOL CPictureEx::Load(LPCTSTR szResourceName, LPCTSTR szResourceType) 567 | { 568 | ASSERT(szResourceName); 569 | ASSERT(szResourceType); 570 | 571 | HRSRC hPicture = FindResource(AfxGetResourceHandle(),szResourceName,szResourceType); 572 | HGLOBAL hResData; 573 | if (!hPicture || !(hResData = LoadResource(AfxGetResourceHandle(),hPicture))) 574 | { 575 | TRACE(_T("Load (resource): Error loading resource %s\n"),szResourceName); 576 | return FALSE; 577 | }; 578 | DWORD dwSize = SizeofResource(AfxGetResourceHandle(),hPicture); 579 | 580 | // hResData is not the real HGLOBAL (we can't lock it) 581 | // let's make it real 582 | 583 | HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD,dwSize); 584 | if (!hGlobal) 585 | { 586 | TRACE(_T("Load (resource): Error allocating memory\n")); 587 | FreeResource(hResData); 588 | return FALSE; 589 | }; 590 | 591 | char *pDest = reinterpret_cast (GlobalLock(hGlobal)); 592 | char *pSrc = reinterpret_cast (LockResource(hResData)); 593 | if (!pSrc || !pDest) 594 | { 595 | TRACE(_T("Load (resource): Error locking memory\n")); 596 | GlobalFree(hGlobal); 597 | FreeResource(hResData); 598 | return FALSE; 599 | }; 600 | CopyMemory(pDest,pSrc,dwSize); 601 | FreeResource(hResData); 602 | GlobalUnlock(hGlobal); 603 | 604 | BOOL bRetValue = Load(hGlobal,dwSize); 605 | GlobalFree(hGlobal); 606 | return bRetValue; 607 | } 608 | 609 | void CPictureEx::ResetDataPointer() 610 | { 611 | // skip header and logical screen descriptor 612 | m_nCurrOffset = 613 | sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize; 614 | } 615 | 616 | BOOL CPictureEx::SkipNextGraphicBlock() 617 | { 618 | if (!m_pRawData) return FALSE; 619 | 620 | // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data 621 | 622 | enum GIFBlockTypes nBlock; 623 | 624 | nBlock = GetNextBlock(); 625 | 626 | while ((nBlock != BLOCK_CONTROLEXT) && 627 | (nBlock != BLOCK_IMAGE) && 628 | (nBlock != BLOCK_PLAINTEXT) && 629 | (nBlock != BLOCK_UNKNOWN) && 630 | (nBlock != BLOCK_TRAILER) ) 631 | { 632 | if (!SkipNextBlock()) return NULL; 633 | nBlock = GetNextBlock(); 634 | }; 635 | 636 | if ((nBlock == BLOCK_UNKNOWN) || 637 | (nBlock == BLOCK_TRAILER)) 638 | return FALSE; 639 | 640 | // it's either a control ext.block, an image or a plain text 641 | 642 | if (GetNextBlockLen() <= 0) return FALSE; 643 | 644 | if (nBlock == BLOCK_CONTROLEXT) 645 | { 646 | if (!SkipNextBlock()) return FALSE; 647 | nBlock = GetNextBlock(); 648 | 649 | // skip everything until we meet an image block or a plain-text block 650 | while ((nBlock != BLOCK_IMAGE) && 651 | (nBlock != BLOCK_PLAINTEXT) && 652 | (nBlock != BLOCK_UNKNOWN) && 653 | (nBlock != BLOCK_TRAILER) ) 654 | { 655 | if (!SkipNextBlock()) return NULL; 656 | nBlock = GetNextBlock(); 657 | }; 658 | 659 | if ((nBlock == BLOCK_UNKNOWN) || 660 | (nBlock == BLOCK_TRAILER)) 661 | return FALSE; 662 | }; 663 | 664 | // skip the found data block (image or plain-text) 665 | if (!SkipNextBlock()) return FALSE; 666 | 667 | return TRUE; 668 | } 669 | 670 | UINT CPictureEx::GetSubBlocksLen(UINT nStartingOffset) const 671 | { 672 | UINT nRet = 0; 673 | UINT nCurOffset = nStartingOffset; 674 | 675 | while (m_pRawData[nCurOffset] != 0) 676 | { 677 | nRet += m_pRawData[nCurOffset]+1; 678 | nCurOffset += m_pRawData[nCurOffset]+1; 679 | }; 680 | 681 | return nRet+1; 682 | } 683 | 684 | enum CPictureEx::GIFBlockTypes CPictureEx::GetNextBlock() const 685 | { 686 | switch(m_pRawData[m_nCurrOffset]) 687 | { 688 | case 0x21: 689 | // extension block 690 | switch(m_pRawData[m_nCurrOffset+1]) 691 | { 692 | case 0x01: 693 | // plain text extension 694 | return BLOCK_PLAINTEXT; 695 | break; 696 | 697 | case 0xF9: 698 | // graphic control extension 699 | return BLOCK_CONTROLEXT; 700 | break; 701 | 702 | case 0xFE: 703 | // comment extension 704 | return BLOCK_COMMEXT; 705 | break; 706 | 707 | case 0xFF: 708 | // application extension 709 | return BLOCK_APPEXT; 710 | break; 711 | }; 712 | break; 713 | 714 | case 0x3B: 715 | // trailer 716 | return BLOCK_TRAILER; 717 | break; 718 | 719 | case 0x2C: 720 | // image data 721 | return BLOCK_IMAGE; 722 | break; 723 | }; 724 | 725 | return BLOCK_UNKNOWN; 726 | } 727 | 728 | BOOL CPictureEx::SkipNextBlock() 729 | { 730 | if (!m_pRawData) return FALSE; 731 | 732 | int nLen = GetNextBlockLen(); 733 | if ((nLen <= 0) || ((m_nCurrOffset+nLen) > m_nDataSize)) 734 | return FALSE; 735 | 736 | m_nCurrOffset += nLen; 737 | return TRUE; 738 | } 739 | 740 | int CPictureEx::GetNextBlockLen() const 741 | { 742 | GIFBlockTypes nBlock = GetNextBlock(); 743 | 744 | int nTmp; 745 | 746 | switch(nBlock) 747 | { 748 | case BLOCK_UNKNOWN: 749 | return -1; 750 | break; 751 | 752 | case BLOCK_TRAILER: 753 | return 1; 754 | break; 755 | 756 | case BLOCK_APPEXT: 757 | nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFAppExtension)); 758 | if (nTmp > 0) 759 | return sizeof(TGIFAppExtension)+nTmp; 760 | break; 761 | 762 | case BLOCK_COMMEXT: 763 | nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFCommentExt)); 764 | if (nTmp > 0) 765 | return sizeof(TGIFCommentExt)+nTmp; 766 | break; 767 | 768 | case BLOCK_CONTROLEXT: 769 | return sizeof(TGIFControlExt); 770 | break; 771 | 772 | case BLOCK_PLAINTEXT: 773 | nTmp = GetSubBlocksLen(m_nCurrOffset+sizeof(TGIFPlainTextExt)); 774 | if (nTmp > 0) 775 | return sizeof(TGIFPlainTextExt)+nTmp; 776 | break; 777 | 778 | case BLOCK_IMAGE: 779 | TGIFImageDescriptor *pIDescr = 780 | reinterpret_cast (&m_pRawData[m_nCurrOffset]); 781 | int nLCTSize = (int) 782 | (pIDescr->GetPackedValue(ID_PACKED_LOCALCT)*3* 783 | (1 << (pIDescr->GetPackedValue(ID_PACKED_LOCALCTSIZE)+1))); 784 | 785 | int nTmp = GetSubBlocksLen(m_nCurrOffset+ 786 | sizeof(TGIFImageDescriptor) + nLCTSize + 1); 787 | if (nTmp > 0) 788 | return sizeof(TGIFImageDescriptor) + nLCTSize + 1 + nTmp; 789 | break; 790 | }; 791 | 792 | return 0; 793 | } 794 | 795 | UINT WINAPI CPictureEx::_ThreadAnimation(LPVOID pParam) 796 | { 797 | ASSERT(pParam); 798 | CPictureEx *pPic = reinterpret_cast (pParam); 799 | 800 | pPic->m_bIsPlaying = TRUE; 801 | pPic->ThreadAnimation(); 802 | pPic->m_bIsPlaying = FALSE; 803 | 804 | // this thread has finished its work so we close the handle 805 | CloseHandle(pPic->m_hThread); 806 | // and init the handle to zero (so that Stop() doesn't Wait on it) 807 | pPic->m_hThread = 0; 808 | return 0; 809 | } 810 | 811 | void CPictureEx::ThreadAnimation() 812 | { 813 | // first, restore background (for stop/draw support) 814 | // disposal method #2 815 | if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2) 816 | { 817 | HBRUSH hBrush = CreateSolidBrush(m_clrBackground); 818 | if (hBrush) 819 | { 820 | RECT rect = { 821 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx, 822 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy, 823 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx, 824 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy }; 825 | FillRect(m_hMemDC,&rect,hBrush); 826 | DeleteObject(hBrush); 827 | }; 828 | } 829 | else 830 | // disposal method #3 831 | if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) ) 832 | { 833 | // put it back 834 | BitBlt(m_hMemDC, 835 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx, 836 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy, 837 | m_arrFrames[m_nCurrFrame].m_frameSize.cx, 838 | m_arrFrames[m_nCurrFrame].m_frameSize.cy, 839 | m_hDispMemDC,0,0, SRCCOPY); 840 | // init variables 841 | SelectObject(m_hDispMemDC,m_hDispOldBM); 842 | DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL; 843 | DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL; 844 | }; 845 | 846 | while (!m_bExitThread) 847 | { 848 | if (m_arrFrames[m_nCurrFrame].m_pPicture) 849 | { 850 | /////////////////////////////////////////////////////// 851 | // Before rendering a frame we should take care of what's 852 | // behind that frame. TFrame::m_nDisposal will be our guide: 853 | // 0 - no disposal specified (do nothing) 854 | // 1 - do not dispose (again, do nothing) 855 | // 2 - restore to background color (m_clrBackground) 856 | // 3 - restore to previous 857 | 858 | //////// disposal method #3 859 | if (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) 860 | { 861 | // prepare a memory DC and store the background in it 862 | m_hDispMemDC = CreateCompatibleDC(m_hMemDC); 863 | m_hDispMemBM = CreateCompatibleBitmap(m_hMemDC, 864 | m_arrFrames[m_nCurrFrame].m_frameSize.cx, 865 | m_arrFrames[m_nCurrFrame].m_frameSize.cy); 866 | 867 | if (m_hDispMemDC && m_hDispMemBM) 868 | { 869 | m_hDispOldBM = reinterpret_cast (SelectObject(m_hDispMemDC,m_hDispMemBM)); 870 | BitBlt(m_hDispMemDC,0,0, 871 | m_arrFrames[m_nCurrFrame].m_frameSize.cx, 872 | m_arrFrames[m_nCurrFrame].m_frameSize.cy, 873 | m_hMemDC, 874 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx, 875 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy, 876 | SRCCOPY); 877 | }; 878 | }; 879 | /////////////////////// 880 | 881 | long hmWidth; 882 | long hmHeight; 883 | m_arrFrames[m_nCurrFrame].m_pPicture->get_Width(&hmWidth); 884 | m_arrFrames[m_nCurrFrame].m_pPicture->get_Height(&hmHeight); 885 | 886 | if (m_arrFrames[m_nCurrFrame].m_pPicture->Render(m_hMemDC, 887 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx, 888 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy, 889 | m_arrFrames[m_nCurrFrame].m_frameSize.cx, 890 | m_arrFrames[m_nCurrFrame].m_frameSize.cy, 891 | 0, hmHeight, hmWidth, -hmHeight, NULL) == S_OK) 892 | { 893 | Invalidate(FALSE); 894 | }; 895 | 896 | if (m_bExitThread) break; 897 | 898 | // if the delay time is too short (like in old GIFs), wait for 100ms 899 | if (m_arrFrames[m_nCurrFrame].m_nDelay < 5) 900 | WaitForSingleObject(m_hExitEvent, 100); 901 | else 902 | WaitForSingleObject(m_hExitEvent, 10*m_arrFrames[m_nCurrFrame].m_nDelay); 903 | 904 | if (m_bExitThread) break; 905 | 906 | // disposal method #2 907 | if (m_arrFrames[m_nCurrFrame].m_nDisposal == 2) 908 | { 909 | HBRUSH hBrush = CreateSolidBrush(m_clrBackground); 910 | if (hBrush) 911 | { 912 | RECT rect = { 913 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx, 914 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy, 915 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx + m_arrFrames[m_nCurrFrame].m_frameSize.cx, 916 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy + m_arrFrames[m_nCurrFrame].m_frameSize.cy }; 917 | FillRect(m_hMemDC,&rect,hBrush); 918 | DeleteObject(hBrush); 919 | }; 920 | } 921 | else 922 | if (m_hDispMemDC && (m_arrFrames[m_nCurrFrame].m_nDisposal == 3) ) 923 | { 924 | // put it back 925 | BitBlt(m_hMemDC, 926 | m_arrFrames[m_nCurrFrame].m_frameOffset.cx, 927 | m_arrFrames[m_nCurrFrame].m_frameOffset.cy, 928 | m_arrFrames[m_nCurrFrame].m_frameSize.cx, 929 | m_arrFrames[m_nCurrFrame].m_frameSize.cy, 930 | m_hDispMemDC,0,0, SRCCOPY); 931 | // init variables 932 | SelectObject(m_hDispMemDC,m_hDispOldBM); 933 | DeleteDC(m_hDispMemDC); m_hDispMemDC = NULL; 934 | DeleteObject(m_hDispMemBM); m_hDispMemBM = NULL; 935 | }; 936 | }; 937 | m_nCurrFrame++; 938 | if (m_nCurrFrame == m_arrFrames.size()) 939 | { 940 | m_nCurrFrame 941 | = 0; 942 | // init the screen for the first frame, 943 | HBRUSH hBrush = CreateSolidBrush(m_clrBackground); 944 | if (hBrush) 945 | { 946 | RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy}; 947 | FillRect(m_hMemDC,&rect,hBrush); 948 | DeleteObject(hBrush); 949 | }; 950 | }; 951 | }; 952 | } 953 | 954 | void CPictureEx::Stop() 955 | { 956 | m_bIsPlaying = FALSE; 957 | m_bExitThread = TRUE; 958 | SetEvent(m_hExitEvent); 959 | if (m_hThread) 960 | { 961 | // we'll wait for 5 seconds then continue execution 962 | WaitForSingleObject(m_hThread,5000); 963 | CloseHandle(m_hThread); 964 | m_hThread = NULL; 965 | } 966 | 967 | // make it possible to Draw() again 968 | ResetEvent(m_hExitEvent); 969 | m_bExitThread = FALSE; 970 | } 971 | 972 | HGLOBAL CPictureEx::GetNextGraphicBlock(UINT *pBlockLen, 973 | UINT *pDelay, SIZE *pBlockSize, SIZE *pBlockOffset, 974 | UINT *pDisposal) 975 | { 976 | if (!m_pRawData) return NULL; 977 | 978 | // GIF header + LSDescriptor [+ GCT] [+ Control block] + Data 979 | 980 | *pDisposal = 0; 981 | enum GIFBlockTypes nBlock; 982 | nBlock = GetNextBlock(); 983 | 984 | while ( 985 | (nBlock != BLOCK_CONTROLEXT) && 986 | (nBlock != BLOCK_IMAGE) && 987 | (nBlock != BLOCK_PLAINTEXT) && 988 | (nBlock != BLOCK_UNKNOWN) && 989 | (nBlock != BLOCK_TRAILER) 990 | ) 991 | { 992 | if (!SkipNextBlock()) return NULL; 993 | nBlock = GetNextBlock(); 994 | }; 995 | 996 | if ((nBlock == BLOCK_UNKNOWN) || 997 | (nBlock == BLOCK_TRAILER)) 998 | return NULL; 999 | 1000 | // it's either a control ext.block, an image or a plain text 1001 | 1002 | int nStart = m_nCurrOffset; 1003 | int nBlockLen = GetNextBlockLen(); 1004 | 1005 | if (nBlockLen <= 0) return NULL; 1006 | 1007 | if (nBlock == BLOCK_CONTROLEXT) 1008 | { 1009 | // get the following data 1010 | TGIFControlExt *pControl = 1011 | reinterpret_cast (&m_pRawData[m_nCurrOffset]); 1012 | // store delay time 1013 | *pDelay = pControl->m_wDelayTime; 1014 | // store disposal method 1015 | *pDisposal = pControl->GetPackedValue(GCX_PACKED_DISPOSAL); 1016 | 1017 | if (!SkipNextBlock()) return NULL; 1018 | nBlock = GetNextBlock(); 1019 | 1020 | // skip everything until we find data to display 1021 | // (image block or plain-text block) 1022 | 1023 | while ( 1024 | (nBlock != BLOCK_IMAGE) && 1025 | (nBlock != BLOCK_PLAINTEXT) && 1026 | (nBlock != BLOCK_UNKNOWN) && 1027 | (nBlock != BLOCK_TRAILER) 1028 | ) 1029 | { 1030 | if (!SkipNextBlock()) return NULL; 1031 | nBlock = GetNextBlock(); 1032 | nBlockLen += GetNextBlockLen(); 1033 | }; 1034 | 1035 | if ((nBlock == BLOCK_UNKNOWN) || (nBlock == BLOCK_TRAILER)) 1036 | return NULL; 1037 | nBlockLen += GetNextBlockLen(); 1038 | } 1039 | else 1040 | *pDelay = -1; // to indicate that there was no delay value 1041 | 1042 | if (nBlock == BLOCK_IMAGE) 1043 | { 1044 | // store size and offsets 1045 | TGIFImageDescriptor *pImage = 1046 | reinterpret_cast (&m_pRawData[m_nCurrOffset]); 1047 | pBlockSize->cx = pImage->m_wWidth; 1048 | pBlockSize->cy = pImage->m_wHeight; 1049 | pBlockOffset->cx = pImage->m_wLeftPos; 1050 | pBlockOffset->cy = pImage->m_wTopPos; 1051 | }; 1052 | 1053 | if (!SkipNextBlock()) return NULL; 1054 | 1055 | HGLOBAL hGlobal = GlobalAlloc(GMEM_FIXED, 1056 | sizeof(TGIFHeader) + 1057 | sizeof(TGIFLSDescriptor) + 1058 | m_nGlobalCTSize + 1059 | nBlockLen + 1060 | 1); // for the trailer 1061 | 1062 | if (!hGlobal) return NULL; 1063 | 1064 | int nOffset = 0; 1065 | 1066 | // GMEM_FIXED means we get a pointer 1067 | unsigned char *pGlobal = reinterpret_cast (hGlobal); 1068 | 1069 | CopyMemory(pGlobal,m_pRawData, 1070 | sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize); 1071 | nOffset += sizeof(TGIFHeader)+sizeof(TGIFLSDescriptor)+m_nGlobalCTSize; 1072 | 1073 | CopyMemory(pGlobal + nOffset,&m_pRawData[nStart], nBlockLen); 1074 | nOffset += nBlockLen; 1075 | 1076 | pGlobal[nOffset] = 0x3B; // trailer 1077 | nOffset++; 1078 | 1079 | *pBlockLen = nOffset; 1080 | 1081 | return hGlobal; 1082 | } 1083 | 1084 | BOOL CPictureEx::IsGIF() const 1085 | { 1086 | return m_bIsGIF; 1087 | } 1088 | 1089 | BOOL CPictureEx::IsAnimatedGIF() const 1090 | { 1091 | return (m_bIsGIF && (m_arrFrames.size() > 1)); 1092 | } 1093 | 1094 | BOOL CPictureEx::IsPlaying() const 1095 | { 1096 | return m_bIsPlaying; 1097 | } 1098 | 1099 | int CPictureEx::GetFrameCount() const 1100 | { 1101 | if (!IsAnimatedGIF()) 1102 | return 0; 1103 | 1104 | return m_arrFrames.size(); 1105 | } 1106 | 1107 | COLORREF CPictureEx::GetBkColor() const 1108 | { 1109 | return m_clrBackground; 1110 | } 1111 | 1112 | void CPictureEx::OnPaint() 1113 | { 1114 | CPaintDC dc(this); // device context for painting 1115 | 1116 | LONG nPaintWidth = m_PaintRect.right-m_PaintRect.left; 1117 | 1118 | if (nPaintWidth > 0) 1119 | { 1120 | LONG nPaintHeight = m_PaintRect.bottom - m_PaintRect.top; 1121 | ::BitBlt(dc.m_hDC, 0, 0, nPaintWidth, nPaintHeight, 1122 | m_hMemDC, m_PaintRect.left, m_PaintRect.top, SRCCOPY); 1123 | } 1124 | else 1125 | { 1126 | ::BitBlt(dc.m_hDC, 0, 0, m_PictureSize.cx, m_PictureSize.cy, 1127 | m_hMemDC, 0, 0, SRCCOPY); 1128 | }; 1129 | } 1130 | 1131 | BOOL CPictureEx::PrepareDC(int nWidth, int nHeight) 1132 | { 1133 | SetWindowPos(NULL,0,0,nWidth,nHeight,SWP_NOMOVE | SWP_NOZORDER); 1134 | 1135 | HDC hWinDC = ::GetDC(m_hWnd); 1136 | if (!hWinDC) return FALSE; 1137 | 1138 | m_hMemDC = CreateCompatibleDC(hWinDC); 1139 | if (!m_hMemDC) 1140 | { 1141 | ::ReleaseDC(m_hWnd,hWinDC); 1142 | return FALSE; 1143 | }; 1144 | 1145 | m_hBitmap = CreateCompatibleBitmap(hWinDC,nWidth,nHeight); 1146 | if (!m_hBitmap) 1147 | { 1148 | ::ReleaseDC(m_hWnd,hWinDC); 1149 | ::DeleteDC(m_hMemDC); 1150 | return FALSE; 1151 | }; 1152 | 1153 | m_hOldBitmap = reinterpret_cast 1154 | (SelectObject(m_hMemDC,m_hBitmap)); 1155 | 1156 | // fill the background 1157 | m_clrBackground = GetSysColor(COLOR_3DFACE); 1158 | RECT rect = {0,0,nWidth,nHeight}; 1159 | FillRect(m_hMemDC,&rect,(HBRUSH)(COLOR_WINDOW)); 1160 | 1161 | ::ReleaseDC(m_hWnd,hWinDC); 1162 | m_bIsInitialized = TRUE; 1163 | return TRUE; 1164 | } 1165 | 1166 | void CPictureEx::OnDestroy() 1167 | { 1168 | Stop(); 1169 | CStatic::OnDestroy(); 1170 | } 1171 | 1172 | void CPictureEx::SetBkColor(COLORREF clr) 1173 | { 1174 | if (!m_bIsInitialized) return; 1175 | 1176 | m_clrBackground = clr; 1177 | 1178 | HBRUSH hBrush = CreateSolidBrush(clr); 1179 | if (hBrush) 1180 | { 1181 | RECT rect = {0,0,m_PictureSize.cx,m_PictureSize.cy}; 1182 | FillRect(m_hMemDC,&rect,hBrush); 1183 | DeleteObject(hBrush); 1184 | }; 1185 | } 1186 | 1187 | #ifdef GIF_TRACING 1188 | void CPictureEx::WriteDataOnDisk(CString szFileName, HGLOBAL hData, DWORD dwSize) 1189 | { 1190 | CFile file; 1191 | 1192 | if (!file.Open(szFileName, 1193 | CFile::modeCreate | 1194 | CFile::modeWrite | 1195 | CFile::shareDenyNone)) 1196 | { 1197 | TRACE(_T("WriteData: Error creating file %s\n"),szFileName); 1198 | return; 1199 | }; 1200 | 1201 | char *pData = reinterpret_cast (GlobalLock(hData)); 1202 | if (!pData) 1203 | { 1204 | TRACE(_T("WriteData: Error locking memory\n")); 1205 | return; 1206 | }; 1207 | 1208 | TRY 1209 | { 1210 | file.Write(pData,dwSize); 1211 | } 1212 | CATCH(CFileException, e); 1213 | { 1214 | TRACE(_T("WriteData: An exception occured while writing to the file %s\n"), 1215 | szFileName); 1216 | e->Delete(); 1217 | GlobalUnlock(hData); 1218 | file.Close(); 1219 | return; 1220 | } 1221 | END_CATCH 1222 | 1223 | GlobalUnlock(hData); 1224 | file.Close(); 1225 | } 1226 | 1227 | void CPictureEx::EnumGIFBlocks() 1228 | { 1229 | enum GIFBlockTypes nBlock; 1230 | 1231 | ResetDataPointer(); 1232 | while(m_nCurrOffset < m_nDataSize) 1233 | { 1234 | nBlock = GetNextBlock(); 1235 | switch(nBlock) 1236 | { 1237 | case BLOCK_UNKNOWN: 1238 | TRACE(_T("- Unknown block\n")); 1239 | return; 1240 | break; 1241 | 1242 | case BLOCK_TRAILER: 1243 | TRACE(_T("- Trailer block\n")); 1244 | break; 1245 | 1246 | case BLOCK_APPEXT: 1247 | TRACE(_T("- Application extension block\n")); 1248 | break; 1249 | 1250 | case BLOCK_COMMEXT: 1251 | TRACE(_T("- Comment extension block\n")); 1252 | break; 1253 | 1254 | case BLOCK_CONTROLEXT: 1255 | { 1256 | TGIFControlExt *pControl = 1257 | reinterpret_cast (&m_pRawData[m_nCurrOffset]); 1258 | TRACE(_T("- Graphic control extension block (delay %d, disposal %d)\n"), 1259 | pControl->m_wDelayTime, pControl->GetPackedValue(GCX_PACKED_DISPOSAL)); 1260 | }; 1261 | break; 1262 | 1263 | case BLOCK_PLAINTEXT: 1264 | TRACE(_T("- Plain text extension block\n")); 1265 | break; 1266 | 1267 | case BLOCK_IMAGE: 1268 | TGIFImageDescriptor *pIDescr = 1269 | reinterpret_cast (&m_pRawData[m_nCurrOffset]); 1270 | TRACE(_T("- Image data block (%dx%d %d,%d)\n"), 1271 | pIDescr->m_wWidth, 1272 | pIDescr->m_wHeight, 1273 | pIDescr->m_wLeftPos, 1274 | pIDescr->m_wTopPos); 1275 | break; 1276 | }; 1277 | 1278 | SkipNextBlock(); 1279 | }; 1280 | 1281 | TRACE(_T("\n")); 1282 | } 1283 | #endif // GIF_TRACING 1284 | 1285 | BOOL CPictureEx::SetPaintRect(const RECT *lpRect) 1286 | { 1287 | return CopyRect(&m_PaintRect, lpRect); 1288 | } 1289 | 1290 | BOOL CPictureEx::GetPaintRect(RECT *lpRect) 1291 | { 1292 | return CopyRect(lpRect, &m_PaintRect); 1293 | } 1294 | --------------------------------------------------------------------------------