본문 바로가기
Study/Driver

Driver Unload할때~

by 뿡뿡대마왕 2011. 9. 28.
반응형
드라이버를 unload 하고 재시작시 CreateService에서 정말 아주 가끔씩  ERROR_SERVICE_MARKED_FOR_DELETE 에러를

내뱉으며 드라이버 설치되지 않을 때가 있었다...;;

재현하기 힘든 상태라서 원인을 파악하기엔 어려움이 있었지만...드라이버 언로시에 관련된 함수들을 지우거나 강제로

실패하게 만들어 재현 상태를 가상적으로나마 만들어 봤었다..

문제는 ControlService()함수가 문제였는데..

언로드시 함수 호출 루틴은 다음과 같다.

 OpenSCManager -> OpenServiceA -> ControlService -> DeleteService ....

여기서 ControlService 함수에서 서비스 중지 명령을 날린 후 DeleteService 를 호출하는데 ControlService 함수의 실패에 대한

예외처리 없이 바로 DeleteService를 호출하게 됨에 따라 ControlService의 stop명령이 실패됬음에도 불구하고 DeleteService

를 호출하여 다시 드라이버를 로드할 때 CreateService에서 ERROR_SERVICE_MARKED_FOR_DELETE 에러가 발생 한 것이

었다.

이 ControlService 함수의 실패가 아주 가끔 발생했기에 문제가 잘보이지 않다가 실패나면 그런 문제가 발생했나 보다..-_-;;
그래서 이래저래 자료를 찾아보니 마소사이트에서 드라이버 언로드의 해제 소스가 깔끔하게 있는것이 아닌가!?(-_-;)
암튼..그 소스를 긁어왔다.

void CRemoveServiceDlg::OnRemoveService() 
{
	// TODO: Add your control notification handler code here
	SERVICE_STATUS          ssStatus;       // current status of the service
  SC_HANDLE   schService;
  SC_HANDLE   schSCManager;
	TCHAR                   szErr[256];

schSCManager = OpenSCManager(
                        NULL,                   // machine (NULL == local)
                        NULL,                   // database (NULL == default)
                        SC_MANAGER_ALL_ACCESS   // access required
                        );
    if ( schSCManager )
    {
        schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);

        if (schService)
        {
            // try to stop the service
            if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
            {
                _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
                Sleep( 1000 );

                while( QueryServiceStatus( schService, &ssStatus ) )
                {
                    if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
                    {
                        _tprintf(TEXT("."));
                        Sleep( 1000 );
                    }
                    else
                        break;
                }

                if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
                    _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
                else
                    _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );

            }
            // now remove the service
            if( DeleteService(schService) )
                _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
            else
                _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));

            CloseServiceHandle(schService);
        }
        else
            _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
        CloseServiceHandle(schSCManager);
   }
    else
        _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
}


LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
{
    DWORD dwRet;
    LPTSTR lpszTemp = NULL;

    dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
                           NULL,
                           GetLastError(),
                           LANG_NEUTRAL,
                           (LPTSTR)&lpszTemp,
                           0,
                           NULL );

    // supplied buffer is not long enough
    if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
        lpszBuf[0] = TEXT('\0');
    else
    {
        lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0');  //remove cr and newline character
        _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
    }

    if ( lpszTemp )
        LocalFree((HLOCAL) lpszTemp );

    return lpszBuf;
}

while문에서 QueryServiceStatus 요 함수로 계속 상태를 보면서 서비스를 stop시키고 DeleteService 를 수행한다.

정말 나이스구만!

반응형

댓글