按MSDN:ms-help://MS.MSDNQTR.2003FEB.2052/debug/base/registereventsource.htm里的说法,
RegisterEventSource这个函数测试注册表中 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\EventLog\Application\这个键下是否有某个指定的子键,
例如,如果HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\
     EventLog\Application\WinApp这个键值存在的话,那么代码
h = RegisterEventSource(NULL,  // uses local computer 
             TEXT("WinApp"));    // source name 
应该返回一个有效的句柄值。MSDN的部分原文:
For example, WinApp is a valid source name if the registry has the following key: 
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\
     EventLog\Application\WinApp但是我和几个朋友的机器上测试,结果却大不相同我的机器上的测试代码段
HANDLE h;
if ((h = RegisterEventSource(NULL,TEXT("SnortService"))) == NULL){
cout<<GetLastError()<<endl;
cout<<"not exist!"<<endl;
}
结果,无论我输入的子键值存在不存在,h均为NULL,
我的系统为中文2000 server+SP4七猫兄的测试代码段和我一样,但结果正常,如果子键存在,则h不为空,子键不存在,则h== hull,他的机器为中文2003 server猎狐兄的测试代码段如下
  HANDLE h;
  LPCTSTR s="134";
  if ((h =RegisterEventSource(NULL,s)) == NULL){
AfxMessageBox("No Result");
  }
测试结果更有意思:无论子键是否存在,h均不为空,和我的正好相反:-),猎狐兄的机器是日文2000
不知道这算不算微软的BUG,希望有条件的朋友也帮着测试一下,然后把结果和你的机器配置发上来,谢谢!

