📄 ntse95r.c
字号:
/****************************************************************************
NT-Service helper library.
SCM Emulation on Win95.
Running the services.
Copyright (c) 2000,2002 Timofei Bondarenko, Kostya Volovich.
****************************************************************************/
#include <windows.h>
#include <winsvc.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h> /* offsetof()*/
#include <process.h>
#include "ntse.h"
#include "ntsepriv.h"
#ifndef SIZEOF_ARRAY
#define SIZEOF_ARRAY(xx) (sizeof(xx)/sizeof((xx)[0]))
#endif
static HINSTANCE hInstGlobal = 0;
static HWND hWndGlobal = 0;
static HMENU hPopupGlobal = 0;
static HICON hIconGlobal16;
static HICON hIconGlobal32;
static QUERY_SERVICE_CONFIG *wndSvcConf;
static CRITICAL_SECTION wndLock;
static int wndLock_ok;
static int wndShouldExit;
static int wndDestroyed;
static ntseContext *wndNC;
static UINT wm_TaskbarCreated;
static int ntseRegServProc95(int reg);
static unsigned command_for_all(unsigned ctl);
static int InitInstance(int, const char *);
static void ExitInstance(void);
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int ntseStatus95(ntseHandle se, const SERVICE_STATUS *st)
{
int ch = 0;
UL_TRACE((NSLOG, "ntseStatus95 {..."));
if (!wndLock_ok) return -1;
if (&se->niStatus != st)
{
EnterCriticalSection(&wndLock);
ch = se->niStatus.dwControlsAccepted != st->dwControlsAccepted ||
se->niStatus.dwCurrentState != st->dwCurrentState;
se->niStatus = *st;
LeaveCriticalSection(&wndLock);
}
if (ch && !wndDestroyed && hWndGlobal)
{
PostMessage(hWndGlobal, WM_COMMAND, se->niWnd + nwCmdSvSTATUS, 0);
UL_TRACE((NSLOG, "ntseStatus95 sent %x", se->niWnd + nwCmdSvSTATUS));
}
return 0;
}
int ntseServRun95(ntseContext *nc,
int (*init_callback)(void *arg, HWND), void *arg)
{
int rv;
MSG msg;
ntseService_int *stw = ntse_servlist;
while(stw->niSe)
{
stw->niStatus.dwCurrentState = stw->niLastStatus = SERVICE_STOPPED;
stw->niStatus.dwControlsAccepted = stw->niLastAccept = 0;
stw++;
}
wndShouldExit = 0;
/********* Windowng stuff here *********************************/
wndNC = nc;
if (!wndLock_ok)
{
InitializeCriticalSection(&wndLock);
wndLock_ok = 1;
}
if (!hInstGlobal) hInstGlobal = GetModuleHandle(NULL);
ntseQueryConf95(nc, ntse_servlist->niSe->nsName, &wndSvcConf);
SetLastError(0); /* Win95 doesn't report some errors,
so clean a previous error code */
wndDestroyed = 0;
if (rv = InitInstance(SW_HIDE/*nCmdShow*/, ntse_servlist->niSe->nsName))
goto Return;
if (0 != init_callback)
{
UL_TRACE((NSLOG, "Calling init_callback(%p, hwnd=%x)...",
arg, hWndGlobal));
if (rv = init_callback(arg, hWndGlobal)) goto Return;
}
#if 1
FreeConsole();
#endif
if (wndSvcConf && wndSvcConf->dwStartType == SERVICE_AUTO_START)
{
command_for_all(nwCmdCtlSTART);
#if 0 /* Let them remove it from taskbar, if required */
rv = ntseAutoRun95(nc, ntse_servlist->niSe->nsName,
wndSvcConf->lpBinaryPathName);
UL_TRACE((NSLOG, "%!l Ensuring AutoRun :: %s / %s",
rv, ntse_servlist->niSe->nsName, wndSvcConf->lpBinaryPathName));
#endif
}
ntseRegServProc95(1);
wm_TaskbarCreated = RegisterWindowMessage("TaskbarCreated");
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
ntseRegServProc95(0);
command_for_all(nwCmdCtlSTOP);
/* rv = 100; // ntseServiceRun() does ...
while(command_for_all(nwCmdCtlSTOP) && --rv) Sleep(100);
*/
rv = 0;
Return:
ExitInstance();
/***************************************************************/
if (wndLock_ok)
{
wndLock_ok = 0;
DeleteCriticalSection(&wndLock);
}
if (wndSvcConf)
{
ntseFree(nc, wndSvcConf); wndSvcConf = 0;
}
wndNC = NULL;
if (rv)
UL_INFO((NSLOG, "%!l ntseRunServ95(%d) FAILED", rv, ntse_servcount));
else
UL_TRACE((NSLOG, "ntseRunServ95() Finished Ok"));
return rv;
}
static UINT isAcceptedMF(ntseService_int *sw, unsigned ctl)
{
unsigned LastStatus, LastAccept;
EnterCriticalSection(&wndLock);
LastStatus = sw->niStatus.dwCurrentState;
LastAccept = sw->niStatus.dwControlsAccepted;
LeaveCriticalSection(&wndLock);
if (LastStatus == SERVICE_STOPPED ||
LastStatus <= 0) return ctl? MF_GRAYED: MF_ENABLED;
if (ctl >= nwCTL_MAX)
return ctl >= 128 && ctl <= 255? MF_ENABLED: MF_GRAYED;
if (ntse_ctlx[ctl].ctlcode == SERVICE_CONTROL_INTERROGATE)
return MF_ENABLED;
if (0 == (ntse_ctlx[ctl].accept & LastAccept))
return MF_GRAYED;
if (LastStatus == SERVICE_PAUSED ||
LastStatus == SERVICE_PAUSE_PENDING)
{
if (ntse_ctlx[ctl].ctlcode == SERVICE_CONTROL_PAUSE)
return MF_GRAYED;
}
else
{
if (ntse_ctlx[ctl].ctlcode == SERVICE_CONTROL_CONTINUE)
return MF_GRAYED;
}
return MF_ENABLED;
}
#define isAccepted(sw,ctl) (MF_ENABLED == isAcceptedMF(sw, ctl))
static void sw_main(ntseService_int *se)
{
SERVICE_STATUS st;
const char *argc[1];
argc[0] = se->niSe->nsName;
UL_TRACE((NSLOG, "sw_main: invoking... %p", se));
if (se->niSe->nsStatus) st = *se->niSe->nsStatus;
else memset(&st, 0, sizeof(st));
st.dwCurrentState = SERVICE_START_PENDING;
st.dwControlsAccepted = 0;
ntseStatus95(se, &st);
se->niSe->nsMain(se, 1, argc);
UL_TRACE((NSLOG, "sw_main: finished %p", se));
st.dwCurrentState = SERVICE_STOPPED;
st.dwControlsAccepted = 0;
ntseStatus95(se, &st);
se->niSh = 0;
if (wndShouldExit)
PostMessage(hWndGlobal, WM_COMMAND, nwCmdWmEXIT, 0);
}
/* Return > 0 if beginthread failed, -1 if command is not accepted */
static int process_command(unsigned ctl, int verbose)
{
unsigned srn, fn;
ntseService_int *sw;
UL_TRACE((NSLOG, "wnd_ctl: %x", ctl));
srn = (ctl - nwCmdBASE) / nwCmdMUL;
fn = (ctl - nwCmdBASE) % nwCmdMUL;
UL_TRACE((NSLOG, "process command{ %d %d }", srn, fn));
if (ctl < nwCmdBASE || srn >= ntse_servcount)
{
UL_INFO((NSLOG, "wnd_ctl: 0x%x Out of range (0x%x)", ctl, ntse_servcount));
return -1;
}
sw = &ntse_servlist[srn];
if (fn == nwCmdSvSTATUS)
{
int ch = 0;
EnterCriticalSection(&wndLock);
if (sw->niLastStatus != sw->niStatus.dwCurrentState)
sw->niLastStatus = sw->niStatus.dwCurrentState, ch = 1;
if (sw->niLastAccept != sw->niStatus.dwControlsAccepted)
sw->niLastAccept = sw->niStatus.dwControlsAccepted, ch = 1;
LeaveCriticalSection(&wndLock);
if (ch) /* changed? */
{
ch = sw->niWnd;
ModifyMenu(hPopupGlobal, ch + nwCmdSvSTATUS,
MF_BYCOMMAND|MF_STRING,
ch + nwCmdSvSTATUS,
(LPSTR)ntsePrintState(sw->niLastStatus));
for(fn = 0; fn < nwCTL_MAXMENU; fn++)
EnableMenuItem(hPopupGlobal, ch + fn,
MF_BYCOMMAND|isAcceptedMF(sw, fn));
// DrawMenuBar(hWndGlobal);
}
return 0;
}
if (!isAccepted(sw, fn)/* && fn == nwCmdCtlSHUTDOWN &&
!isAccepted(sw, fn = SERVICE_CONTROL_STOP)*/)
{ // real SCM doesn't convert SHUTDOWN to STOP
UL_TRACE((NSLOG, "wnd_ctl: 0x%x is not accepted by 0x%x", fn, srn));
return -1;
}
if (fn != 0)
sw->niSe->nsHandler(fn < nwCTL_MAX? ntse_ctlx[fn].ctlcode: fn);
else if (!sw->niSh)
{
sw->niStatus.dwCurrentState = SERVICE_STOPPED;
sw->niStatus.dwControlsAccepted = 0;
sw->niSh = 1;
if (-1 == _beginthread((void(*)(void*))sw_main, 0, sw))
{
sw->niSh = 0;
UL_ERROR((NSLOG, "wnd_ctl: Failed to start thread [%s]", sw->niSe->nsName));
if (verbose)
MessageBox(hWndGlobal, "Failed to start service", sw->niSe->nsName,
MB_OK|MB_ICONERROR);
return 1;
}
else
{
UL_TRACE((NSLOG, "wnd_ctl: thread started [%s]", sw->niSe->nsName));
}
}
#if 1
else return -1;
#else
else if (verbose)
MessageBox(hWndGlobal, "Failed to start service\r\n"
"The service is already running\r\n"
"or not completly stopped yet.",
sw->niSe->nsName,
MB_OK|MB_ICONERROR);
#endif
return 0;
}
/* Return number of acceptors of a command or total for command =-1 */
static unsigned command_for_all(unsigned ctl)
{
unsigned running = 0;
unsigned ii;
for(ii = 0; ii < ntse_servcount; ii++)
{
if ((-1 == (int)ctl ||
0 == process_command(ctl + ntse_servlist[ii].niWnd, 0))
&& ntse_servlist[ii].niSh) running++;
}
UL_DEBUG((NSLOG, "ntse95::command_for_all(%d) = %u", ctl, running));
return running;
}
static BOOL refresh_start_type(HMENU menu)
{
static const struct StartTypeData
{
char *text;
unsigned type;
unsigned command;
} sttData[] = {
{ "Auto", SERVICE_AUTO_START, nwCmdStAUTO },
{ "Manual", SERVICE_DEMAND_START, nwCmdStDEMAND },
{ "Disabled", SERVICE_DISABLED, nwCmdStDISABLED } };
BOOL rv = 1;
int ii;
for(ii = 0; ii < SIZEOF_ARRAY(sttData); ii++)
{
UINT attr = wndSvcConf ? (wndSvcConf->dwStartType ==
sttData[ii].type ? MF_ENABLED|MF_CHECKED|MF_STRING:
MF_ENABLED|MF_UNCHECKED|MF_STRING):
MF_GRAYED |MF_STRING;
rv &= 0 != menu? AppendMenu(menu, attr,
sttData[ii].command, sttData[ii].text)
: ModifyMenu(hPopupGlobal, sttData[ii].command, attr,
sttData[ii].command, (LPSTR)sttData[ii].text);
}
return rv;
}
static int InitMenus(void)
{
HMENU submenu, demenu = 0;
unsigned ii;
int rv = 1;
ntseService_int *srw = ntse_servlist;
#if defined(USE_LOG) && USE_LOG >= ll_NOTICE
#define ANDrv rv = rv &&
#else
#define ANDrv
#endif
for(ii = 0; rv && srw->niSe; ii++, srw++)
{
int xx;
int xwn = srw->niWnd = nwCmdBASE + ii * nwCmdMUL;
submenu = CreatePopupMenu();
if (!submenu ||
!AppendMenu(hPopupGlobal, MF_POPUP|MF_STRING,
(UINT_PTR)submenu, srw->niSe->nsName))
{
demenu = submenu; goto Error;
}
ANDrv AppendMenu(ii? submenu: hPopupGlobal, MF_STRING,
xwn + nwCmdSvSTATUS, ntsePrintState(srw->niLastStatus));
ANDrv AppendMenu(ii? submenu: hPopupGlobal, MF_SEPARATOR, 0, "");
for(xx = 0; rv && xx < nwCTL_MAXMENU; xx++)
{
ANDrv AppendMenu(submenu, MF_STRING | isAcceptedMF(srw, xx),
xwn + xx, ntse_ctlx[xx].ctlname);
}
}
if (ii > 1)
{
ANDrv AppendMenu(hPopupGlobal, MF_SEPARATOR, 0, "");
}
submenu = CreatePopupMenu();
if (!submenu ||
!AppendMenu(hPopupGlobal, MF_POPUP|MF_STRING/*|
(wndSvcConf? MF_ENABLED: MF_GRAYED)*/,
(UINT_PTR)submenu, "Start Type"))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -