├── 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 | 
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 | 
42 |
43 | 原始目录
44 |
45 | 
46 |
47 | 加壳后的区段信息
48 |
49 | 
50 |
51 | 加壳之后的目录表
52 |
53 | 
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------