/* winsaver.c RHS 1/25/91
 */

#include<windows.h>
#include<stdio.h>
#include<mem.h>
#include<string.h>
#include<stdlib.h>

#define MAXWINDOWSPARM  256
#define MAXFILENAME     80
#define MAXWINS         256
#define ICONIC          SW_SHOWMINNOACTIVE

#define SC_USER         (0xF000-1)
#define SC_ABOUT        SC_USER
#define SC_AUTOSAVE     SC_USER-1
#define SC_AUTOLOAD     SC_USER-2

#define MYTIMER         1
#define MYTIMER2        2

typedef struct _windows
    {
    RECT rect;
    int winState;
    HWND hWnd;
    char filename[MAXFILENAME];
    } Wins;
Wins windows[MAXWINS];

long FAR PASCAL WndProc(HWND, WORD, WORD, LONG);

void SaveSession(void);
void RestoreSession(void);
void GetWindowList(void);
void PaintWindowList(void);
int  ReadProfile(void);
void LoadPrograms(int maxwins);
void RestoreSession(void);
void Execute(char *command, int ncmdshow);
HWND GetWindowHandle(char *name);
BOOL HandleUsed(HWND hWnd);
void ActivateProgMan(void);
void UpdateSystemMenu(void);
void Autoload(void);

int getint(char **p);
BOOL bufmatch(char *str, char *winbuf, char *fullname);

static char szCopyRight[] = " WinSaver, Copyright (C) Richard Hale Shaw, 1991 ";
static char szWinSaver[] = "WinSaver";
static char szAutoSave[] = "Autosave";
static char szAutoLoad[] = "Autoload";

char szAppName[MAXFILENAME];

BOOL AutoSave = FALSE;
BOOL AutoLoad = FALSE;

#define DEFAULTTIMER    1000
WORD TimerVal = DEFAULTTIMER;

HCURSOR hNormalCursor, hHourGlassCursor;
HWND WinSaver;
HANDLE hPrev;
LPSTR CmdLine;

int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
    {
    MSG msg;
    WNDCLASS wndclass;

    hPrev = hPrevInstance;

    if(!hPrevInstance)	
        {
        wndclass.style = NULL;
        wndclass.lpfnWndProc = WndProc;
        wndclass.cbClsExtra = 0;       
        wndclass.cbWndExtra = 0;       
        wndclass.hInstance = hInstance;
        wndclass.hIcon = LoadIcon(hInstance, "WINSAVER");
        wndclass.hCursor = NULL;
        wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); 
        wndclass.lpszMenuName =  NULL;
        wndclass.lpszClassName = szWinSaver;

        RegisterClass(&wndclass);
        }

    hNormalCursor = LoadCursor(NULL, IDC_ARROW);
    hHourGlassCursor = LoadCursor(NULL, IDC_WAIT);

    WinSaver = CreateWindow(szWinSaver,
        "Session Saver",
        WS_OVERLAPPEDWINDOW,            
//        0,
        CW_USEDEFAULT,                  
        CW_USEDEFAULT,                  
        CW_USEDEFAULT,                  
        CW_USEDEFAULT,                  
        NULL,                           
        NULL,                           
        hInstance,                      
        NULL);

    UpdateSystemMenu();

    ShowWindow(WinSaver, SW_SHOWMINIMIZED);
    UpdateWindow(WinSaver);        

    while(GetMessage(&msg, NULL, 0, 0))
    	{
	    TranslateMessage(&msg);
    	DispatchMessage(&msg); 
        }
    return (msg.wParam);  
    }



