1 // Written by Christopher E. Miller
2 // See the included license.txt for copyright and license details.
3 
4 
5 ///
6 module dfl.resources;
7 
8 private import dfl.internal.dlib;
9 
10 private import dfl.internal.utf, dfl.internal.winapi, dfl.base, dfl.drawing;
11 
12 
13 version(DFL_NO_RESOURCES)
14 {
15 }
16 else
17 {
18 	///
19 	class Resources // docmain
20 	{
21 		///
22 		this(HINSTANCE inst, WORD language = 0, bool owned = false)
23 		{
24 			this.hinst = inst;
25 			this.lang = language;
26 			this._owned = owned;
27 		}
28 		
29 		/// ditto
30 		// Note: libName gets unloaded and may take down all its resources with it.
31 		this(Dstring libName, WORD language = 0)
32 		{
33 			HINSTANCE inst;
34 			inst = loadLibraryEx(libName, LOAD_LIBRARY_AS_DATAFILE);
35 			if(!inst)
36 				throw new DflException("Unable to load resources from '" ~ libName ~ "'");
37 			this(inst, language, true); // Owned.
38 		}
39 		
40 		/+ // Let's not depend on Application; the user can do so if they wish.
41 		/// ditto
42 		this(WORD language = 0)
43 		{
44 			this(Application.getInstance(), language);
45 		}
46 		+/
47 		
48 		
49 		///
50 		void dispose()
51 		{
52 			assert(_owned);
53 			//if(hinst != Application.getInstance()) // ?
54 				FreeLibrary(hinst);
55 			hinst = null;
56 		}
57 		
58 		
59 		///
60 		final @property WORD language() // getter
61 		{
62 			return lang;
63 		}
64 		
65 		
66 		///
67 		final Icon getIcon(int id, bool defaultSize = true)
68 		in
69 		{
70 			assert(id >= WORD.min && id <= WORD.max);
71 		}
72 		body
73 		{
74 			/+
75 			HICON hi;
76 			hi = LoadIconA(hinst, cast(LPCSTR)cast(WORD)id);
77 			if(!hi)
78 				return null;
79 			return Icon.fromHandle(hi);
80 			+/
81 			HICON hi;
82 			hi = cast(HICON)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_ICON,
83 				0, 0, defaultSize ? (LR_DEFAULTSIZE | LR_SHARED) : 0);
84 			if(!hi)
85 				return null;
86 			return new Icon(hi, true); // Owned.
87 		}
88 		
89 		/// ditto
90 		final Icon getIcon(Dstring name, bool defaultSize = true)
91 		{
92 			/+
93 			HICON hi;
94 			hi = LoadIconA(hinst, unsafeStringz(name));
95 			if(!hi)
96 				return null;
97 			return Icon.fromHandle(hi);
98 			+/
99 			HICON hi;
100 			hi = cast(HICON)dfl.internal.utf.loadImage(hinst, name, IMAGE_ICON,
101 				0, 0, defaultSize ? (LR_DEFAULTSIZE | LR_SHARED) : 0);
102 			if(!hi)
103 				return null;
104 			return new Icon(hi, true); // Owned.
105 		}
106 		
107 		/// ditto
108 		final Icon getIcon(int id, int width, int height)
109 		in
110 		{
111 			assert(id >= WORD.min && id <= WORD.max);
112 		}
113 		body
114 		{
115 			// Can't have size 0 (plus causes Windows to use the actual size).
116 			//if(width <= 0 || height <= 0)
117 			//	_noload("icon");
118 			HICON hi;
119 			hi = cast(HICON)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_ICON,
120 				width, height, 0);
121 			if(!hi)
122 				return null;
123 			return new Icon(hi, true); // Owned.
124 		}
125 		
126 		/// ditto
127 		final Icon getIcon(Dstring name, int width, int height)
128 		{
129 			// Can't have size 0 (plus causes Windows to use the actual size).
130 			//if(width <= 0 || height <= 0)
131 			//	_noload("icon");
132 			HICON hi;
133 			hi = cast(HICON)dfl.internal.utf.loadImage(hinst, name, IMAGE_ICON,
134 				width, height, 0);
135 			if(!hi)
136 				return null;
137 			return new Icon(hi, true); // Owned.
138 		}
139 		
140 		deprecated alias getIcon loadIcon;
141 		
142 		
143 		///
144 		final Bitmap getBitmap(int id)
145 		in
146 		{
147 			assert(id >= WORD.min && id <= WORD.max);
148 		}
149 		body
150 		{
151 			HBITMAP h;
152 			h = cast(HBITMAP)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_BITMAP,
153 				0, 0, 0);
154 			if(!h)
155 				return null;
156 			return new Bitmap(h, true); // Owned.
157 		}
158 		
159 		/// ditto
160 		final Bitmap getBitmap(Dstring name)
161 		{
162 			HBITMAP h;
163 			h = cast(HBITMAP)loadImage(hinst, name, IMAGE_BITMAP,
164 				0, 0, 0);
165 			if(!h)
166 				return null;
167 			return new Bitmap(h, true); // Owned.
168 		}
169 		
170 		deprecated alias getBitmap loadBitmap;
171 		
172 		
173 		///
174 		final Cursor getCursor(int id)
175 		in
176 		{
177 			assert(id >= WORD.min && id <= WORD.max);
178 		}
179 		body
180 		{
181 			HCURSOR h;
182 			h = cast(HCURSOR)LoadImageA(hinst, cast(LPCSTR)cast(WORD)id, IMAGE_CURSOR,
183 				0, 0, 0);
184 			if(!h)
185 				return null;
186 			return new Cursor(h, true); // Owned.
187 		}
188 		
189 		/// ditto
190 		final Cursor getCursor(Dstring name)
191 		{
192 			HCURSOR h;
193 			h = cast(HCURSOR)loadImage(hinst, name, IMAGE_CURSOR,
194 				0, 0, 0);
195 			if(!h)
196 				return null;
197 			return new Cursor(h, true); // Owned.
198 		}
199 		
200 		deprecated alias getCursor loadCursor;
201 		
202 		
203 		///
204 		final Dstring getString(int id)
205 		in
206 		{
207 			assert(id >= WORD.min && id <= WORD.max);
208 		}
209 		body
210 		{
211 			// Not casting to wDstring because a resource isn't guaranteed to be the same size.
212 			wchar* ws = cast(wchar*)_getData(cast(LPCWSTR)RT_STRING, cast(LPCWSTR)cast(WORD)(id / 16 + 1)).ptr;
213 			Dstring result;
214 			if(ws)
215 			{
216 				int i;
217 				for(i = 0; i < (id & 15); i++)
218 				{
219 					ws += 1 + cast(size_t)*ws;
220 				}
221 				result = utf16stringtoUtf8string((ws + 1)[0 .. cast(size_t)*ws]);
222 			}
223 			return result;
224 		}
225 		
226 		deprecated alias getString loadString;
227 		
228 		
229 		// Used internally
230 		// NOTE: win9x doesn't like these strings to be on the heap!
231 		final void[] _getData(LPCWSTR type, LPCWSTR name) // internal
232 		{
233 			HRSRC hrc;
234 			hrc = FindResourceExW(hinst, type, name, lang);
235 			if(!hrc)
236 				return null;
237 			HGLOBAL hg = LoadResource(hinst, hrc);
238 			if(!hg)
239 				return null;
240 			LPVOID pv = LockResource(hg);
241 			if(!pv)
242 				return null;
243 			return pv[0 .. SizeofResource(hinst, hrc)];
244 		}
245 		
246 		///
247 		final void[] getData(int type, int id)
248 		in
249 		{
250 			assert(type >= WORD.min && type <= WORD.max);
251 			assert(id >= WORD.min && id <= WORD.max);
252 		}
253 		body
254 		{
255 			return _getData(cast(LPCWSTR)type, cast(LPCWSTR)id);
256 		}
257 		
258 		/// ditto
259 		final void[] getData(Dstring type, int id)
260 		in
261 		{
262 			assert(id >= WORD.min && id <= WORD.max);
263 		}
264 		body
265 		{
266 			return _getData(utf8stringToUtf16stringz(type), cast(LPCWSTR)id);
267 		}
268 		
269 		/// ditto
270 		final void[] getData(int type, Dstring name)
271 		in
272 		{
273 			assert(type >= WORD.min && type <= WORD.max);
274 		}
275 		body
276 		{
277 			return _getData(cast(LPCWSTR)type, utf8stringToUtf16stringz(name));
278 		}
279 		
280 		/// ditto
281 		final void[] getData(Dstring type, Dstring name)
282 		{
283 			return _getData(utf8stringToUtf16stringz(type), utf8stringToUtf16stringz(name));
284 		}
285 		
286 		
287 		~this()
288 		{
289 			if(_owned)
290 				dispose();
291 		}
292 		
293 		
294 		private:
295 		
296 		HINSTANCE hinst;
297 		WORD lang = 0;
298 		bool _owned = false;
299 		
300 		
301 		void _noload(Dstring type)
302 		{
303 			throw new DflException("Unable to load " ~ type ~ " resource");
304 		}
305 	}
306 }
307