📄 status.c
字号:
/* Status.c -- the status module of WizUnZip
* Robert Heath. 1991.
*/
#include <sys\types.h>
#include <sys\stat.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#include <stdio.h>
#include <stdarg.h>
#include "wizunzip.h"
#include "unzip.h"
#define STATUS_INCREMENT 512 /* incremental status data size */
#define MAX_H_CHARS 160 /* max horizontal chars. */
#define MAX_INDEX_ENTRIES 16 /* Message Window index max entries */
#define cchBufferMax 0xffffL /* max Message Buffer size. Must fit
* within one memory segment! */
#define cchTextOutMax 0x7fffL /* max no. bytes TextOut() accepts */
#define STDIO_BUF_SIZE (FILNAMSIZ+LONG_FORM_FNAME_INX) /* buffer size during printf or fprintf */
static short yClient; /* height of client area */
static short nVscrollPos = 0; /* scroll position of mesg. window */
static short nNumLines = 0; /* number of lines in buffer */
static short nVscrollMax; /* max scroll position of mesg. window */
static DWORD dwStatusSize = 0L; /* status data size */
static DWORD dwBufferSize = 0L; /* Status buffer size. Never
exceeds cchBufferMax */
static HANDLE hStatusBuffer; /* global mesg. handle */
static DWORD rgidwMsgWin[MAX_INDEX_ENTRIES]; /* max index entries */
static short cMsgWinEntries; /* no. active index entries, with
MAX_INDEX_ENTRIES as its max.
When set to 0, it's time to
re-index.*/
static short nLinesPerEntry; /* lines per index entry */
/* displayed when buffer shouldn't grow or can't grow */
static char __based(__segname("STRINGS_TEXT")) szClearBufferMsg[] =
"Clearing Status window to make room for more information.";
/* displayed when buffer shouldn't grow or can't grow */
static char __based(__segname("STRINGS_TEXT")) szCantClipboard[] =
"Cannot get enough memory to copy Status window to clipboard.";
struct KeyEntry
{
WORD wVirtKey;
BOOL bCntl;
WORD wMessage;
WORD wRequest;
} __based(__segname("STRINGS_TEXT")) KeyTable[] =
{
/* vertical scroll control */
{VK_HOME, TRUE, WM_VSCROLL, SB_TOP },
{VK_END, TRUE, WM_VSCROLL, SB_BOTTOM },
{VK_PRIOR, FALSE, WM_VSCROLL, SB_PAGEUP },
{VK_NEXT, FALSE, WM_VSCROLL, SB_PAGEDOWN },
{VK_UP, FALSE, WM_VSCROLL, SB_LINEUP },
{VK_DOWN, FALSE, WM_VSCROLL, SB_LINEDOWN },
/* horizontal scroll control */
{VK_HOME, FALSE, WM_HSCROLL, SB_TOP },
{VK_END, FALSE, WM_HSCROLL, SB_BOTTOM },
{VK_PRIOR, TRUE, WM_HSCROLL, SB_PAGEUP },
{VK_NEXT, TRUE, WM_HSCROLL, SB_PAGEDOWN },
{VK_LEFT, FALSE, WM_HSCROLL, SB_LINEUP },
{VK_RIGHT, FALSE, WM_HSCROLL, SB_LINEDOWN },
} ;
#define NUMKEYS (sizeof(KeyTable)/sizeof(struct KeyEntry))
/* Forward Refs
*/
static void FreeStatusLog(void);
/* Globals */
BOOL bRealTimeMsgUpdate = TRUE; /* update messages window in real-time.
* Reset by callers when update can be
* be deferred.
*/
BOOL gfCancelDisplay = FALSE; /* cancel display if got in over our heads */
/* Clears status buffer. Frees buffer.
*/
static void FreeStatusLog(void)
{
if (hStatusBuffer)
{
GlobalFree(hStatusBuffer);
hStatusBuffer = (HANDLE)0;
}
dwStatusSize = 0L; /* status data size */
dwBufferSize = 0L; /* status buffer size */
nNumLines = 0; /* number of lines in buffer */
nVscrollMax = 1;
SetScrollRange(hWndStatus, SB_VERT, 0, 1, FALSE);
nVscrollPos = 0;
SetScrollPos(hWndStatus, SB_VERT, nVscrollPos, TRUE);
}
/* Update Message Window Position is called after adding
* a number of lines to the message window without updating it.
* The function invalidates then updates the window.
*/
void UpdateMsgWndPos(void)
{
nVscrollPos = max(0,(nNumLines-cLinesMessageWin+1)); /* set position to next to last line */
SetScrollPos(hWndStatus, SB_VERT, nVscrollPos, TRUE);
InvalidateRect(hWndStatus, NULL, TRUE);
UpdateWindow(hWndStatus);
}
/* Set Status Top Window Position is called after adding
* a number of lines to the message window without updating it.
* Unlike UpdateMsgWndPos() above, this function sets the
* status window position to the top.
* The function invalidates then updates the window.
*/
void SetStatusTopWndPos(void)
{
nVscrollPos = 0; /* set position to next to top line */
SetScrollPos(hWndStatus, SB_VERT, nVscrollPos, TRUE);
InvalidateRect(hWndStatus, NULL, TRUE);
UpdateWindow(hWndStatus);
}
/* Add message line (or part of a line) to the global status buffer
* that is the contents of the Message Window.
* Assumes that global data is unlocked when called.
*/
void WriteStringToMsgWin(PSTR psz, BOOL bUpdate)
{
WriteBufferToMsgWin(psz, strlen(psz), bUpdate);
}
/* Add message buffer (maybe part of a line) to the global status buffer
* that is the contents of the Message Window.
* Assumes that global data is unlocked when called.
*/
void WriteBufferToMsgWin(LPSTR pszBuffer, int nBufferLen, BOOL bUpdate)
{
LPSTR lpszT; /* pointer into buffer */
HANDLE hStatusBufferTmp;
LPSTR lpGlobalBuffer; /* pointer into global buffer */
DWORD dwNewSize = dwStatusSize + (DWORD)nBufferLen;
int nIncrLines = 0; /* incremental lines in buffer */
int nIncompleteExistingLine = 0; /* add -1 if incomplete existing last line */
int nIncompleteAddedLine = 0; /* add +1 if incomplete added last line */
DWORD dwRequestedSize; /* Size needed to hold all data. Can't
practically exceeded cchBufferMax.*/
if (gfCancelDisplay) /* if canceling display (in the middle of a lengthy operation) */
return; /* just discard data */
if (!nBufferLen) /* if no data */
return; /* just beat it */
/* count LF's in buffer to later add to total */
for (lpszT = pszBuffer; lpszT != NULL && (lpszT - pszBuffer) < nBufferLen; )
{
/* use memchr() for speed (?) considerations */
if (lpszT = _fmemchr(lpszT, '\n', (size_t)(nBufferLen - (lpszT - pszBuffer))))
{
nIncrLines++; /* tally line found */
lpszT++; /* point beyond LF for next pass */
}
}
if (dwNewSize > dwBufferSize) /* if won't fit or 1st time */
{
/* Round up if necessary to nearest whole increment */
dwRequestedSize = ((dwNewSize + STATUS_INCREMENT - 1) /
STATUS_INCREMENT) * STATUS_INCREMENT;
if (hStatusBuffer) /* if buffer exists, realloc */
{
if (dwRequestedSize <= cchBufferMax &&
(hStatusBufferTmp = GlobalReAlloc(hStatusBuffer,
dwRequestedSize, GMEM_MOVEABLE)))
{
/* successful re-allocation */
hStatusBuffer = hStatusBufferTmp;
dwBufferSize = dwRequestedSize;
}
else /* re-allocation failed, make last-ditch attempt! */
{
FreeStatusLog(); /* free own buffers */
if (MessageBox (hWndMain, szClearBufferMsg,
"Note", MB_ICONINFORMATION | MB_OKCANCEL) == IDCANCEL)
gfCancelDisplay = TRUE;
else /* no cancel */
WriteBufferToMsgWin(pszBuffer, nBufferLen, bUpdate);
return;
}
}
else /* 1st time */
{
if (hStatusBuffer = GlobalAlloc(GMEM_MOVEABLE,
dwRequestedSize))
{
dwBufferSize = dwRequestedSize; /* save it */
}
else /* 1st allocation failed! */
{
WinAssert(hStatusBuffer);
return;
}
}
}
/* should be easy copy of data from here */
lpGlobalBuffer = GlobalLock(hStatusBuffer);
if (lpGlobalBuffer)
{
/* Account for partial lines existing and being added. */
if (dwStatusSize &&
lpGlobalBuffer[dwStatusSize-1] != '\n')
nIncompleteExistingLine-- ; /* subtract 1 */
if (pszBuffer[nBufferLen-1] != '\n') /* nBufferLen guaranteed >0 */
nIncompleteAddedLine++ ; /* add 1 */
/* copy data into global buffer */
if (nBufferLen) /* map to ANSI; if 0 don't copy; 0 means 65K */
{
OemToAnsiBuff(pszBuffer, &lpGlobalBuffer[dwStatusSize], nBufferLen);
}
/* bump no. lines accounting for incomplete lines */
nNumLines += (nIncrLines+nIncompleteExistingLine+nIncompleteAddedLine);
dwStatusSize = dwNewSize; /* new data size counting end null */
GlobalUnlock(hStatusBuffer);
nVscrollMax = max(1, nNumLines + 2 - yClient/dyChar);
SetScrollRange(hWndStatus, SB_VERT, 0, nVscrollMax, FALSE);
cMsgWinEntries = 0; /* re-index whenever more data is added */
if (bUpdate) /* if requested to update message box */
{
nVscrollPos = max(0,(nNumLines-cLinesMessageWin+1)); /* set position to next to last line */
SetScrollPos(hWndStatus, SB_VERT, nVscrollPos, TRUE);
InvalidateRect(hWndStatus, NULL, TRUE);
UpdateWindow(hWndStatus);
}
}
else
{
WinAssert(lpGlobalBuffer);
}
}
long FAR PASCAL StatusProc(HWND hWnd, WORD wMessage, WORD wParam, LONG lParam)
{
short xClient ; /* size of client area */
HDC hDC; /* device context */
PAINTSTRUCT ps;
struct KeyEntry __far *pKE; /* pointer to key entry */
LPSTR lpStatusBuffer; /* pointer to global msg. buffer */
int nMenuItemCount; /* no. items in System menu before deleting separators */
BOOL bCntl; /* control shift pressed ? */
static short nHscrollMax;
static short nHscrollPos;
static short nMaxWidth; /* in pixels */
short nVscrollInc;
short nHscrollInc;
short i, x, y, nPaintBeg, nPaintEnd;
HMENU hSysMenu; /* this guy's system menu */
switch (wMessage)
{
case WM_CREATE:
nMaxWidth = MAX_H_CHARS * dxChar;
nVscrollPos = 0;
nVscrollMax = max(1,nNumLines);
SetScrollRange(hWnd, SB_VERT, 0, nVscrollMax, FALSE);
SetScrollPos(hWnd, SB_VERT, 0, TRUE);
/* Remove system menu items to limit user actions on status window */
hSysMenu = GetSystemMenu(hWnd, FALSE);
DeleteMenu(hSysMenu, SC_SIZE, MF_BYCOMMAND);
DeleteMenu(hSysMenu, SC_MOVE, MF_BYCOMMAND);
DeleteMenu(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
DeleteMenu(hSysMenu, SC_TASKLIST, MF_BYCOMMAND);
/* walk thru menu and delete all separator bars */
for (nMenuItemCount = GetMenuItemCount(hMenu);
nMenuItemCount ; nMenuItemCount--)
{
if (GetMenuState(hSysMenu, nMenuItemCount-1, MF_BYPOSITION) & MF_SEPARATOR)
{
DeleteMenu(hSysMenu, nMenuItemCount-1, MF_BYPOSITION);
}
}
return 0;
case WM_SIZE:
xClient = LOWORD(lParam);/* x size of client area */
yClient = HIWORD(lParam);/* y size of client area */
nVscrollMax = max(1, nNumLines + 2 - yClient/dyChar);
nVscrollPos = min(nVscrollPos, nVscrollMax);
SetScrollRange(hWnd, SB_VERT, 0, nVscrollMax, FALSE);
SetScrollPos(hWnd, SB_VERT, nVscrollPos, TRUE);
nHscrollMax = max(0, 2 + (nMaxWidth - xClient) / dxChar);
nHscrollPos = min(nHscrollPos, nHscrollMax);
SetScrollRange(hWnd, SB_HORZ, 0, nHscrollMax, FALSE);
SetScrollPos(hWnd, SB_HORZ, nHscrollPos, TRUE);
return 0;
case WM_SYSCOMMAND:
switch ((wParam & 0xFFF0))
{
case SC_RESTORE: /* alert parent */
PostMessage(hWndMain, WM_COMMAND, IDM_SPLIT, 0L);
break;
case SC_MAXIMIZE:
PostMessage(hWndMain, WM_COMMAND, IDM_MAX_STATUS, 0L);
break;
default:
return DefWindowProc(hWnd, wMessage, wParam, lParam);
}
break;
case WM_COMMAND:
if (wParam == IDM_CLEAR_STATUS)
{
FreeStatusLog();
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
}
break;
case WM_VSCROLL: /* scroll bar action on list box */
switch (wParam)
{
case SB_TOP:
nVscrollInc = -nVscrollPos;
break;
case SB_BOTTOM:
nVscrollInc = nVscrollMax - nVscrollPos;
break;
case SB_LINEUP:
nVscrollInc = -1;
break;
case SB_LINEDOWN:
nVscrollInc = 1;
break;
case SB_PAGEUP:
nVscrollInc = min(-1, -yClient/dyChar);
break;
case SB_PAGEDOWN:
nVscrollInc = max(1, yClient/dyChar);
break;
case SB_THUMBPOSITION:
nVscrollInc = LOWORD(lParam) - nVscrollPos;
break;
default: /* END_SCROLL comes thru here */
nVscrollInc = 0;
}
if (nVscrollInc = max(-nVscrollPos,
min(nVscrollInc, nVscrollMax - nVscrollPos)))
{
nVscrollPos += nVscrollInc;
ScrollWindow(hWnd, 0, -dyChar * nVscrollInc, NULL, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -