DeskBand가 실현한 문제

4519 단어
DeskBand를 하는 과정에서 몇 가지 문제에 부딪혔다. 이런 문제들은 크면 크고 작으면 작지만 두세 번 하면 해결되는 것이 아니라 그래도 시간이 좀 걸렸다.

1. explorer를 초래할 수 있습니다.끊다

이유:
이 문제가 발생한 것은 현재 DeskBand의 DLL 참조 수가 정확하지 않기 때문입니다.시스템은 현재 DLL이 시스템에서 제거될 수 있는지 확인하기 위해 일정 시간마다 DllCanUnloadNow 함수를 호출합니다.시스템은 약 15분마다 DllCanUnloadNow 함수가 S 로 되돌아올 때 검사합니다OK 시 시스템은 이 DLL을 프로세스 주소 공간에서 마운트 해제합니다. 그러면 DLL의DeskBand Window 메시지 처리 함수가 실행 중입니다. 그러나 DLL이 프로세스에서 제거되면 메시지 처리 함수의 호출이 실패하고 explorer가 발생합니다.exe 끊어.
솔루션:
1) ClassFactory 객체를 만들 때 DLL에 대한 참조 개수 glDllRefCount(전역 변수)에 1을 더하면 대상이 풀릴 때 glDllRefCount 감소 1
2)Band Object 개체를 만들 때도 이 인용 계수에 1을 더하고 놓을 때 1을 줄여야 한다. Band Object만 존재한다면 이 DLL은 반드시 존재해야 하기 때문에 Band Object가 놓으면 이 DLL은 방출될 수 있다.
 

2. 코드로 DeskBand를 표시하고 삭제하면 질문 대화상자가 팝업됩니다

이것은 프로그램을 통해 COM 대상이 작업 표시줄에 표시되는 것을 제어하기 때문이다. 마이크로소프트는 안전성에 대한 고려를 바탕으로 사용자에게 이 Band 대상을 표시하는지 물어보는 대화 상자를 팝업하기 때문이다. 그러면 일부 광고 프로그램이 작업 표시줄에 엉뚱하게 나타나지 않도록 하는 장점이 있다.
이 대화상자를 어떻게 없애요?
갈고리를 이용하면: SetWindowsHookEx(WH CALLWNDPROCRET, (HOKPROC)HookCallWndProcRet, hCurInst, 0);
문제는 이 갈고리를 등록하는 것입니다. 프로그램이 Band를 표시하거나 숨길 때 이 갈고리를 등록해야 합니다. 따라서 일반적인 상황에서 이 DLL은 Band를 표시하거나 숨길 수 있는 내보내기 방법을 쓸 수 있습니다.
HINSTANCE의 코드는 다음과 같습니다.
HMODULE WINAPI SdkDeskBandHook::GetCurrentModuleHandle()
{
    // s_somevar must be static variable, otherwise 
    // the returned HMODULE is not correct
    // instance of current dll.
    static int s_somevar = 0;
    MEMORY_BASIC_INFORMATION mbi;
    if(!::VirtualQuery(&s_somevar, &mbi, sizeof(mbi)))
    {
        return NULL;
    }

    return static_cast<HMODULE>(mbi.AllocationBase);
}

BOOL WINAPI SdkCommonHelper::ShowDeskBand(BOOL fShowOrHide)
{
    ITrayDeskBand *pTrayDeskBand = NULL;
    HRESULT hr = CoCreateInstance(CLSID_TrayDeskBand, NULL, CLSCTX_ALL,
                              IID_PPV_ARGS(&pTrayDeskBand));
    // Vista and higher operating system
    if ( SUCCEEDED(hr) )
    {
        if ( TRUE == fShowOrHide )
        {
            hr = pTrayDeskBand->DeskBandRegistrationChanged();
            if ( SUCCEEDED(hr) )
            {
                // If window hook is not started, starts it.
                if ( FALSE == CSdkDeskBandHook::IsHookStart() )
                {
                    CSdkDeskBandHook::StartHook();
                }
            hr = pTrayDeskBand->IsDeskBandShown(CLSID_SampleDeskBand);
                if ( SUCCEEDED(hr) && (S_FALSE == hr) )
                {
                    hr = pTrayDeskBand->ShowDeskBand(CLSID_SampleDeskBand);
                }
            }
        }
        else
        {
            hr = pTrayDeskBand->IsDeskBandShown(CLSID_SampleDeskBand);
            if ( SUCCEEDED(hr) && (S_OK == hr) )
            {
                hr = pTrayDeskBand->HideDeskBand(CLSID_SampleDeskBand);
            }
        }
    }

    SAFE_RELEASE(pTrayDeskBand);
    return (SUCCEEDED(hr)) ? TRUE : FALSE;
}

갈고리를 이용해 창문을 갈고리로 하는 WMINITDIALOG 메시지, 대화상자 창에 있는 YES 단추를 찾아서 BN 보내기CLICKED 메시지어차피 아날로그 클릭 사건이야.갈고리의 처리 함수에 다음과 같은 코드를 넣는다.
// Find [Yes] button on the dialog box for prompting 
// user allow desk band show in task bar.
LPCWPRETSTRUCT lpMsg = (LPCWPRETSTRUCT)lParam;
if ( (NULL != lpMsg) && (WM_INITDIALOG == lpMsg->message) )
{
    // Get caption of dialog box, which is same with the 
    // name of sub menu item of toolbar.
    WCHAR szCaption[100] = { 0 };
    GetWindowText(lpMsg->hwnd, szCaption, 100);
    // Get tool bar menu item name from registry, 
    // because the caption of dialog box is same
    // with the tool bar menu item.
    wstring strMenuName = GetToolbarMenuNameFromRegistry();
    if ( (0 == CommonHelper::OrdinalIgnoreCaseCompareStrings(
        szCaption, strMenuName.c_str()))
    || (0 == CommonHelper::OrdinalIgnoreCaseCompareStrings(
        szCaption, L"explorer.exe")) )
    {
        HWND destHwnd = FindWindowEx(lpMsg->hwnd, NULL,
             L"DirectUIHWND", NULL);
        if ( destHwnd != NULL )
        {
            HWND sink = FindWindowEx(destHwnd, NULL ,
                 L"CtrlNotifySink", NULL);
            int i = 0;
            while ( i++ < 6 )
            {
                sink = FindWindowEx(destHwnd, sink, L"CtrlNotifySink", NULL);
            }

        HWND button = FindWindowEx(sink, NULL, L"Button", NULL);
            SendMessage(sink, WM_COMMAND, BN_CLICKED, (LPARAM)button);
        }
    }
}

좋은 웹페이지 즐겨찾기