long FAR PASCAL WndProc(HWND hWnd, WORD message,
    WORD wParam, LONG lParam)
    {
    static BOOL done1 = FALSE;
    static BOOL done2 = FALSE;

    switch(message)
        {
        case WM_CREATE:
            {
            WORD w = LOBYTE(GetVersion());

            if(w < 3)                           // if Win 1.0 or Win 2.0
                {
                MessageBox(hWnd,
                    "Sorry, WinSaver must run on Windows 3.x or higher!",
                    szWinSaver,
                    MB_ICONEXCLAMATION);
                SendMessage(hWnd,WM_DESTROY,0,0L);
                }
            else if(hPrev)                      // if a previous instance
                {
                MessageBox(hWnd,
                    "WinSaver already running!",
                    szWinSaver,
                    MB_ICONEXCLAMATION);
                SendMessage(hWnd,WM_DESTROY,0,0L);
                }
            else
                SetTimer(hWnd,MYTIMER,50,NULL);
            break;
            }

        case WM_INITMENU:           // modify the system menu
            CheckMenuItem(GetSystemMenu(WinSaver,0),
                SC_AUTOSAVE,
                (MF_BYCOMMAND | (AutoSave ? MF_CHECKED : MF_UNCHECKED)));
            CheckMenuItem(GetSystemMenu(WinSaver,0),
                SC_AUTOLOAD,
                (MF_BYCOMMAND | (AutoLoad ? MF_CHECKED : MF_UNCHECKED)));
            break;

        case WM_TIMER:
            {
            if(!done1 && wParam == MYTIMER)
                {
                SetCursor(hHourGlassCursor);
                KillTimer(hWnd,MYTIMER);
                RestoreSession();
                GetModuleFileName(GetClassWord(hWnd,GCW_HMODULE),
                        szAppName, MAXFILENAME-1);
                SetTimer(hWnd,MYTIMER2,TimerVal,NULL);
                done1 = TRUE;
                }
            if(!done2 && wParam == MYTIMER2)
                {
                char buf[20];

                KillTimer(hWnd,MYTIMER2);
                SetCursor(hNormalCursor);
                done2 = TRUE;
                }
            }
            break;

        case WM_QUERYENDSESSION:
            if(AutoSave || (MessageBox(hWnd,"Save this session?",szWinSaver,
                MB_ICONQUESTION | MB_YESNO) == IDYES))
                {
                SetCursor(hHourGlassCursor);
                GetWindowList();
                SaveSession();
                }
            return -1L;

        case WM_QUERYOPEN:                      // prevent icon from opening
            return 0L;                          // into a window

        case WM_CLOSE:
            DestroyWindow(hWnd);
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        case WM_SYSCOMMAND:
            switch(wParam)
                {
                case SC_ABOUT:
                    MessageBox(hWnd,szCopyRight,szWinSaver,
                        MB_ICONINFORMATION);
                    break;

                case SC_AUTOLOAD:
                    Autoload();
                    break;

                case SC_AUTOSAVE:
                    AutoSave = !AutoSave;
                    CheckMenuItem(GetSystemMenu(WinSaver,0),
                        SC_AUTOSAVE,(MF_BYCOMMAND |
                            (AutoSave ? MF_CHECKED : MF_UNCHECKED)));
                    break;
                default:
                    goto defwindowproc;
                }
            break;

         default:
defwindowproc:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    return 0L;
    }


void UpdateSystemMenu(void)
    {
    HMENU hSysMenu = GetSystemMenu(WinSaver,0);

    RemoveMenu(hSysMenu, SC_RESTORE, MF_BYCOMMAND);
    RemoveMenu(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
    RemoveMenu(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
    RemoveMenu(hSysMenu, SC_SIZE, MF_BYCOMMAND);

    AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hSysMenu, MF_STRING, SC_ABOUT, "About...");
    AppendMenu(hSysMenu, MF_STRING, SC_AUTOSAVE, "Autosave");
    AppendMenu(hSysMenu, MF_STRING, SC_AUTOLOAD, "Autoload");
    }

char outbuf[MAXWINDOWSPARM];

void Autoload(void)
    {
    char *p;

    GetProfileString("windows","load",NULL,outbuf,sizeof(outbuf));
    strupr(outbuf);

    AutoLoad = !AutoLoad;

        // if Auto Load is selected and app name is not in LOAD= list
    if(AutoLoad && !strstr(outbuf,szAppName))
        {
        strcat(outbuf," ");                     // add blank and name to 
        strcat(outbuf,szAppName);               // LOAD= list
        WriteProfileString("windows","load",outbuf);
        }
        // if Auto Load is not selected and app name is in LOAD= list
    if(!AutoLoad && (p = strstr(outbuf,szAppName)))
        {
        *p = '\0';                              // NULL at start of appname
        p += strlen(szAppName);                 // move past appname
        strcat(outbuf,p);                       // copy everybody up
        WriteProfileString("windows","load",outbuf);
        }
    }

void SaveSession(void)
    {
    int i, j;
    char buf[10];
    char *p;
    RECT rect;
    int winState;

    WriteProfileString(szWinSaver,NULL,NULL);
    WriteProfileString(szWinSaver,szAutoSave,(AutoSave ? "1" : "0"));
    WriteProfileString(szWinSaver,szAutoLoad,(AutoLoad ? "1" : "0"));

    for(i = 0; i < MAXWINS; i++)
        if(!windows[i+1].hWnd)
            break;

    for(j = 0; i >= 0; i--)
        {
        p = windows[i].filename;

            // eliminate all entries that are NULL, blank,
            // or contain "\\USER.EXE"
        if(!(*p) ||
            (*p == ' ') ||
            strstr(p,"\\USER.EXE") ||
            strstr(p, "\\PROGMAN.EXE"))
            continue;

        sprintf(buf,"Win%d",j++);

        GetWindowRect(windows[i].hWnd,&rect);

        winState = SW_SHOWNORMAL;
        if(IsIconic(windows[i].hWnd))
            winState = ICONIC;
//            winState = SW_SHOWMINIMIZED;
        if(IsZoomed(windows[i].hWnd))
            winState = SW_SHOWMAXIMIZED;

        sprintf(outbuf,"%s %d %d %d %d %d",
            windows[i].filename,
            winState,
            rect.left, rect.top, rect.right, rect.bottom);

        WriteProfileString(szWinSaver,buf,outbuf);
        }
    }

void GetWindowList(void)
    {
    int i;

    memset(windows,0,sizeof(windows));

    windows[0].hWnd = GetWindow(GetDesktopWindow(),GW_CHILD);
    for(i = 0; i < MAXWINS; i++)
        {
        GetModuleFileName(GetClassWord(windows[i].hWnd,GCW_HMODULE),
            windows[i].filename, MAXFILENAME-1);
        if(!(windows[i+1].hWnd = GetNextWindow(windows[i].hWnd,GW_HWNDNEXT)))
            break;
        }
    }

void PaintWindowList(void)
    {
    int i;
    PAINTSTRUCT ps;
    RECT rect;

    BeginPaint(WinSaver, &ps);
    GetClientRect(WinSaver,&rect);

    for(i = 0; windows[i].hWnd && i < MAXWINS; i++)
        {
        sprintf(outbuf,"HWND: %u %s state=%d @ %d %d %d %d",
            windows[i].hWnd,
            windows[i].filename,
            windows[i].winState,
            windows[i].rect.left,
            windows[i].rect.top,
            windows[i].rect.right,
            windows[i].rect.bottom);

        TextOut(ps.hdc,0,i*15,outbuf,strlen(outbuf));
        }        

    EndPaint(WinSaver, &ps);
    }

int getint(char **p)
    {
    char *q = *p, *r;

    r = strchr(q,' ');
    *r++ = '\0';
    *p = r;
    return atoi(q);
    }

void RestoreSession(void)
    {
    int maxwins;

    maxwins = ReadProfile();
    LoadPrograms(maxwins);
//    ActivateProgMan();
    }

void ActivateProgMan(void)
    {
    HWND hWnd;
    char progmanfile[MAXFILENAME];

    GetWindowsDirectory(progmanfile,MAXFILENAME-1);
    strcat(progmanfile,"\\PROGMAN.EXE");
    hWnd = GetWindowHandle(progmanfile);
    SetActiveWindow(hWnd);
    }

BOOL HandleUsed(HWND hWnd)
    {
    int i;

    for(i = 0; i < MAXWINS; i++)
        if(hWnd == windows[i].hWnd)
            return TRUE;
    return FALSE;
    }

HWND GetWindowHandle(char *name)
    {
    char filename[MAXFILENAME];
    HWND hWnd;
    int i;

    hWnd = GetWindow(GetDesktopWindow(),GW_CHILD);

    for(i = 0; i < MAXWINS; i++)
        {
        if(!HandleUsed(hWnd))                   // if handle is not in list
            {                                   // get it's filename
            GetModuleFileName(GetClassWord(hWnd,GCW_HMODULE),filename,
                MAXFILENAME-1);
            if(!strcmp(name,filename))   // if filenames match
                break;
            }
        hWnd = GetNextWindow(hWnd,GW_HWNDNEXT);
        }
    return hWnd;
    }

#define WM_BOGUS1   WM_USER+0x00A0
#define WM_BOGUS2   WM_USER+0x00AA

void LoadPrograms(int maxwins)
    {
    int i;

    for(i = 0; i < maxwins && windows[i].hWnd == 0xffff; i++)
        {
        if(strstr(windows[i].filename,"\\WINSAVER.EXE"))
            windows[i].hWnd = WinSaver;
        else
            {
            Execute(windows[i].filename,SW_HIDE);
            windows[i].hWnd = GetWindowHandle(windows[i].filename);
//            SendMessage(windows[i].hWnd,WM_BOGUS1,0xffff,0xffffffff);
            }
        }
    for(i = 0; i < maxwins && windows[i].hWnd != 0xffff; i++)
        {
        if(windows[i].winState != ICONIC)
            MoveWindow(windows[i].hWnd,
                windows[i].rect.left,
                windows[i].rect.top,
                windows[i].rect.right-windows[i].rect.left,
                windows[i].rect.bottom-windows[i].rect.top,
                TRUE);
        ShowWindow(windows[i].hWnd,windows[i].winState);
//        PostMessage(windows[i].hWnd,WM_BOGUS2,0xffff,0xffffffff);
        }
    TimerVal *= i;                              // multiply by # of windows
    }


BOOL bufmatch(char *str, char *winbuf, char *fullname)
    {
    char *p, *q;
    char fname[MAXFILENAME], fname2[MAXFILENAME];

    p = winbuf;                                 // set to start of buffer
    while((p = strstr(p,str)))                  // look for str in p
        {                                       // if found,
        p--;                                    // look at previous char
                                                // if p not one of these
        if((*p != '=') && (*p != ',') && (*p != ' '))
            {
            p += 2;                             // move past match point
            continue;                           // try again
            }
                                                // see if directories match
        strcpy(fname,fullname);
        q = strrchr(fname,'\\');
        *q = '\0';
        GetWindowsDirectory(fname2,MAXFILENAME-1);
        if(!strcmp(fname,fname2))               // if directories match,
            return TRUE;                        // return TRUE
        p += 2;                                 // move past match point
        }
    return FALSE;
    }

char loadrun[MAXWINDOWSPARM*2],
windir[MAXWINDOWSPARM];
char inbuf[MAXWINDOWSPARM];

int ReadProfile(void)
    {    
    char buf[13], *p;
    int i,j;

    GetProfileString("windows","load",NULL,loadrun,sizeof(loadrun));
    p = &loadrun[strlen(loadrun)];
    *p++ = ' ';
    *p = '\0';
    GetProfileString("windows","run",NULL,p,sizeof(loadrun)-strlen(loadrun));
    strupr(loadrun);

    GetWindowsDirectory(windir,MAXWINDOWSPARM-1);

    GetProfileString(szWinSaver,szAutoSave,NULL,buf,sizeof(buf));
    if(!strcmp(buf,"1"))
        AutoSave = TRUE;

    GetProfileString(szWinSaver,szAutoLoad,NULL,buf,sizeof(buf));
    if(!strcmp(buf,"1"))
        AutoLoad = TRUE;


    for(i = j = 0; i < MAXWINS; )
        {
        sprintf(buf,"Win%d",j++);
        if(!GetProfileString(szWinSaver,buf,NULL,inbuf,MAXWINDOWSPARM))
            break;
        p = strchr(inbuf,' ');
        *p++ = '\0';

        windows[i].winState = getint(&p);
        windows[i].rect.left = getint(&p);
        windows[i].rect.top = getint(&p);
        windows[i].rect.right = getint(&p);
        windows[i].rect.bottom = getint(&p);

        strcpy(windows[i].filename,inbuf);
        if(strstr(loadrun,windows[i].filename)) // if fullname match
            continue;

        p = strrchr(windows[i].filename,'\\');
        strcpy(buf,++p);                        // p to beginning of filename

                                                // if filename+ext match
        if(bufmatch(buf,loadrun,windows[i].filename))
            continue;

        p = strchr(buf,'.');
        *p = '\0';
                                                // if filename match
        if(bufmatch(buf,loadrun,windows[i].filename))
            continue;

        windows[i++].hWnd = 0xffff;
        }
    return i;
    }


char *messages[5] =
    {    
    "Out of memory",
    "(Unknown Error)",
    "File not found",
    "Path not found",
    "Failed attempt to dynamically link"
    };

void Execute(char *command, int ncmdshow)
    {
    char buf[256],*p;
    int retval;

    strcpy(buf,command);                        // copy command to buffer
    p = strrchr(buf,'\\');                      // find last '\'
    if((p-buf) == 2)                            // if "C:\"
        p++;                                    // point past '\'
    *p = '\0';                                  // remove the character
    setdisk(*buf-'A');                          // change to that disk
    chdir(buf);                                 // change to that directory

    if((retval = WinExec(command,ncmdshow)) < 32)
        {
        strcpy(buf,"Unable to execute '");
        strcat(buf,command);
        strcat(buf,"', ");
        strcat(buf,messages[retval]);
        MessageBox(WinSaver,buf,"WinSaver Error!",MB_ICONEXCLAMATION);
        }
    strcpy(buf,szAppName);                      // copy command to buffer
    p = strrchr(buf,'\\');                      // find last '\'
    if((p-buf) == 2)                            // if "C:\"
        p++;                                    // point past '\'
    *p = '\0';                                  // remove the character
    setdisk(*buf-'A');                          // change to that disk
    chdir(buf);                                 // change to that directory
    }