解决方案 »

  1.   

    补充,在同事的XP 中文版下测试正常,子键存在则h!=null ,不存在则 == null
      

  2.   


    用RegOpenKeyEx看返回值不也能知道键存在不存在吗?
      

  3.   

    cpio(希望我的回复能带给您一点点帮助) ( ) 信誉:100  2006-05-19 11:07:00  得分: 0  
    用RegOpenKeyEx看返回值不也能知道键存在不存在吗?我的目的就是要测RegisterEventSource这个函数,呵呵。
      
     
      

  4.   

    顺便说一下,我的 getlasterror返回值是1717,含义是unknown interface,微软的东西真是不知所云,呵呵
      

  5.   

    有木有用GetLastError看是什么问题?
      

  6.   

    老迈表乱贴本地msdn的地址如果没装MSDN 2003 Feb打开不了的。
    看http://msdn.microsoft.com/library/en-us/eventlog/base/registereventsource.aspRegisterEventSourceThe RegisterEventSource function retrieves a registered handle to the specified event log人家说的是从event log里边找好不好
      

  7.   

    我的测试代码int main()
    {
    HANDLE h=NULL;
    cout<< "result:" <<endl;
    h = RegisterEventSource(NULL,TEXT("asasdf"));
    cout<< "ErrorNum:" << GetLastError()<<endl;
    cout<< "HANDLE ID:"<< h << endl;
    if ( h == NULL)
    {
    cout<<"not exist!"<<endl;
    }
    }我的环境
    简体中文Windows XP SP2至05月最新补丁
    VISUAL C++ 2005 PROFESSIONAL键存在与不存在
    都返回非NULL
    result:
    ErrorNum:0
    HANDLE ID:00155DA0看了一下MSDN对这个函数的描述
    在requirements里面
    Client Requires Windows XP, Windows 2000 Professional, or Windows NT Workstation. 
    Server Requires Windows Server 2003, Windows 2000 Server, or Windows NT Server. 说明是支持windows xp的
    但是却真的不生效,可能真的有问题
      

  8.   

    如果返回unknown interface 
    应该是还没有实现这个函数
    这种情况在98下面挺多
    如果系统不支持,很可能就直接实现了一个空函数
      

  9.   

    哦,罐头说的倒很有启发,难道我得去装个SDK?
      

  10.   

    测试环境: win2k sp4
    测试代码:
    HANDLE h;
    if ((h = RegisterEventSource(NULL,TEXT("SnortService"))) == NULL){
    cout<<GetLastError()<<endl;
    cout<<"not exist!"<<endl;
    }结果,返回都为非NULL, 但是发现不关用什么关键字,返回的HANDLE值都一样。
    而且,真正用这个HANDLE去写log的时候,都是失败的.
      

  11.   

    应该不是。不支持的话就是系统底层的API就不支持这个功能
    SDK只是提供用来开发的API
    底层的还是kernel。dll那种东西。没法替换的。
    具体的倒是真的可以问下ms
    好像是有点奇怪
    楼上的结果和我一样。
      

  12.   

    看了一下,这个还是RPC调用,先把客户端贴一下。不过估计用处也不太大。
    NTSTATUS
    ElfRegisterEventSourceW (
        IN  PUNICODE_STRING         UNCServerName,
        IN  PUNICODE_STRING         ModuleName,
        OUT PHANDLE                 LogHandle
        )/*++Routine Description:    This is the client DLL entry point for the ElfRegisterEventSource API.    It creates an RPC binding for the server specified, and stores that
        and additional data away. It returns a handle to the caller that can
        be used to later on access the handle-specific information.Arguments:    UNCServerName   - Server with which to bind for subsequent operations.    ModuleName      - Supplies the name of the module to associate with
                          this handle.    LogHandle       - Location where log handle is to be returned.
    Return Value:    Returns an NTSTATUS code and, if no error, a handle that can be used
        for subsequent Elf API calls.
    --*/
    {
        NTSTATUS            status = STATUS_SUCCESS;
        UNICODE_STRING      RegModuleName;
        EVENTLOG_HANDLE_W   ServerNameString;    //
        // Make sure input & output pointers are valid
        //    if (!LogHandle || !ModuleName || ModuleName->Length == 0) {
           return(STATUS_INVALID_PARAMETER);
        }    if ((UNCServerName != NULL) && (UNCServerName->Length != 0)) {
            ServerNameString = UNCServerName->Buffer;
        } else {
            ServerNameString = NULL;
        }    RtlInitUnicodeString( &RegModuleName, UNICODE_NULL);    // Call service via RPC. Pass in major and minor version numbers.    *LogHandle = NULL;          // Must be NULL so RPC fills it in    //
        // Do the RPC call with an exception handler since RPC will raise an
        // exception if anything fails. It is up to us to figure out what
        // to do once the exception is raised.
        //
        RpcTryExcept {        status = ElfrRegisterEventSourceW(
                        ServerNameString,
                        (PRPC_UNICODE_STRING)ModuleName,
                        (PRPC_UNICODE_STRING)&RegModuleName,
                        ELF_VERSION_MAJOR,
                        ELF_VERSION_MINOR,
                        (PIELF_HANDLE) LogHandle
                        );    }
        RpcExcept (1) {        status = I_RpcMapWin32Status(RpcExceptionCode());
        }
        RpcEndExcept
        return (status);
    }
      

  13.   

    这是服务器端
    NTSTATUS
    ElfpOpenELW (
        IN  EVENTLOG_HANDLE_W   UNCServerName,
        IN  PRPC_UNICODE_STRING ModuleName,
        IN  PRPC_UNICODE_STRING RegModuleName,
        IN  ULONG               MajorVersion,
        IN  ULONG               MinorVersion,
        OUT PIELF_HANDLE        LogHandle,
        IN  ULONG               DesiredAccess
        )/*++Routine Description:  Looks alot like ElfrOpenELW but also gets passed a DesiredAccess.Arguments:    UNCServerName   - Not used.    ModuleName      - Name of the module that is making this call.    RegModuleName   - Not used.    MajorVersion/MinorVersion - The version of the client.
        LogHandle       - Pointer to the place where the pointer to the
                          context handle structure will be placed.    DesiredAccess   - Indicates the access desired for this logfile.Return Value:    Returns an NTSTATUS code and, if no error, a "handle".
    --*/
    {
        NTSTATUS        Status;
        PLOGMODULE      Module;
        IELF_HANDLE     LogIHandle;
        BOOL            ForSecurityLog = FALSE;    //
        // Check arguments.
        //    Status = VerifyUnicodeString(ModuleName);    if (!NT_SUCCESS(Status)) {
            return(Status);
        }    if (LogHandle == NULL) {
            return(STATUS_INVALID_PARAMETER);
        }    //
        // Allocate a new structure for the context handle
        //    LogIHandle = (IELF_HANDLE) ElfpAllocateBuffer (
                                        sizeof (*LogIHandle)
                                      + ModuleName->Length
                                      + sizeof (WCHAR)
                                      );    if (LogIHandle) {        //
            // Find the module structure in order to pull out the Atom.
            //
            // GetModuleStruc *always* succeeds! (returns default if module
            // not found).
            //        Module = GetModuleStruc ((PUNICODE_STRING)ModuleName);        //
            // Validate the caller has appropriate access to this logfile.
            // If this is the security log, then check privilege instead.
            //
            if (_wcsicmp(ELF_SECURITY_MODULE_NAME, Module->LogFile->LogModuleName->Buffer) == 0) {
                ForSecurityLog = TRUE;
            }
            Status = ElfpAccessCheckAndAudit(
                L"EventLog",            // SubSystemName
                L"LogFile",             // ObjectTypeName
                Module->ModuleName,     // ObjectName
                LogIHandle,             // Context handle - required?
                Module->LogFile->Sd,    // Security Descriptor
                DesiredAccess,          // Requested Access
                NULL,                   // GENERIC_MAPPING
                ForSecurityLog          // Indicates the check is for security log
                );        if (NT_SUCCESS(Status)) {            LogIHandle->Atom = Module->ModuleAtom;            LogIHandle->NameLength = ModuleName->Length + sizeof(WCHAR);
                RtlMoveMemory( LogIHandle->Name,
                                ModuleName->Buffer,
                                ModuleName->Length
                             );            LogIHandle->Name[ModuleName->Length / sizeof(WCHAR)] = L'\0';            LogIHandle->MajorVersion = MajorVersion; // Store the version
                LogIHandle->MinorVersion = MinorVersion; // of the client            //
                // Initialize seek positions and flags to zero.
                //            LogIHandle->SeekRecordPos    = 0;
                LogIHandle->SeekBytePos      = 0;
                LogIHandle->Flags            = 0;
                LogIHandle->dwNotifyRequests = 0;            //
                // Link in this structure to the list of context handles
                //            LogIHandle->Signature = ELF_CONTEXTHANDLE_SIGN; // DEBUG
                LinkContextHandle (LogIHandle);            *LogHandle = LogIHandle;                // Set return handle
                Status = STATUS_SUCCESS;                // Set return status
            }
            else {
                ElfpFreeBuffer(LogIHandle);
            }    } else {        Status = STATUS_NO_MEMORY;
        }    return (Status);    UNREFERENCED_PARAMETER(UNCServerName);
        UNREFERENCED_PARAMETER(RegModuleName);
    }
      

  14.   

    这是里面一个检查和审计的代码,我怀疑搞不好就是这里面报错了。
    NTSTATUS
    ElfpAccessCheckAndAudit(
        IN     LPWSTR SubsystemName,
        IN     LPWSTR ObjectTypeName,
        IN     LPWSTR ObjectName,
        IN OUT IELF_HANDLE ContextHandle,
        IN     PSECURITY_DESCRIPTOR SecurityDescriptor,
        IN     ACCESS_MASK DesiredAccess,
        IN     PGENERIC_MAPPING GenericMapping,
        IN     BOOL ForSecurityLog
        )
    /*++Routine Description:    This function impersonates the caller so that it can perform access
        validation using NtAccessCheckAndAuditAlarm; and reverts back to
        itself before returning.Arguments:    SubsystemName - Supplies a name string identifying the subsystem
            calling this routine.    ObjectTypeName - Supplies the name of the type of the object being
            accessed.    ObjectName - Supplies the name of the object being accessed.    ContextHandle - Supplies the context handle to the object.  On return, the
            granted access is written to the AccessGranted field of this structure
            if this call succeeds.    SecurityDescriptor - A pointer to the Security Descriptor against which
            acccess is to be checked.    DesiredAccess - Supplies desired acccess mask.  This mask must have been
            previously mapped to contain no generic accesses.    GenericMapping - Supplies a pointer to the generic mapping associated
            with this object type.    ForSecurityLog - TRUE if the access check is for the security log.
            This is a special case that may require a privilege check.Return Value:    NT status mapped to Win32 errors.--*/
    {
        NTSTATUS   Status;
        RPC_STATUS RpcStatus;    UNICODE_STRING Subsystem;
        UNICODE_STRING ObjectType;
        UNICODE_STRING Object;    BOOLEAN         GenerateOnClose = FALSE;
        NTSTATUS        AccessStatus;
        ACCESS_MASK     GrantedAccess = 0;
        HANDLE          ClientToken = NULL;
        PRIVILEGE_SET   PrivilegeSet;
        ULONG           PrivilegeSetLength = sizeof(PRIVILEGE_SET);
        ULONG           privileges[1];
        GenericMapping = &LogFileObjectMapping;    RtlInitUnicodeString(&Subsystem, SubsystemName);
        RtlInitUnicodeString(&ObjectType, ObjectTypeName);
        RtlInitUnicodeString(&Object, ObjectName);    if ((RpcStatus = RpcImpersonateClient(NULL)) != RPC_S_OK) {        ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: Failed to impersonate "
                "client %08lx\n", RpcStatus));        return RpcStatus;
        }    //
        // Get a token handle for the client
        //
        Status = NtOpenThreadToken (NtCurrentThread(),
                                    TOKEN_QUERY,        // DesiredAccess
                                    TRUE,               // OpenAsSelf
                                    &ClientToken);    if (!NT_SUCCESS(Status)) {        ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: NtOpenThreadToken Failed: "
                             "0x%lx\n",Status));
            goto CleanExit;
        }    //
        // We want to see if we can get the desired access, and if we do
        // then we also want all our other accesses granted.
        // MAXIMUM_ALLOWED gives us this.
        //
        DesiredAccess |= MAXIMUM_ALLOWED;    //
        // Bug #57153 -- Make sure that the current user has the right to manage
        // the security log.  Without this check, the Eventlog will allow all
        // administrators to manage the log, even if they don't have the access
        //
        if (ForSecurityLog) {
            DesiredAccess |= ACCESS_SYSTEM_SECURITY;
        }    Status = NtAccessCheck(SecurityDescriptor,
                               ClientToken,
                               DesiredAccess,
                               GenericMapping,
                               &PrivilegeSet,
                               &PrivilegeSetLength,
                               &GrantedAccess,
                               &AccessStatus);    if (! NT_SUCCESS(Status)) {        ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: Error calling "
                             "NtAccessCheck %08lx\n",
                         Status));        goto CleanExit;
        }    if (AccessStatus != STATUS_SUCCESS) {        ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: Access status is %08lx\n",
                         AccessStatus));        //
      

  15.   

    // MarkBl 1/30/95 : Modified this code a bit to give backup operators
            //                  the ability to open the security log for purposes
            //                  of backup.
            //        if ((AccessStatus == STATUS_ACCESS_DENIED) && (ForSecurityLog)) {            //
                // MarkBl 1/30/95 :  First, evalutate the existing code (performed
                //                   for read or clear access), since its
                //                   privilege check is more rigorous than mine.
                //            Status = STATUS_ACCESS_DENIED;            if (!(DesiredAccess & ELF_LOGFILE_WRITE)) {                //
                    // If read or clear access to the security log is desired,
                    // then we will see if this user passes the privilege check.
                    //
                    //
                    // Do Privilege Check for SeSecurityPrivilege
                    // (SE_SECURITY_NAME).
                    //
                    // MarkBl 1/30/95 : Modified code to fall through on error
                    //                  instead of the jump to 'CleanExit'.
                    //                Status = ElfpTestClientPrivilege(SE_SECURITY_PRIVILEGE,
                                                     ClientToken);                if (NT_SUCCESS(Status)) {                    GrantedAccess |= (ELF_LOGFILE_READ |
                                          ELF_LOGFILE_CLEAR);
                    }
                    else {                    ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: "
                                         "ElfpTestClientPrivilege failed %x\n",
                                     Status));
                    }
                }            //
                // MarkBl 1/30/95 : Finally, my code. If this user has backup
                //                  privilege, let the open succeed.
                //            if (!NT_SUCCESS(Status)) {                Status = ElfpTestClientPrivilege(SE_BACKUP_PRIVILEGE,
                                                     ClientToken);                if (NT_SUCCESS(Status)) {                    GrantedAccess |= ELF_LOGFILE_BACKUP;
                    }
                    else {
                        goto CleanExit;
                    }
                }
            }
            else {
                Status = AccessStatus;
            }
        }
        //
        // Revert to Self
        //
        if ((RpcStatus = RpcRevertToSelf()) != RPC_S_OK) {        ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: Fail to revert to "
                "self %08lx\n", RpcStatus));
            //
            // We don't return the error status here because we don't want
            // to write over the other status that is being returned.
            //    }    //
        // Get SeAuditPrivilege so I can call NtOpenObjectAuditAlarm.
        // If any of this stuff fails, I don't want the status to overwrite the
        // status that I got back from the access and privilege checks.
        //    privileges[0] = SE_AUDIT_PRIVILEGE;
        AccessStatus  = ElfpGetPrivilege(1, privileges);    if (!NT_SUCCESS(AccessStatus)) {        ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: ElfpGetPrivilege "
                             "(Enable) failed.  Status is 0x%x\n",
                         AccessStatus));
        }    //
        // Call the Audit Alarm function.
        //    AccessStatus = NtOpenObjectAuditAlarm (
                            &Subsystem,
                            (PVOID)ContextHandle,
                            &ObjectType,
                            &Object,
                            SecurityDescriptor,
                            ClientToken,            // Handle ClientToken
                            DesiredAccess,
                            GrantedAccess,
                            &PrivilegeSet,          // PPRIVLEGE_SET
                            FALSE,                  // BOOLEAN ObjectCreation,
                            TRUE,                   // BOOLEAN AccessGranted,
                            &GenerateOnClose);    if (!NT_SUCCESS(AccessStatus)) {
            ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: NtOpenObjectAuditAlarm "
                             "failed. status is 0x%lx\n",
                         AccessStatus));
        }
        else {        if (GenerateOnClose) {
                ContextHandle->Flags |= ELF_LOG_HANDLE_GENERATE_ON_CLOSE;
            }
        }    //
        // Update the GrantedAccess in the context handle.
        //
        ContextHandle->GrantedAccess = GrantedAccess;    NtClose(ClientToken);    ElfpReleasePrivilege();    return(Status);CleanExit:    //
        // Revert to Self
        //
        if ((RpcStatus = RpcRevertToSelf()) != RPC_S_OK) {        ElfDbgPrint(("[ELF] ElfpAccessCheckAndAudit: Fail to revert to "
                             "self %08lx\n",
                         RpcStatus));
            //
            // We don't return the error status here because we don't want
            // to write over the other status that is being returned.
            //
        }    if (ClientToken != NULL) {
            NtClose(ClientToken);
        }    return(Status);
    }
      

  16.   

    Install symbols for system DLLs, step into assembly code to figure out where it failed.
    sevencat(七猫): Please do not post Microsoft source code.
      

  17.   

    to:FengYuanMSFT(袁峰 http://spaces.msn.com/fengyuancom/)
    谢谢,以后我会注意的。