~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/user32/tests/winstation.c

Version: ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Unit tests for window stations and desktops
  3  *
  4  * Copyright 2002 Alexandre Julliard
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2.1 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #include "wine/test.h"
 22 #include "winbase.h"
 23 #include "wingdi.h"
 24 #include "winuser.h"
 25 #include "winnls.h"
 26 
 27 #define DESKTOP_ALL_ACCESS 0x01ff
 28 
 29 static void print_object( HANDLE obj )
 30 {
 31     char buffer[100];
 32     DWORD size;
 33 
 34     strcpy( buffer, "foobar" );
 35     if (!GetUserObjectInformationA( obj, UOI_NAME, buffer, sizeof(buffer), &size ))
 36         trace( "could not get info for %p\n", obj );
 37     else
 38         trace( "obj %p name '%s'\n", obj, buffer );
 39     strcpy( buffer, "foobar" );
 40     if (!GetUserObjectInformationA( obj, UOI_TYPE, buffer, sizeof(buffer), &size ))
 41         trace( "could not get type for %p\n", obj );
 42     else
 43         trace( "obj %p type '%s'\n", obj, buffer );
 44 }
 45 
 46 static void register_class(void)
 47 {
 48     WNDCLASSA cls;
 49 
 50     cls.style = CS_DBLCLKS;
 51     cls.lpfnWndProc = DefWindowProcA;
 52     cls.cbClsExtra = 0;
 53     cls.cbWndExtra = 0;
 54     cls.hInstance = GetModuleHandleA(0);
 55     cls.hIcon = 0;
 56     cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
 57     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
 58     cls.lpszMenuName = NULL;
 59     cls.lpszClassName = "WinStationClass";
 60     RegisterClassA(&cls);
 61 }
 62 
 63 static HDESK initial_desktop;
 64 
 65 static DWORD CALLBACK thread( LPVOID arg )
 66 {
 67     HDESK d1, d2;
 68     HWND hwnd = CreateWindowExA(0,"WinStationClass","test",WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0);
 69     ok( hwnd != 0, "CreateWindow failed\n" );
 70     d1 = GetThreadDesktop(GetCurrentThreadId());
 71     trace( "thread %p desktop: %p\n", arg, d1 );
 72     ok( d1 == initial_desktop, "thread %p doesn't use initial desktop\n", arg );
 73 
 74     SetLastError( 0xdeadbeef );
 75     ok( !CloseHandle( d1 ), "CloseHandle succeeded\n" );
 76     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
 77     SetLastError( 0xdeadbeef );
 78     ok( !CloseDesktop( d1 ), "CloseDesktop succeeded\n" );
 79     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
 80     print_object( d1 );
 81     d2 = CreateDesktop( "foobar2", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
 82     trace( "created desktop %p\n", d2 );
 83     ok( d2 != 0, "CreateDesktop failed\n" );
 84 
 85     SetLastError( 0xdeadbeef );
 86     ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" );
 87     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
 88 
 89     DestroyWindow( hwnd );
 90     ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" );
 91     d1 = GetThreadDesktop(GetCurrentThreadId());
 92     ok( d1 == d2, "GetThreadDesktop did not return set desktop %p/%p\n", d1, d2 );
 93     print_object( d2 );
 94     if (arg < (LPVOID)5)
 95     {
 96         HANDLE hthread = CreateThread( NULL, 0, thread, (char *)arg + 1, 0, NULL );
 97         Sleep(1000);
 98         WaitForSingleObject( hthread, INFINITE );
 99         CloseHandle( hthread );
100     }
101     return 0;
102 }
103 
104 static void test_handles(void)
105 {
106     HWINSTA w1, w2, w3;
107     HDESK d1, d2, d3;
108     HANDLE hthread;
109     DWORD id, flags;
110     ATOM atom;
111     char buffer[20];
112 
113     /* win stations */
114 
115     w1 = GetProcessWindowStation();
116     ok( GetProcessWindowStation() == w1, "GetProcessWindowStation returned different handles\n" );
117     ok( !CloseWindowStation(w1), "closing process win station succeeded\n" );
118     SetLastError( 0xdeadbeef );
119     ok( !CloseHandle(w1), "closing process win station handle succeeded\n" );
120     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
121     print_object( w1 );
122 
123     flags = 0;
124     ok( GetHandleInformation( w1, &flags ), "GetHandleInformation failed\n" );
125     ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) ||
126         broken(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), /* set on nt4 */
127         "handle %p PROTECT_FROM_CLOSE set\n", w1 );
128 
129     ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
130                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
131     ok( CloseWindowStation(w2), "closing dup win station failed\n" );
132 
133     ok( DuplicateHandle( GetCurrentProcess(), w1, GetCurrentProcess(), (PHANDLE)&w2, 0,
134                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
135     ok( CloseHandle(w2), "closing dup win station handle failed\n" );
136 
137     w2 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
138     ok( w2 != 0, "CreateWindowStation failed\n" );
139     ok( w2 != w1, "CreateWindowStation returned default handle\n" );
140     SetLastError( 0xdeadbeef );
141     ok( !CloseDesktop( (HDESK)w2 ), "CloseDesktop succeeded on win station\n" );
142     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
143     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
144 
145     w2 = CreateWindowStation("WinSta0", 0, WINSTA_ALL_ACCESS, NULL );
146     ok( CloseHandle( w2 ), "CloseHandle failed\n" );
147 
148     w2 = OpenWindowStation("winsta0", TRUE, WINSTA_ALL_ACCESS );
149     ok( w2 != 0, "OpenWindowStation failed\n" );
150     ok( w2 != w1, "OpenWindowStation returned default handle\n" );
151     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
152 
153     w2 = OpenWindowStation("dummy name", TRUE, WINSTA_ALL_ACCESS );
154     ok( !w2, "open dummy win station succeeded\n" );
155 
156     CreateMutexA( NULL, 0, "foobar" );
157     w2 = CreateWindowStation("foobar", 0, WINSTA_ALL_ACCESS, NULL );
158     ok( w2 != 0, "create foobar station failed\n" );
159 
160     w3 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
161     ok( w3 != 0, "open foobar station failed\n" );
162     ok( w3 != w2, "open foobar station returned same handle\n" );
163     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
164     ok( CloseWindowStation( w3 ), "CloseWindowStation failed\n" );
165 
166     w3 = OpenWindowStation("foobar", TRUE, WINSTA_ALL_ACCESS );
167     ok( !w3, "open foobar station succeeded\n" );
168 
169     w2 = CreateWindowStation("foobar1", 0, WINSTA_ALL_ACCESS, NULL );
170     ok( w2 != 0, "create foobar station failed\n" );
171     w3 = CreateWindowStation("foobar2", 0, WINSTA_ALL_ACCESS, NULL );
172     ok( w3 != 0, "create foobar station failed\n" );
173     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
174     ok( GetHandleInformation( w3, &flags ), "GetHandleInformation failed\n" );
175 
176     SetProcessWindowStation( w2 );
177     register_class();
178     atom = GlobalAddAtomA("foo");
179     ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
180     ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
181 
182     ok( !CloseWindowStation( w2 ), "CloseWindowStation succeeded\n" );
183     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
184 
185     SetProcessWindowStation( w3 );
186     ok( GetHandleInformation( w2, &flags ), "GetHandleInformation failed\n" );
187     ok( CloseWindowStation( w2 ), "CloseWindowStation failed\n" );
188     ok( GlobalGetAtomNameA( atom, buffer, sizeof(buffer) ) == 3, "GlobalGetAtomName failed\n" );
189     ok( !lstrcmpiA( buffer, "foo" ), "bad atom value %s\n", buffer );
190 
191     /* desktops */
192     d1 = GetThreadDesktop(GetCurrentThreadId());
193     initial_desktop = d1;
194     ok( GetThreadDesktop(GetCurrentThreadId()) == d1,
195         "GetThreadDesktop returned different handles\n" );
196 
197     flags = 0;
198     ok( GetHandleInformation( d1, &flags ), "GetHandleInformation failed\n" );
199     ok( !(flags & HANDLE_FLAG_PROTECT_FROM_CLOSE), "handle %p PROTECT_FROM_CLOSE set\n", d1 );
200 
201     SetLastError( 0xdeadbeef );
202     ok( !CloseDesktop(d1), "closing thread desktop succeeded\n" );
203     ok( GetLastError() == ERROR_BUSY, "bad last error %d\n", GetLastError() );
204 
205     SetLastError( 0xdeadbeef );
206     if (CloseHandle( d1 ))  /* succeeds on nt4 */
207     {
208         win_skip( "NT4 desktop handle management is completely different\n" );
209         return;
210     }
211     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
212 
213     ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
214                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
215     ok( CloseDesktop(d2), "closing dup desktop failed\n" );
216 
217     ok( DuplicateHandle( GetCurrentProcess(), d1, GetCurrentProcess(), (PHANDLE)&d2, 0,
218                          TRUE, DUPLICATE_SAME_ACCESS ), "DuplicateHandle failed\n" );
219     ok( CloseHandle(d2), "closing dup desktop handle failed\n" );
220 
221     d2 = OpenDesktop( "dummy name", 0, TRUE, DESKTOP_ALL_ACCESS );
222     ok( !d2, "open dummy desktop succeeded\n" );
223 
224     d2 = CreateDesktop( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
225     ok( d2 != 0, "create foobar desktop failed\n" );
226     SetLastError( 0xdeadbeef );
227     ok( !CloseWindowStation( (HWINSTA)d2 ), "CloseWindowStation succeeded on desktop\n" );
228     ok( GetLastError() == ERROR_INVALID_HANDLE, "bad last error %d\n", GetLastError() );
229 
230     SetLastError( 0xdeadbeef );
231     d3 = CreateDesktop( "foobar", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL );
232     ok( d3 != 0, "create foobar desktop again failed\n" );
233     ok( GetLastError() == 0xdeadbeef, "bad last error %d\n", GetLastError() );
234     ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
235 
236     d3 = OpenDesktop( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
237     ok( d3 != 0, "open foobar desktop failed\n" );
238     ok( d3 != d2, "open foobar desktop returned same handle\n" );
239     ok( CloseDesktop( d2 ), "CloseDesktop failed\n" );
240     ok( CloseDesktop( d3 ), "CloseDesktop failed\n" );
241 
242     d3 = OpenDesktop( "foobar", 0, TRUE, DESKTOP_ALL_ACCESS );
243     ok( !d3, "open foobar desktop succeeded\n" );
244 
245     ok( !CloseHandle(d1), "closing thread desktop handle succeeded\n" );
246     d2 = GetThreadDesktop(GetCurrentThreadId());
247     ok( d1 == d2, "got different handles after close\n" );
248 
249     trace( "thread 1 desktop: %p\n", d1 );
250     print_object( d1 );
251     hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id );
252     Sleep(1000);
253     trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
254     WaitForSingleObject( hthread, INFINITE );
255     CloseHandle( hthread );
256 }
257 
258 /* Enumeration tests */
259 
260 static BOOL CALLBACK window_station_callbackA(LPSTR winsta, LPARAM lp)
261 {
262     trace("window_station_callbackA called with argument %s\n", winsta);
263     return lp;
264 }
265 
266 static BOOL CALLBACK open_window_station_callbackA(LPSTR winsta, LPARAM lp)
267 {
268     HWINSTA hwinsta;
269 
270     trace("open_window_station_callbackA called with argument %s\n", winsta);
271     hwinsta = OpenWindowStationA(winsta, FALSE, WINSTA_ENUMERATE);
272     ok(hwinsta != NULL, "Could not open desktop %s!\n", winsta);
273     if (hwinsta)
274         CloseWindowStation(hwinsta);
275     return lp;
276 }
277 
278 static void test_enumstations(void)
279 {
280     BOOL ret;
281 
282     if (0) /* Crashes instead */
283     {
284         SetLastError(0xbabefeed);
285         ret = EnumWindowStationsA(NULL, 0);
286         ok(!ret, "EnumWindowStationsA returned successfully!\n");
287         ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
288     }
289 
290     SetLastError(0xdeadbeef);
291     ret = EnumWindowStationsA(open_window_station_callbackA, 0x12345);
292     ok(ret == 0x12345, "EnumWindowStationsA returned %x\n", ret);
293     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
294 
295     SetLastError(0xdeadbeef);
296     ret = EnumWindowStationsA(window_station_callbackA, 0);
297     ok(!ret, "EnumWindowStationsA returned %x\n", ret);
298     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
299 }
300 
301 static BOOL CALLBACK desktop_callbackA(LPSTR desktop, LPARAM lp)
302 {
303     trace("desktop_callbackA called with argument %s\n", desktop);
304     return lp;
305 }
306 
307 static BOOL CALLBACK open_desktop_callbackA(LPSTR desktop, LPARAM lp)
308 {
309     HDESK hdesk;
310     static int once;
311 
312     trace("open_desktop_callbackA called with argument %s\n", desktop);
313     /* Only try to open one desktop */
314     if (once++)
315         return lp;
316 
317     hdesk = OpenDesktopA(desktop, 0, FALSE, DESKTOP_ENUMERATE);
318     ok(hdesk != NULL, "Could not open desktop %s!\n", desktop);
319     if (hdesk)
320         CloseDesktop(hdesk);
321     return lp;
322 }
323 
324 static void test_enumdesktops(void)
325 {
326     BOOL ret;
327 
328     if (0)  /* Crashes instead */
329     {
330         SetLastError(0xbabefeed);
331         ret = EnumDesktopsA(GetProcessWindowStation(), NULL, 0);
332         ok(!ret, "EnumDesktopsA returned successfully!\n");
333         ok(GetLastError() == ERROR_INVALID_PARAMETER, "LastError is set to %08x\n", GetLastError());
334     }
335 
336     SetLastError(0xdeadbeef);
337     ret = EnumDesktopsA(NULL, desktop_callbackA, 0x12345);
338     ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
339     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
340 
341     SetLastError(0xdeadbeef);
342     ret = EnumDesktopsA(GetProcessWindowStation(), open_desktop_callbackA, 0x12345);
343     ok(ret == 0x12345, "EnumDesktopsA returned %x\n", ret);
344     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
345 
346     SetLastError(0xdeadbeef);
347     ret = EnumDesktopsA(INVALID_HANDLE_VALUE, desktop_callbackA, 0x12345);
348     ok(!ret, "EnumDesktopsA returned %x\n", ret);
349     ok(GetLastError() == ERROR_INVALID_HANDLE, "LastError is set to %08x\n", GetLastError());
350 
351     SetLastError(0xdeadbeef);
352     ret = EnumDesktopsA(GetProcessWindowStation(), desktop_callbackA, 0);
353     ok(!ret, "EnumDesktopsA returned %x\n", ret);
354     ok(GetLastError() == 0xdeadbeef, "LastError is set to %08x\n", GetLastError());
355 }
356 
357 START_TEST(winstation)
358 {
359     /* Check whether this platform supports WindowStation calls */
360 
361     SetLastError( 0xdeadbeef );
362     GetProcessWindowStation();
363     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
364     {
365         skip("WindowStation calls not supported on this platform\n");
366         return;
367     }
368 
369     test_enumstations();
370     test_enumdesktops();
371     test_handles();
372 }
373 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.