roberth@microsoft.UUCP (Robert Hess) (09/20/89)
Ok, there has been enough posting back and forth about how to spawn a Windows application, and enough mis-information being stated that I decided I'd better 'bring out the horse' so you could get it straight from the source. Following this message will be the code that the Windows Development Support Team provides its customers on how to spawn applications in Windows. If you have an OnLine account, an archive of this information (includeing .OBJs and the .EXE) is available under the title of WINSPAWN.ARC in the software library. !!DO NOT EVER USE ANY OF THE 'spawn' FUNCTIONS FROM THE C RUNTIME LIBRARY!! They do not properly spawn Windows applications, and your applications will eventually fail under the right conditions. Just because they 'happen' to work on your machine, doesn't mean they will always work. Under interesting memory conditions, things can get strange. Even using the following code, there is at least one situation that I know of that will cause problems. That is: Execute your program, have it spawn Excel, then quit your program, then quit Excel. There are conditions that will cause this to crash Windows. The reason being, that Excel (and some other non-MS applications) took for granted that they were being spawned by the MS-DOS Executive, which was 'guaranteed' to be around longer then they were, and they were making use of the spawners stack to maintain some special data. If that stack disappears, then problems arise. Even though this application demonstrates it, I would not recommend allowing users of your program to spawn *any* application. (If you are shipping your program as a 'Stand-Alone' application, this would invalidate your licenceing agreement with Microsoft). Only spawn your own applications, or specific others (such as the ones that ship with Windows). - Robert __________________________________________________________________________ ##### ####### | Robert B. Hess, Microsoft Corp., Redmond, WA ###### ####### |----------------------------------------------------- ####### ####### | roberth@microsof.uu.net #### ##### #### | {decvax, uunet, uw-beaver}!microsof!roberth #### ### #### |_____________________________________________________ "...my opinions are strictly my own, and not those of my employer..." [Disclaimer: The following code is provided as-is. It does not represent any guarantee on the part of Microsoft or any other person or company to be error-free. Microsoft takes no responsibility regarding its usage in an application, and it is presented mearly as an example. This code may not be re-distibuted in any manner that provides profit or advertisement. It may not be shipped with any application, either as source code, or executable] //----------------------------------------------------------------------- //----------------------------------------------------------------------- // WinSpawn.MAK //----------------------------------------------------------------------- //----------------------------------------------------------------------- WinSpawn.obj : WinSpawn.c cl -c -D LINT_ARGS -Gsw -Os -W2 -Zp WinSpawn.c WinSpawn.res : WinSpawn.rc WinSpawn.h rc -r WinSpawn.rc wspawn.obj : wspawn.asm masm wspawn; WinSpawn.exe : WinSpawn.obj WinSpawn.def WinSpawn.res wspawn.obj link4 WinSpawn wspawn, /align:16, /map, slibw, WinSpawn mapsym WinSpawn rc WinSpawn.res WinSpawn.exe : WinSpawn.res rc WinSpawn.res //----------------------------------------------------------------------- //----------------------------------------------------------------------- // WinSpawn.DEF //----------------------------------------------------------------------- //----------------------------------------------------------------------- NAME WINSPAWN DESCRIPTION 'Andrew Krois June 1988' STUB 'WINSTUB.EXE' CODE MOVEABLE DATA MOVEABLE MULTIPLE SEGMENTS ASMCODE CLASS'ASMCODE' FIXED LOADONCALL READWRITE HEAPSIZE 1024 STACKSIZE 4096 EXPORTS WndProc SpawnDlgBoxProc @2 NewSpawnDlgBoxProc @3 //----------------------------------------------------------------------- //----------------------------------------------------------------------- // WinSpawn.RC //----------------------------------------------------------------------- //----------------------------------------------------------------------- #include <windows.h> #include "WinSpawn.h" WinSpawn MENU BEGIN POPUP "&Choose Application" BEGIN MENUITEM "&MS-DOS dir | sort", IDM_DOSDIRSORT MENUITEM "MS-DOS &type winspawn.c", IDM_DOSTYPE MENUITEM "&Windows Clock", IDM_CLOCK MENUITEM "&Notepad winspawn.c", IDM_NOTEPAD MENUITEM "&Spawn All", IDM_SPAWNALL END MENUITEM "\a&Help" IDM_HELP HELP END SpawnDlgBox DIALOG LOADONCALL MOVEABLE DISCARDABLE 13, 14, 104, 72 STYLE WS_DLGFRAME | WS_POPUP BEGIN LTEXT "App Name Extension", -1, 2, 4,100, 10 EDITTEXT IDD_DLGSPAWNAPPNAME,2, 14, 50, 12, ES_AUTOHSCROLL EDITTEXT IDD_DLGEXTENSION, 55, 14, 25, 12, ES_AUTOHSCROLL LTEXT "Command Line", -1, 2, 30, 75, 10 EDITTEXT IDD_DLGCOMMANDLINE, 2, 42,100, 12, ES_AUTOHSCROLL DEFPUSHBUTTON "&OK", IDOK, 27, 56, 50, 14, WS_GROUP END //----------------------------------------------------------------------- //----------------------------------------------------------------------- // WinSpawn.H //----------------------------------------------------------------------- //----------------------------------------------------------------------- #define IDM_ABOUT 45 #define IDM_CHOOSERANDOM 46 #define IDM_HELP 47 #define IDM_CHOOSE 48 #define IDM_CLOCK 49 #define IDM_DOSDIRSORT 50 #define IDM_SPAWNIT 51 #define IDM_NOTEPAD 52 #define IDM_DOSTYPE 53 #define IDM_SPAWNALL 54 #define IDD_DLGSPAWNAPPNAME 55 #define IDD_DLGCOMMANDLINE 56 #define IDD_DLGEXTENSION 57 long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ; BOOL FAR PASCAL SpawnDlgBoxProc (HWND, unsigned, WORD, LONG) ; BOOL FAR PASCAL NewSpawnDlgBoxProc (HWND, unsigned, WORD, LONG); HWND FindNextWindow (HWND) ; BOOL FindPeriod (char *); extern int far pascal Int21Function4B (BYTE, LPSTR, LPSTR); //----------------------------------------------------------------------- //----------------------------------------------------------------------- // WSpawn.ASM //----------------------------------------------------------------------- //----------------------------------------------------------------------- include cmacros.inc externFP <GlobalCompact> createSeg ASMCODE,ASMCODE,PARA,PUBLIC,ASMCODE ;; ;; Int21Function4B cannot be a discardable segment. If the segment ;; were discardable, the int21 interrupt might cause it to be discarded ;; and then reread from disk. This would set stackSS and stackSP to 0. ;; Upon return from int21, SS would be set to 0 and SP would be set to ;; 0. ;; ;; Warning: the code is not reentrant. Multiple sp's cannot be saved. ;; Warning: In applications SS == DS by default. If the DS should move ;; the stored SS would be invalidated. For maximum reliability it is ;; recommended that LockData(), UnlockData() call bracket the call to ;; int21function4B. ;; Warning: Should the code segment move using the debugging KERNEL, ;; the segment will be checksummed and the write of SS:SP into the ;; code segment detected as a fatal error. To avoid this extraneous ;; ( in this one instance ) error condition, ;; use the non-debugging kernel or place the code in a fixed segment. ;; assumes CS,ASMCODE assumes DS,DATA sBegin DATA sEnd DATA sBegin ASMCODE stackSS dw 0 stackSP dw 0 cProc Int21Function4B,<PUBLIC,FAR>,<ax,bx,cx,dx,si,di,es,ds> parmB mode parmD path parmD execblock cBegin mov ax,-1 cCall GlobalCompact,<ax,ax> mov cs:[stackSS],ss ;; EXEC destroys all register. Save SS:SP. mov cs:[stackSP],sp mov al,mode lds dx,path les bx,execblock mov ah,4bh int 21h mov ss,cs:[stackSS] mov sp,cs:[stackSP] ; AX is return value cEnd sEnd ASMCODE END //----------------------------------------------------------------------- //----------------------------------------------------------------------- // WinSpawn.C //----------------------------------------------------------------------- //----------------------------------------------------------------------- /* Date: June 15, 1988 Function(s) demonstrated in this program: Int21Function4B Windows version: 2.03 Windows SDK version: 2.00 Compiler version: C 5.10 Description: This is a Function created using Masm, and it corresponds with the MS-DOS interrupt 21 function 4BH. Additional Comments: This function can be used to spawn windows applications, as well as old MS-DOS applications from within a windows application. A method of sending command line arguments to the spawnded windows application is also discussed. */ #define NOMINMAX #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include "WinSpawn.h" HWND hWndMain; HANDLE hInstMain; char szOutputBuffer1 [70]; char szOutputBuffer2 [500]; char szSpawnAppName [40]; char szCommandLine [40]; HWND hSpawnAppEdit, hExtensionEdit, hCommandLineEdit, hOK2; FARPROC lpProcSpawnDlgBox; FARPROC lpProcNewSpawnDlgBox; FARPROC lpProcOldSpawnApp; FARPROC lpProcOldExtension; FARPROC lpProcOldCommandLine; char szDlgSpawnAppName [40]; char szDlgCommandLine [40]; char szDlgExtension [4] = "EXE"; typedef struct { WORD environment; LPSTR commandline; LPSTR FCB1; LPSTR FCB2; } EXECBLOCK; EXECBLOCK exec; WORD wFCB1Contents[2]; /****************************************************************************/ /************************ Message Structure *************************/ /****************************************************************************/ struct { char *szMessage; } Messages [] = { "About", " This is a sample application to demonstrate the\n\ use of Interrupt 21 function 4B in spawning Windows\n\ applications, and MS-DOS applications from a Windows\n\ Windows application. Program by Andrew Krois", "Help Message", " This program demonstrates the use of the\n\ Int21Function4B function. Use the menu to select\n\ either a MS-DOS application or a Windows application\n\ to be spawned. The program will also send command\n\ line arguments to the spawned application.", }; /****************************************************************************/ void ProcessMessage (HWND, int); void ProcessMessage (hWnd, MessageNumber) HWND hWnd; int MessageNumber; { sprintf (szOutputBuffer1, "%s", Messages [MessageNumber]); sprintf (szOutputBuffer2, "%s", Messages [MessageNumber + 1]); MessageBox (hWnd, szOutputBuffer2, szOutputBuffer1, MB_OK); } /****************************************************************************/ int PASCAL WinMain (hInstance, hPrevInstance, lpszCmdLine, nCmdShow) HANDLE hInstance, hPrevInstance ; LPSTR lpszCmdLine ; int nCmdShow ; { static char szAppName [] = "WinSpawn" ; static char szChildClass [] = "WinSpawnChild" ; HWND hWnd ; WNDCLASS wndclass ; MSG msg; if (!hPrevInstance) { wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = szAppName ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) return FALSE ; } hWnd = CreateWindow (szAppName, /* window class name */ "Windows Spawn", /* window caption */ WS_OVERLAPPEDWINDOW, /* window style */ CW_USEDEFAULT, /* initial x position */ 0, /* initial y position */ CW_USEDEFAULT, /* initial x size */ 0, /* initial y size */ NULL, /* parent window handle */ NULL, /* window menu handle */ hInstance, /* program instance handle */ NULL) ; /* create parameters */ ShowWindow (hWnd, nCmdShow) ; UpdateWindow (hWnd) ; hWndMain = hWnd; hInstMain = hInstance; lpProcSpawnDlgBox = MakeProcInstance (SpawnDlgBoxProc, hInstance); lpProcNewSpawnDlgBox = MakeProcInstance (NewSpawnDlgBoxProc,hInstance); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (msg.wParam) ; } /****************************************************************************/ long FAR PASCAL WndProc (hWnd, iMessage, wParam, lParam) HWND hWnd ; unsigned iMessage ; WORD wParam ; LONG lParam ; { HMENU hMenu; PAINTSTRUCT ps; switch(iMessage) { case WM_CREATE: hMenu = GetSystemMenu (hWnd, FALSE); ChangeMenu (hMenu, NULL, "&About", IDM_ABOUT, MF_APPEND | MF_STRING); break; case WM_SYSCOMMAND: switch (wParam) { case IDM_ABOUT: ProcessMessage (hWnd, 0); break; default: return DefWindowProc (hWnd, iMessage, wParam, lParam) ; } break; case WM_COMMAND: switch (wParam) { case IDM_SPAWNIT: hMenu = GetSystemMenu (hWnd, NULL); ChangeMenu (hMenu, SC_CLOSE, "&Close", SC_CLOSE, MF_CHANGE | MF_DISABLED | MF_GRAYED); GlobalCompact(-1L); LockData(0); exec.environment = 0; exec.commandline = szCommandLine; wFCB1Contents[0] = 2; wFCB1Contents[1] = SW_SHOWNORMAL; exec.FCB1 = (LPSTR)wFCB1Contents; exec.FCB2 = (LPSTR)NULL; Int21Function4B(0, (LPSTR)szSpawnAppName, (LPSTR)&exec); UnlockData(0); break; case IDM_CLOCK: sprintf (szSpawnAppName,"CLOCK.EXE"); sprintf (szCommandLine, ""); SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L); break; case IDM_DOSDIRSORT: sprintf (szSpawnAppName,"COMMAND.COM"); sprintf (szCommandLine, "%c /c dir | sort", 14); SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L); break; case IDM_DOSTYPE: sprintf (szSpawnAppName,"COMMAND.COM"); sprintf (szCommandLine, "%c /c type winspawn.c", 0x13); SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L); break; case IDM_NOTEPAD: sprintf (szSpawnAppName,"NOTEPAD.EXE"); sprintf (szCommandLine, " WINSPAWN.C"); SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L); break; case IDM_SPAWNALL: DialogBox (hInstMain, (LPSTR)"SpawnDlgBox", hWnd, lpProcSpawnDlgBox); sprintf (szSpawnAppName, "%s.%s", szDlgSpawnAppName, szDlgExtension); sprintf (szCommandLine, "%c %s", strlen (szDlgCommandLine) + 1, szDlgCommandLine); SendMessage (hWnd, WM_COMMAND, IDM_SPAWNIT, 0L); break; case IDM_HELP: ProcessMessage (hWnd, 2); break; } break; case WM_PAINT: BeginPaint(hWnd, (LPPAINTSTRUCT)&ps); EndPaint(hWnd, (LPPAINTSTRUCT)&ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: { return DefWindowProc (hWnd, iMessage, wParam, lParam) ; } } return (0L); } /****************************************************************************/ BOOL FAR PASCAL SpawnDlgBoxProc (hDlg, iMessage, wParam, lParam) HWND hDlg; unsigned iMessage; WORD wParam; LONG lParam; { int Index; char szChange [10]; long lReturn; switch (iMessage) { case WM_INITDIALOG: SendDlgItemMessage (hDlg, IDD_DLGSPAWNAPPNAME, EM_LIMITTEXT, (WORD)40, 0L); SendDlgItemMessage (hDlg, IDD_DLGCOMMANDLINE, EM_LIMITTEXT, (WORD)40, 0L); SendDlgItemMessage (hDlg, IDD_DLGEXTENSION, EM_LIMITTEXT, (WORD)10, 0L); SetDlgItemText (hDlg, IDD_DLGEXTENSION, szDlgExtension); hSpawnAppEdit = GetDlgItem (hDlg, IDD_DLGSPAWNAPPNAME); lpProcOldSpawnApp = (FARPROC) GetWindowLong (hSpawnAppEdit, GWL_WNDPROC); SetWindowLong (hSpawnAppEdit, GWL_WNDPROC, (LONG)lpProcNewSpawnDlgBox); SendMessage (hSpawnAppEdit, EM_SETSEL, 0, MAKELONG (0,32767)); hExtensionEdit = GetDlgItem (hDlg, IDD_DLGEXTENSION); lpProcOldExtension = (FARPROC)GetWindowLong (hExtensionEdit, GWL_WNDPROC); SetWindowLong (hExtensionEdit, GWL_WNDPROC, (LONG)lpProcNewSpawnDlgBox); SendMessage (hExtensionEdit, EM_SETSEL, 0, MAKELONG (0,32767)); hCommandLineEdit = GetDlgItem (hDlg, IDD_DLGCOMMANDLINE); lpProcOldCommandLine = (FARPROC) GetWindowLong (hCommandLineEdit, GWL_WNDPROC); SetWindowLong (hCommandLineEdit, GWL_WNDPROC, (LONG)lpProcNewSpawnDlgBox); SendMessage (hCommandLineEdit, EM_SETSEL, 0, MAKELONG (0,32767)); hOK2 = GetDlgItem (hDlg, IDOK); return TRUE; break; case WM_COMMAND: switch (wParam) { case IDOK: GetDlgItemText (hDlg, IDD_DLGSPAWNAPPNAME,szDlgSpawnAppName,40); GetDlgItemText (hDlg, IDD_DLGCOMMANDLINE, szDlgCommandLine,40); GetDlgItemText (hDlg, IDD_DLGEXTENSION, szDlgExtension, 4) ; EndDialog (hDlg, TRUE); break; default: return FALSE; } default: return FALSE; } return TRUE; } /****************************************************************************/ BOOL FAR PASCAL NewSpawnDlgBoxProc (hWnd, iMessage, wParam, lParam) HWND hWnd; unsigned iMessage; WORD wParam; LONG lParam; { switch (iMessage) { case WM_GETDLGCODE: return (DLGC_WANTALLKEYS); case WM_CHAR: if ((wParam == VK_TAB) || (wParam == VK_RETURN)) { SendMessage (hWndMain, WM_USER, 0, 0L); SetFocus (FindNextWindow (hWnd)); return TRUE; } else { if (hWnd == hSpawnAppEdit) return ((BOOL)CallWindowProc (lpProcOldSpawnApp, hWnd, iMessage, wParam, lParam)); if (hWnd == hExtensionEdit) return ((BOOL)CallWindowProc (lpProcOldExtension, hWnd, iMessage, wParam, lParam)); if (hWnd == hCommandLineEdit) return ((BOOL)CallWindowProc (lpProcOldCommandLine, hWnd, iMessage, wParam, lParam)); } break; default: if (hWnd == hSpawnAppEdit) return ((BOOL)CallWindowProc (lpProcOldSpawnApp, hWnd, iMessage, wParam, lParam)); if (hWnd == hExtensionEdit) return ((BOOL)CallWindowProc (lpProcOldExtension, hWnd, iMessage, wParam, lParam)); if (hWnd == hCommandLineEdit) return ((BOOL)CallWindowProc (lpProcOldCommandLine, hWnd, iMessage, wParam, lParam)); } } /****************************************************************************/ HWND FindNextWindow (hWnd) HWND hWnd; { if (hWnd == hSpawnAppEdit) return hExtensionEdit; if (hWnd == hExtensionEdit) return hCommandLineEdit; if (hWnd == hCommandLineEdit) return hOK2; return NULL; } //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // ...end... //-------------------------------------------------------------------------- //--------------------------------------------------------------------------
mms00786@uxa.cso.uiuc.edu (09/23/89)
That was very much appreciated, but it brought up another question. Can I use code like winspawn, or perhaps taken from copyrighted sources like Petzold's book, and include them as part of a program I might sell? Obviously, I will have to change them a little for my needs, but beyond that, the meat of the code is essentially the same. As an example, can I use the FileDlg code in Petzold's book in my programs? Sorry if this is the wrong news group. Thanks . Milan mms00786@uxa.cso.uiuc.edu .
mcdonald@uxe.cso.uiuc.edu (09/23/89)
>/* ---------- "Spawning Windows Applications (The" ---------- */ >Ok, there has been enough posting back and forth about how to spawn a >Windows application, and enough mis-information being stated that I >decided I'd better 'bring out the horse' so you could get it straight >from the source. >Following this message will be the code that the Windows Development >Support Team provides its customers on how to spawn applications in >Windows. If you have an OnLine account, an archive of this information >(includeing .OBJs and the .EXE) is available under the title of >WINSPAWN.ARC in the software library. >!!DO NOT EVER USE ANY OF THE 'spawn' FUNCTIONS FROM THE C RUNTIME LIBRARY!! >Execute your program, have it spawn Excel, then quit your program, >then quit Excel. >There are conditions that will cause this to crash Windows. The reason >being, that Excel (and some other non-MS applications) took for granted >that they were being spawned by the MS-DOS Executive, which was >'guaranteed' to be around longer then they were, and they were making >use of the spawners stack to maintain some special data. If that stack >disappears, then problems arise. > __________________________________________________________________________ > ##### ####### | Robert B. Hess, Microsoft Corp., Redmond, WA > ###### ####### |----------------------------------------------------- > ####### ####### | roberth@microsof.uu.net > #### ##### #### | {decvax, uunet, uw-beaver}!microsof!roberth > #### ### #### |_____________________________________________________ > "...my opinions are strictly my own, and not those of my employer..." Very odd. Very odd indeed!!!!!! An admission from an employee of Microsoft Corporation that their products - Microsoft C, Microsoft Windows, and Microsoft Excel - are DEFECTIVE. FLAME ON!!! really now! Look at the Ansi standard for C. The spawn and exec functions are in the standard. They are REQUIRED either to work or to do nothing at all. When tried under Windows they most certainly do something. If I write a program under Windows, which most certainly claims to be multitasking (at least Windows 386), I would spawn new programs using "spawn". I tried it - and it most certainly worked in every case I tried. If it breaks **** IT IS NOT MY FAULT ****. Microsoft should fix their bugs!!!!!! Is there an OFFICIAL admission that Windows is brain-dead? Does this same sick admission apply to OS/2? Is it brain-dead also? Doug McDonald
bright@Data-IO.COM (Walter Bright) (09/26/89)
In article <245400027@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes:
<<!!DO NOT EVER USE ANY OF THE 'spawn' FUNCTIONS FROM THE C RUNTIME LIBRARY!!
<<There are conditions that will cause this to crash Windows.
<Very odd. Very odd indeed!!!!!!
<An admission from an employee of Microsoft Corporation that their
<products - Microsoft C, Microsoft Windows, and Microsoft Excel -
<are DEFECTIVE.
<FLAME ON!!!
<really now! Look at the Ansi standard for C. The spawn and exec
<functions are in the standard. They are REQUIRED either to work
<or to do nothing at all. When tried under Windows they most certainly
<do something. If I write a program under Windows, which most
<certainly claims to be multitasking (at least Windows 386),
<I would spawn new programs using "spawn". I tried it - and
<it most certainly worked in every case I tried. If it breaks
<**** IT IS NOT MY FAULT ****.
<Microsoft should fix their bugs!!!!!!
<Is there an OFFICIAL admission that Windows is brain-dead?
<Does this same sick admission apply to OS/2? Is it brain-dead also?
Ease up. All programs have bugs in them. The guy from Microsoft was
trying to be helpful by admitting a problem and suggesting a work-
around. Attacks like yours are what cause companies to normally clam
up and refuse to admit any problems, thus *causing* problems for
developers. It's to all our advantage to encourage vendors to disclose
bug lists and suggested workarounds.
By suggesting that anything posted by an MS employee is an OFFICIAL
pronouncement, you do a disservice to both the employee and the company.
You encourage companies to not allow their employees to post anything.
Is your mail message an official statement by your company? Or is it
personal opinion?
Windows predates ANSI C (which isn't even official yet) by YEARS. Thus,
non-conformance is not a bug.
When you write a non-trivial program with no bugs in it, be sure and
let us know.
meyer@s.cs.uiuc.edu (09/27/89)
No, Windows is not "brain-dead", that's the 80286 that is "brain-dead". Windows, in its current incarnation, is just clumsy -- prone to falling over and killing itself. Don meyer@s.cs.uiuc.edu