1 // LDViewThumbExtractor.cpp : Implementation of CLDViewThumbExtractor
2 #include "stdafx.h"
3 #include "LDViewThumbs.h"
4 #include "LDViewThumbExtractor.h"
5 #include <TCFoundation/TCUserDefaults.h>
6 #include <TCFoundation/TCImage.h>
7 #include <TCFoundation/mystring.h>
8 
9 #define INSTALL_PATH_KEY "InstallPath"
10 #define INSTALL_PATH_4_1_KEY "InstallPath 4.1"
11 
12 //#define DEBUG_LOG
13 #ifdef DEBUG_LOG
14 FILE *g_logFile = NULL;
15 
logToFile(const wchar_t * text)16 void logToFile(const wchar_t *text)
17 {
18 	if (g_logFile != NULL)
19 	{
20 		fwrite(text, wcslen(text) * 2, 1, g_logFile);
21 		fwrite(L"\r\n", 4, 1, g_logFile);
22 		fflush(g_logFile);
23 	}
24 }
25 #endif // DEBUG_LOG
26 
27 /////////////////////////////////////////////////////////////////////////////
28 // CLDViewThumbExtractor
29 
findLDView(void)30 bool CLDViewThumbExtractor::findLDView(void)
31 {
32 	TCUserDefaults::setAppName("Travis Cobbs/LDView");
33 	UCSTR lDViewDir = TCUserDefaults::stringForKeyUC(INSTALL_PATH_4_1_KEY);
34 
35 	if (lDViewDir == NULL)
36 	{
37 		lDViewDir = TCUserDefaults::stringForKeyUC(INSTALL_PATH_KEY);
38 	}
39 	if (lDViewDir != NULL)
40 	{
41 		FILE *lDView;
42 
43 		m_ldviewDir = lDViewDir;
44 		delete lDViewDir;
45 		m_ldviewPath = m_ldviewDir + L"\\LDView.exe";
46 		lDView = _wfopen(m_ldviewPath.c_str(), L"rb");
47 		if (lDView)
48 		{
49 			fclose(lDView);
50 			return true;
51 		}
52 		m_ldviewPath = m_ldviewDir + L"\\LDView64.exe";
53 		lDView = _wfopen(m_ldviewPath.c_str(), L"rb");
54 		if (lDView)
55 		{
56 			fclose(lDView);
57 			return true;
58 		}
59 		m_ldviewPath = L"";
60 	}
61 #ifdef DEBUG_LOG
62 	logToFile(L"Could not find LDView.");
63 #endif // DEBUG_LOG
64 	return false;
65 }
66 
67 /*
68 static bool copyToClipboard(const wchar_t *value)
69 {
70 	int len = wcslen(value) + 1;
71 	HGLOBAL hBuf = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
72 		len * sizeof(wchar_t));
73 
74 	if (hBuf)
75 	{
76 		wchar_t *buf = (wchar_t*)GlobalLock(hBuf);
77 
78 		wcscpy(buf, value);
79 		GlobalUnlock(hBuf);
80 		if (OpenClipboard(NULL))
81 		{
82 			EmptyClipboard();
83 			SetClipboardData(CF_UNICODETEXT, hBuf);
84 			CloseClipboard();
85 			return true;
86 		}
87 		else
88 		{
89 			GlobalFree(hBuf);
90 		}
91 	}
92 	return false;
93 }
94 */
95 
processFile(const wchar_t * datPath,const wchar_t * imageFilename)96 bool CLDViewThumbExtractor::processFile(
97 	const wchar_t *datPath,
98 	const wchar_t *imageFilename)
99 {
100 	wchar_t commandLine[2048];
101 	STARTUPINFOW startupInfo;
102 	PROCESS_INFORMATION processInfo;
103 	int windowWidth = m_size.cx;
104 	int windowHeight = m_size.cy;
105 	DWORD priority = NORMAL_PRIORITY_CLASS;
106 
107 	if (windowWidth < 320)
108 	{
109 		windowWidth = 320;
110 	}
111 	if (windowHeight < 240)
112 	{
113 		windowHeight = 240;
114 	}
115 	wsprintfW(commandLine, L"\"%ls\" \"%ls\" -qq -SaveSnapshot=%ls -SaveActualSize=0 "
116 		L"-SaveWidth=%d -SaveHeight=%d -CheckPartTracker=0"
117 		L"-WindowWidth=%d -WindowHeight=%d -SaveZoomToFit=1 "
118 		L"-PreferenceSet=Thumbnails -SnapshotSuffix=.bmp",
119 		m_ldviewPath.c_str(), datPath, imageFilename, m_size.cx, m_size.cy,
120 		windowWidth, windowHeight);
121 	//copyToClipboard(commandLine);
122 	memset(&startupInfo, 0, sizeof(startupInfo));
123 	startupInfo.cb = sizeof(startupInfo);
124 	startupInfo.dwFlags = STARTF_USEPOSITION;
125 	startupInfo.dwX = 0;
126 	startupInfo.dwY = 0;
127 #ifdef DEBUG_LOG
128 	logToFile(commandLine);
129 #endif // DEBUG_LOG
130 	debugLog1s("ThumbsLog", L"Launching: %s\r\n", commandLine);
131 	if (CreateProcessW(m_ldviewPath.c_str(), commandLine, NULL, NULL, FALSE,
132 		DETACHED_PROCESS | priority, NULL, NULL, &startupInfo, &processInfo))
133 	{
134 		while (1)
135 		{
136 			DWORD exitCode;
137 
138 			GetExitCodeProcess(processInfo.hProcess, &exitCode);
139 			if (exitCode != STILL_ACTIVE)
140 			{
141 				debugLog("ThumbsLog", L"LDView exit code: %d\r\n", exitCode);
142 				printf("Done.\n");
143 				return true;
144 			}
145 			Sleep(50);
146 		}
147 	}
148 	else
149 	{
150 		DWORD error = GetLastError();
151 		char *buf;
152 
153 		printf("Failed!\n");
154 		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
155 			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
156 			error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf,
157 			0, NULL);
158 		printf("%s\n", buf);
159 		debugLog("ThumbsLog", L"Error launching:\r\n%s\r\n", buf);
160 		LocalFree(buf);
161 		return false;
162 	}
163 }
164 
165 
166 
167 ////////////////////////////////////////////////////////////////////////////
168 // IPersistFile Begin
169 ////////////////////////////////////////////////////////////////////////////
170 
Load(LPCOLESTR pszFileName,DWORD)171 STDMETHODIMP CLDViewThumbExtractor::Load(
172 	/* [in] */ LPCOLESTR pszFileName,
173 	/* [in] */ DWORD /*dwMode*/)
174 {
175 	if (!findLDView())
176 	{
177 		return E_FAIL;
178 	}
179 	m_path = pszFileName;
180 	return S_OK;
181 }
182 
183 ////////////////////////////////////////////////////////////////////////////
184 // IPersistFile End
185 ////////////////////////////////////////////////////////////////////////////
186 
187 
188 
189 ////////////////////////////////////////////////////////////////////////////
190 // IExtractImage2 Begin
191 ////////////////////////////////////////////////////////////////////////////
GetLocation(LPWSTR pszPathBuffer,DWORD cch,DWORD *,const SIZE * prgSize,DWORD,DWORD * pdwFlags)192 STDMETHODIMP CLDViewThumbExtractor::GetLocation(
193 	/* [size_is][out] */ LPWSTR pszPathBuffer,
194 	/* [in] */ DWORD cch,
195 	/* [unique][out][in] */ DWORD * /*pdwPriority*/,
196 	/* [in] */ const SIZE *prgSize,
197 	/* [in] */ DWORD /*dwRecClrDepth*/,
198 	/* [out][in] */ DWORD *pdwFlags)
199 {
200 	if (cch > 0)
201 	{
202 		pszPathBuffer[0] = 0;
203 	}
204 	m_size = *prgSize;
205 	*pdwFlags |= IEIFLAG_CACHE;
206 	if (*pdwFlags & IEIFLAG_ASYNC)
207 	{
208 		return E_PENDING;
209 	}
210 	else
211 	{
212 		return S_OK;
213 	}
214 }
215 
isLDrawFile(void)216 bool CLDViewThumbExtractor::isLDrawFile(void)
217 {
218 	std::string filename;
219 	FILE *file;
220 	bool retValue = false;
221 
222 	wstringtoutf8(filename, m_path);
223 	file = ucfopen(filename.c_str(), "rb");
224 	if (file != NULL)
225 	{
226 		while (!retValue)
227 		{
228 			char buf[1024];
229 			char *spot = buf;
230 
231 			if (fgets(buf, sizeof(buf), file) == NULL)
232 			{
233 				break;
234 			}
235 			buf[sizeof(buf) - 1] = 0;
236 			replaceStringCharacter(buf, '\t', ' ');
237 			stripCRLF(buf);
238 			while (spot[0] == ' ' || spot[0] == '\r' || spot[0] == '\n')
239 			{
240 				spot++;
241 			}
242 			if (spot[0] == '0' && (spot[1] == ' ' || spot[1] == 0))
243 			{
244 			}
245 			else if (spot[0] >= '1' && spot[0] <= '5' && spot[1] == ' ')
246 			{
247 				retValue = true;
248 			}
249 			else if (spot[0])
250 			{
251 #ifdef DEBUG_LOG
252 			if (g_logFile != NULL)
253 			{
254 				std::wstring message = L"FAILED on line: ";
255 				std::wstring tempString;
256 
257 				utf8towstring(tempString, buf);
258 				message += tempString;
259 				logToFile(message.c_str());
260 			}
261 #endif // DEBUG_LOG
262 				break;
263 			}
264 		}
265 		fclose(file);
266 	}
267 	return retValue;
268 }
269 
Extract(HBITMAP * phBmpThumbnail)270 STDMETHODIMP CLDViewThumbExtractor::Extract(/* [out] */ HBITMAP *phBmpThumbnail)
271 {
272 	HRESULT hr = E_FAIL;
273 
274 #ifdef DEBUG_LOG
275 	g_logFile = ucfopen("C:\\temp\\LDViewThumbs.log", "ab");
276 #endif // DEBUG_LOG
277 	*phBmpThumbnail = NULL;
278 	if (findLDView() && isLDrawFile())
279 	{
280 		wchar_t wszTempPath[1024];
281 		wchar_t wszTempFilename[MAX_PATH + 16];
282 
283 		if (GetTempPathW(sizeof(wszTempPath) / sizeof(wszTempPath[0]), wszTempPath) == 0)
284 		{
285 			wcscpy(wszTempPath, L"C:\\Temp");
286 		}
287 		if (GetTempFileNameW(wszTempPath, L"LDVThumb", 0, wszTempFilename))
288 		{
289 			if (processFile(m_path.c_str(), wszTempFilename))
290 			{
291 				TCImage *image = new TCImage;
292 				std::string tempFilename;
293 
294 				image->setFlipped(true);
295 				image->setLineAlignment(4);
296 				wstringtoutf8(tempFilename, wszTempFilename);
297 				if (image->loadFile(tempFilename.c_str()))
298 				{
299 					BITMAPINFO bmInfo;
300 					TCByte *bmData;
301 					TCByte *imageData;
302 					int imageWidth;
303 					int imageHeight;
304 					int srcRowSize;
305 					int dstRowSize;
306 					int row;
307 					int col;
308 					HBITMAP hbm;
309 
310 					SetLastError(0);
311 					bmInfo.bmiHeader.biSize = sizeof(bmInfo.bmiHeader);
312 					bmInfo.bmiHeader.biWidth = image->getWidth();
313 					bmInfo.bmiHeader.biHeight = image->getHeight();
314 					bmInfo.bmiHeader.biPlanes = 1;
315 					bmInfo.bmiHeader.biBitCount = 24;
316 					bmInfo.bmiHeader.biCompression = BI_RGB;
317 					bmInfo.bmiHeader.biSizeImage = 0;
318 					bmInfo.bmiHeader.biXPelsPerMeter = 1;
319 					bmInfo.bmiHeader.biYPelsPerMeter = 1;
320 					bmInfo.bmiHeader.biClrUsed = 0;
321 					bmInfo.bmiHeader.biClrImportant = 0;
322 					HDC hMEMDC = CreateCompatibleDC(NULL);
323 					hbm = CreateDIBSection(hMEMDC, &bmInfo, DIB_RGB_COLORS,
324 						(void**)&bmData, NULL, 0);
325 					imageData = image->getImageData();
326 					imageWidth = image->getWidth();
327 					imageHeight = image->getHeight();
328 					srcRowSize = image->getRowSize();
329 					dstRowSize = TCImage::roundUp(imageWidth * 3, 4);
330 					for (row = 0; row < imageHeight; row++)
331 					{
332 						for (col = 0; col < imageWidth; col++)
333 						{
334 							int srcOffset = row * srcRowSize + col * 3;
335 							int dstOffset = row * dstRowSize + col * 3;
336 
337 							bmData[dstOffset] = imageData[srcOffset + 2];
338 							bmData[dstOffset + 1] = imageData[srcOffset + 1];
339 							bmData[dstOffset + 2] = imageData[srcOffset];
340 						}
341 					}
342 					*phBmpThumbnail = hbm;
343 					hr = S_OK;
344 				}
345 				image->release();
346 			}
347 			DeleteFileW(wszTempFilename);
348 		}
349 	}
350 #ifdef DEBUG_LOG
351 	if (g_logFile != NULL)
352 	{
353 		fclose(g_logFile);
354 		g_logFile = NULL;
355 	}
356 #endif // DEBUG_LOG
357 	return hr;
358 }
359 
GetDateStamp(FILETIME * pDateStamp)360 STDMETHODIMP CLDViewThumbExtractor::GetDateStamp(/* [out] */ FILETIME *pDateStamp)
361 {
362     FILETIME ftCreate, ftAccess, ftWrite;
363 	HANDLE hFile = CreateFileW(m_path.c_str(), GENERIC_READ, FILE_SHARE_READ,
364 		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
365 
366 	if (!hFile)
367 	{
368 		return E_ACCESSDENIED;
369 	}
370 	if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
371 	{
372 		CloseHandle(hFile);
373 		return E_ACCESSDENIED;
374 	}
375 	*pDateStamp = ftWrite;
376 	CloseHandle(hFile);
377 	return S_OK;
378 }
379 
380 ////////////////////////////////////////////////////////////////////////////
381 // IExtractImage2 End
382 ////////////////////////////////////////////////////////////////////////////
383