Repository navigation
Expand file tree
/
Copy pathWaitCursor.cpp
More file actions
175 lines (136 loc) · 4.5 KB
/
Copy pathWaitCursor.cpp
File metadata and controls
175 lines (136 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
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
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
* $Header: /Cleaner/WaitCursor.cpp 15 22.03.02 12:58 Oslph312 $
*
* Thread challenges:
* 1. SetCursor from a different thread has no effect unless thread
* input has been attached.
* 2. Animation always works under debugger. With no debugger, requires
* a running thread. Which is why there are *two* calls to
* WaitForSingleObject in _threadFunc.
*
* Since we don't need CRT in the thread, plain Win thread function is OK.
*/
#include "precomp.h"
#include "String.h"
#include "WaitCursor.h"
#include "trace.h"
#define CURSOR_PATH _T( "Cursors\\" )
PRIVATE inline HCURSOR loadCursor( LPCTSTR pszName ) {
return static_cast< HCURSOR >( LoadImage( 0, pszName,
IMAGE_CURSOR, 0, 0,
LR_DEFAULTSIZE | LR_DEFAULTCOLOR | LR_LOADFROMFILE ) );
}
/*
* If we don't call AttachThreadInput, SetCursor has
* no effect when called from the worker thread.
*/
inline void WaitCursor::_attachThreadInput( bool bAttach ) const {
verify( AttachThreadInput(
GetCurrentThreadId(), _dwParentThreadId, bAttach ) );
}
void WaitCursor::_threadFunc( void ) const {
const DWORD dwRet = WaitForSingleObject( _hEvent, _nTimeIn );
if ( WAIT_TIMEOUT == dwRet ) {
_attachThreadInput( true );
_restore();
_attachThreadInput( false ); // Works OK withouth this...
// ...but without this, no animation unless in debugger.
verify( WAIT_OBJECT_0 == WaitForSingleObject( _hEvent, INFINITE ) );
}
assert( (DWORD) -1 != dwRet );
}
DWORD WINAPI WaitCursor::_threadFunc( void *pData ) {
const WaitCursor *pThis =
reinterpret_cast< WaitCursor * >( pData );
assert( isGoodConstPtr( pThis ) );
pThis->_threadFunc();
return 0;
}
void WaitCursor::_finishThread( void ) {
if ( 0 != _hEvent ) {
// Signal event, if necessary, to wake the thread.
// If the thread has finished already, no matter.
verify( SetEvent( _hEvent ) );
}
if ( 0 != _hThread ) {
verify( WAIT_OBJECT_0 == WaitForSingleObject( _hThread, INFINITE ) );
verify( CloseHandle( _hThread ) );
_hThread = 0;
}
if ( 0 != _hEvent ) {
verify( CloseHandle( _hEvent ) );
_hEvent = 0;
}
}
void WaitCursor::_restore( void ) const {
// Actually, 0 is an acceptable value for SetCursor,
// but _hcur is nevertheless not *supposed* to be 0 here:
assert( 0 != _hcur );
SetCursor( _hcur );
}
HCURSOR WaitCursor::_loadCursor( LPCTSTR pszName ) {
if ( 0 != pszName ) {
assert( isGoodStringPtr( pszName ) );
String strCursor( CURSOR_PATH );
strCursor += pszName;
PATHNAME szWindowsDirectory = { 0 };
const int nChars = GetWindowsDirectory(
szWindowsDirectory, dim( szWindowsDirectory ) );
if ( 0 < nChars && nChars < dim( szWindowsDirectory ) ) {
// We now have something like C:\\WINNT or C:\\WINDOWS.
// There's a terminating \\ if it is a root directory.
PATHNAME szCursorPath = { 0 };
_tmakepath_s( szCursorPath, 0, szWindowsDirectory, strCursor.c_str() , 0 );
// Sample szCursorPath = "C:\\WINNT\\Cursors\\load.ani"
return loadCursor( szCursorPath );
}
}
return 0;
}
/**
* The constructor attempts to load the named cursor.
* The pszName parameter should be relative to the Windows directory.
*/
WaitCursor::WaitCursor( LPCTSTR pszName, int nTimeIn )
: _nTimeIn( nTimeIn )
, _hThread( 0 )
, _hEvent( 0 )
, _dwParentThreadId( GetCurrentThreadId() )
, _hcur( _loadCursor( pszName ) )
, _isFromFile( 0 != _hcur )
{
if ( !_isFromFile ) {
_hcur = LoadCursor( 0, IDC_WAIT ); // NOTE: LR_SHARED is undoc!
}
if ( 0 < _nTimeIn ) {
_hEvent = CreateEvent( 0, true, false, 0 );
DWORD dwThreadId = 0; // Required under Win9x, not under NT.
_hThread = CreateThread( 0, 0, _threadFunc, this, 0, &dwThreadId );
}
if ( 0 == _hThread ) {
_restore();
}
}
WaitCursor::~WaitCursor() throw() {
_finishThread();
assert( 0 != _hcur );
if ( _isFromFile ) {
//verify( DestroyCursor( _hcur ) ); // NOTE: This fails.
DestroyCursor( _hcur );
}
reset_pointer( _hcur );
POINT pt; // Screen coordinates.
// SetCursorPos forces a WM_SETCURSOR message.
if ( !GetCursorPos( &pt ) ) {
trace( _T( "GetCursorPos failed!" ) );
assert( false );
} else if ( !SetCursorPos( pt.x, pt.y ) ) {
trace( _T( "SetCursorPos( %d, %d ) failed!" ), pt.x, pt.y );
assert( false );
}
}
void WaitCursor::restore( void ) {
_finishThread();
_restore();
}
// end of file