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