雷达智富

首页 > 内容 > 程序笔记 > 正文

程序笔记

Windows中后台服务与用户模式进程的跨进程信号量

2024-08-17 45

在Windows中,后台服务与用户模式的进程之间,可能需要通过信号量进行一些同步操作,最近在写类似功能的时候发现,创建Event,Mutex,Semphore时,使用命名的创建方式无法实现同步,两个进程的信号量之间都无反应。
服务端的代码如下:

#includeiostream
#includewindows.h
#includewinbase.h
using namespace std;
#define SLEEP_TIME 50000

typedef void* handle;
typedef WINADVAPI BOOL (WINAPI *PInitializeSecurityDescriptor)(PSECURITY_DESCRIPTOR, DWORD);
typedef WINADVAPI BOOL (WINAPI *PSetSecurityDescriptorDacl)(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL);
#define LOGFILE D:\\result.txt
handle temp=NULL;
static int a=65;
char muname[]={NewMutex2};
int errNm;
char *str;
FILE* log;

SECURITY_ATTRIBUTES  *g_pSaCms;
SERVICE_STATUS ServiceStatus; 
SERVICE_STATUS_HANDLE hStatus; 

void  ServiceMain(int argc, char** argv); 
void  ControlHandler(DWORD request); 
int InitService();


bool Win32Mutex(char muname[8])
{

    HINSTANCE hAdvApi = LoadLibrary(Advapi32.DLL);
    PInitializeSecurityDescriptor pInitializeSecurityDescriptor = 0;
    PSetSecurityDescriptorDacl pSetSecurityDescriptorDacl = 0;
    PSECURITY_DESCRIPTOR pSD = 0;
    g_pSaCms = new SECURITY_ATTRIBUTES;
    if (g_pSaCms == 0)
    {
        prinerr();
        return 1;
    }
    memset(g_pSaCms,0X0, sizeof(*g_pSaCms));
    g_pSaCms-nLength = sizeof(*g_pSaCms);
    g_pSaCms-bInheritHandle = 1;

    pSD = new SECURITY_DESCRIPTOR;

    if (pSD == 0)
    {
        printerr();
            goto LABEL_CSA_ERROR;
    }

    pInitializeSecurityDescriptor = (PInitializeSecurityDescriptor)GetProcAddress(hAdvApi,InitializeSecurityDescriptor);

    if (pInitializeSecurityDescriptor == 0)
    {
        printerr();
            goto LABEL_CSA_ERROR;
    }

    pSetSecurityDescriptorDacl = (PSetSecurityDescriptorDacl)GetProcAddress(hAdvApi, SetSecurityDescriptorDacl);

    if (pSetSecurityDescriptorDacl == 0)
    {
            goto LABEL_CSA_ERROR;
    }

    if (!(*pInitializeSecurityDescriptor)(pSD, SECURITY_DESCRIPTOR_REVISION)
            || (!(*pSetSecurityDescriptorDacl)(pSD, TRUE, (PACL)0, FALSE)))
    {
            goto LABEL_CSA_ERROR;
    }

    (void)FreeLibrary(hAdvApi);
    g_pSaCms-lpSecurityDescriptor=pSD;
    goto LABEL_CSA_PASS;

LABEL_CSA_ERROR:
    (void)FreeLibrary(hAdvApi);

    if (pSD != 0)
    {
        delete pSD;
        pSD = 0;
    }

    if (g_pSaCms != 0)
    {
        delete g_pSaCms;
        g_pSaCms = 0;
    }


LABEL_CSA_PASS:
    temp=::CreateMutex(g_pSaCms,0,muname); //for icdcomm
    errNm=GetLastError();
    if (!temp)
    {
        print_err();
    }
    else
    {
        print_err();
    }
    if ((!temp) || errNm == ERROR_ALREADY_EXISTS)
    {
            if(temp)
            {
            (void)CloseHandle(temp);
            a++;
            muname[8]=a;
            Win32Mutex(muname);
            }
            else
            {
            printInf()
            }
            return 0;
    }
    return 1;
}



int main()
{ 
    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = MemoryStatus;
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;

    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;
    StartServiceCtrlDispatcher(ServiceTable);  
    return 0;
}

void ServiceMain(int argc, char** argv) 
{
    int error; 
    ServiceStatus.dwServiceType        = SERVICE_WIN32; 
    ServiceStatus.dwCurrentState       = SERVICE_START_PENDING; 
    ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    ServiceStatus.dwWin32ExitCode      = 0; 
    ServiceStatus.dwServiceSpecificExitCode = 0; 
    ServiceStatus.dwCheckPoint         = 0; 
    ServiceStatus.dwWaitHint           = 0; 

    hStatus = RegisterServiceCtrlHandler(
        MemoryStatus, 
        (LPHANDLER_FUNCTION)ControlHandler); 
    if (hStatus == (SERVICE_STATUS_HANDLE)0) 
    { 
        // Registering Control Handler failed
        return; 
    }  
    // Initialize Service 
    error = InitService(); 
    if (error) 
    {
        // Initialization failed
        ServiceStatus.dwCurrentState       = SERVICE_STOPPED; 
        ServiceStatus.dwWin32ExitCode      = -1; 
        SetServiceStatus(hStatus, ServiceStatus); 
        return; 
    } 

    // My service
    muname[8]=a;
    Win32Mutex(muname);

    // We report the running status to SCM. 
    ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
    SetServiceStatus (hStatus, ServiceStatus);


    // The worker loop of a service
    while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
    {
        Sleep(SLEEP_TIME);
    }
    return;
}

// Control handler function
void ControlHandler(DWORD request) 
{ 
    switch(request) 
    { 
        case SERVICE_CONTROL_STOP: 
            ServiceStatus.dwWin32ExitCode = 0; 
            ServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
            SetServiceStatus (hStatus, ServiceStatus);
            return; 

        case SERVICE_CONTROL_SHUTDOWN: 

            ServiceStatus.dwWin32ExitCode = 0; 
            ServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
            SetServiceStatus (hStatus, ServiceStatus);
            return; 

        default:
            break;
    } 

    // Report current status
    SetServiceStatus (hStatus,  ServiceStatus);

    return; 
} 

用户程序如下:

int main()
{ 
    muname[8]=a;
    Win32Mutex(muname);
    Sleep(SLEEP_TIME);
    return 0;
}

查找相关资料发现,在Windows系统中,后台服务程序通常是运行在session0,而用户程序是运行在session1,这两个进程之间如果要实现进程间的同步,创建信号量时,应当用全局的名称进行创建,如下:

char muname[]={Global\\NewMutex2};

参考:
https://docs.microsoft.com/zh-cn/windows/win32/termserv/kernel-object-namespaces?redirectedfrom=MSDN

关于session0进程隔离:
https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653293(v=vs.85)?redirectedfrom=MSDN

更新于:3个月前
赞一波!3

文章评论

评论问答