OSDN Git Service

Apply my experimental code and fixes for Japanese MS-Windows.
[winmerge-jp/winmerge-jp.git] / Src / DiffThread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    License (GPLv2+):
3 //    This program is free software; you can redistribute it and/or modify
4 //    it under the terms of the GNU General Public License as published by
5 //    the Free Software Foundation; either version 2 of the License, or (at
6 //    your option) any later version.
7 //    
8 //    This program is distributed in the hope that it will be useful, but
9 //    WITHOUT ANY WARRANTY; without even the implied warranty of
10 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //    GNU General Public License for more details.
12 //
13 //    You should have received a copy of the GNU General Public License
14 //    along with this program; if not, write to the Free Software
15 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 /////////////////////////////////////////////////////////////////////////////
17 /** 
18  * @file  DiffThread.cpp
19  *
20  * @brief Code for DiffThread class
21  */
22 // ID line follows -- this is updated by SVN
23 // $Id: DiffThread.cpp 6910 2009-07-12 09:06:54Z kimmov $
24
25 #include "stdafx.h"
26 #include "UnicodeString.h"
27 #include "diffcontext.h"
28 #include "diffthread.h"
29 #include "DirScan.h"
30 #include "Plugins.h"
31 #include "DiffItemList.h"
32 #include "PathContext.h"
33 #include "CompareStats.h"
34 #include "IAbortable.h"
35
36 /**
37  * @brief Force compare to be single-threaded.
38  * Set this to true in order to single step through entire compare process all
39  * in a single thread. Either edit this line, or breakpoint & change it in
40  * CompareDirectories() below.
41  *
42  * If you are going to debug compare procedure, you most probably need to set
43  * this to true. As Visual Studio seems to have real problems with debugging
44  * these threads otherwise.
45  */
46 static bool bSinglethreaded = false;
47
48 /** @brief abort handler for CDiffThread -- just a gateway to CDiffThread */
49 class DiffThreadAbortable : public IAbortable
50 {
51 // Implement DirScan's IAbortable
52 public:
53         virtual bool ShouldAbort() const { return m_diffthread->ShouldAbort(); }
54
55 // All this object does is forward ShouldAbort calls to its containing CDiffThread
56
57         DiffThreadAbortable(CDiffThread * diffthread) : m_diffthread(diffthread) { }
58         CDiffThread * m_diffthread;
59 };
60
61 /**
62  * @brief Default constructor.
63  */
64 CDiffThread::CDiffThread()
65 : m_pDiffContext(NULL)
66 , m_msgUpdateUI(0)
67 , m_hWnd(0)
68 , m_bAborting(FALSE)
69 {
70         ZeroMemory(&m_threads[0], sizeof(m_threads));
71         m_pDiffParm = new DiffFuncStruct;
72         m_pAbortgate = new DiffThreadAbortable(this);
73 }
74
75 /**
76  * @brief Destructor, release resources.
77  */
78 CDiffThread::~CDiffThread()
79 {
80         CloseHandle(m_pDiffParm->hSemaphore);
81         delete m_pDiffParm;
82         delete m_pAbortgate;
83 }
84
85 /**
86  * @brief Sets context pointer forwarded to thread.
87  * @param [in] pCtx Pointer to compare context.
88  */
89 void CDiffThread::SetContext(CDiffContext * pCtx)
90 {
91         m_pDiffContext = pCtx;
92 }
93
94 /**
95  * @brief runtime interface for child thread, called on child thread
96  */
97 bool CDiffThread::ShouldAbort() const
98 {
99         if (bSinglethreaded)
100         {
101                 MSG msg;
102                 while (::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
103                 {
104                         AfxGetApp()->PumpMessage();
105                 }
106         }
107         return m_bAborting;
108 }
109
110 /**
111  * @brief Start and run directory compare thread.
112  * @param [in] dir1 First directory to compare.
113  * @param [in] dir2 Second directory to compare.
114  * @return Success (1) or error for thread. Currently always 1.
115  */
116 UINT CDiffThread::CompareDirectories(const String & dir1,
117                 const String & dir2)
118 {
119         ASSERT(m_pDiffParm->nThreadState != THREAD_COMPARING);
120
121         m_pDiffParm->context = m_pDiffContext;
122         m_pDiffParm->msgUIUpdate = m_msgUpdateUI;
123         m_pDiffParm->hWindow = m_hWnd;
124         m_pDiffParm->m_pAbortgate = m_pAbortgate;
125         m_pDiffParm->bOnlyRequested = m_bOnlyRequested;
126         m_bAborting = FALSE;
127
128         m_pDiffParm->nThreadState = THREAD_COMPARING;
129
130         m_pDiffParm->hSemaphore = CreateSemaphore(0, 0, LONG_MAX, 0);
131
132         m_pDiffParm->context->m_pCompareStats->SetCompareState(CompareStats::STATE_START);
133
134         if (bSinglethreaded)
135         {
136                 if (m_bOnlyRequested == FALSE)
137                         DiffThreadCollect(m_pDiffParm);
138                 DiffThreadCompare(m_pDiffParm);
139         }
140         else
141         {
142                 if (m_bOnlyRequested == FALSE)
143                         m_threads[0] = AfxBeginThread(DiffThreadCollect, m_pDiffParm);
144                 m_threads[1] = AfxBeginThread(DiffThreadCompare, m_pDiffParm);
145         }
146
147         return 1;
148 }
149
150 /**
151  * @brief Set window receiving messages thread sends.
152  * @param [in] hWnd Hand to window to receive messages.
153  */
154 void CDiffThread::SetHwnd(HWND hWnd)
155 {
156         m_hWnd = hWnd;
157 }
158
159 /**
160  * @brief Set message-id for update message.
161  * @param [in] updateMsg Message-id for update message.
162  */
163 void CDiffThread::SetMessageIDs(UINT updateMsg)
164 {
165         m_msgUpdateUI = updateMsg;
166 }
167
168 /**
169  * @brief Selects to compare all or only selected items.
170  * @param [in] bSelected If TRUE only selected items are compared.
171  */
172 void CDiffThread::SetCompareSelected(bool bSelected /*=FALSE*/)
173 {
174         m_bOnlyRequested = bSelected;
175 }
176
177 /**
178  * @brief Returns thread's current state
179  */
180 UINT CDiffThread::GetThreadState() const
181 {
182         return m_pDiffParm->nThreadState;
183 }
184
185 /**
186  * @brief Item collection thread function.
187  *
188  * This thread is responsible for finding and collecting all items to compare
189  * to the item list.
190  * @param [in] lpParam Pointer to parameter structure.
191  * @return Thread's return value.
192  */
193 UINT DiffThreadCollect(LPVOID lpParam)
194 {
195         PathContext paths;
196         DiffFuncStruct *myStruct = (DiffFuncStruct *) lpParam;
197
198         ASSERT(myStruct->bOnlyRequested == FALSE);
199
200         // Stash abortable interface into context
201         myStruct->context->SetAbortable(myStruct->m_pAbortgate);
202
203         // keep the scripts alive during the Rescan
204         // when we exit the thread, we delete this and release the scripts
205         CAssureScriptsForThread scriptsForRescan;
206
207         bool casesensitive = false;
208         int depth = myStruct->context->m_bRecursive ? -1 : 0;
209
210         paths = myStruct->context->GetNormalizedPaths();
211
212         LPCTSTR subdir[3] = {_T(""), _T(""), _T("")}; // blank to start at roots specified in diff context
213 #ifdef _DEBUG
214         _CrtMemState memStateBefore;
215         _CrtMemState memStateAfter;
216         _CrtMemState memStateDiff;
217         _CrtMemCheckpoint(&memStateBefore);
218 #endif
219
220         // Build results list (except delaying file comparisons until below)
221         DirScan_GetItems(paths, subdir, myStruct,
222                         casesensitive, depth, NULL, myStruct->context->m_bWalkUniques);
223
224 #ifdef _DEBUG
225         _CrtMemCheckpoint(&memStateAfter);
226         _CrtMemDifference(&memStateDiff, &memStateBefore, &memStateAfter);
227         _CrtMemDumpStatistics(&memStateDiff);
228 #endif
229
230         // ReleaseSemaphore() once again to signal that collect phase is ready
231         ReleaseSemaphore(myStruct->hSemaphore, 1, 0);
232
233         // Send message to UI to update
234         PostMessage(myStruct->hWindow, myStruct->msgUIUpdate, 2, myStruct->bOnlyRequested);
235         return 1;
236 }
237
238 /**
239  * @brief Folder compare thread function.
240  *
241  * Compares items in item list. After compare is ready
242  * sends message to UI so UI can update itself.
243  * @param [in] lpParam Pointer to parameter structure.
244  * @return Thread's return value.
245  */
246 UINT DiffThreadCompare(LPVOID lpParam)
247 {
248         DiffFuncStruct *myStruct = (DiffFuncStruct *) lpParam;
249
250         // Stash abortable interface into context
251         myStruct->context->SetAbortable(myStruct->m_pAbortgate);
252
253         // keep the scripts alive during the Rescan
254         // when we exit the thread, we delete this and release the scripts
255         CAssureScriptsForThread scriptsForRescan;
256
257         myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_COMPARE);
258
259         // Now do all pending file comparisons
260         if (myStruct->bOnlyRequested)
261                 DirScan_CompareRequestedItems(myStruct, NULL);
262         else
263                 DirScan_CompareItems(myStruct, NULL);
264
265         myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_IDLE);
266
267         // Send message to UI to update
268         myStruct->nThreadState = CDiffThread::THREAD_COMPLETED;
269         // msgID=MSG_UI_UPDATE=1025 (2005-11-29, Perry)
270         PostMessage(myStruct->hWindow, myStruct->msgUIUpdate, NULL, myStruct->bOnlyRequested);
271         return 1;
272 }