从 Plain C 访问通用项目对话框

问题描述 投票:0回答:1

这是我第一次尝试任何类型的 COM。我正在尝试在文件夹模式下启动“打开文件”对话框。代码可以编译,但应用程序无法启动,并且出现“无法在动态链接库中找到序号”错误。谁能查明是什么原因造成的?任何帮助将不胜感激。注意:该代码基于我对 MSDN 示例和文档的解释。现在我知道它不会做任何事情,我只是想让它显示对话框。

谢谢!

HRESULT OpenDirectory()
{
    //Initialize the COM library
    COINIT Init = COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE;
    CoInitialize(NULL);

    //CoCreate Folder Open Dialog Object
    IFileDialog *pfd = NULL;
    CLSID OpenFileID = CLSID_FileOpenDialog;
    IID IFileDialog = IID_IFileDialog;
    HRESULT hr = CoCreateInstance(&OpenFileID, NULL, CLSCTX_INPROC_SERVER, &IFileDialog, (void**) ( &pfd));
    


    if (SUCCEEDED(hr))
    {
        IFileDialogEvents *pfde = NULL;
        hr = OpenDirEventHandler(&pfde);

        if (SUCCEEDED(hr))
        {
            //Hook the Event Handler
            DWORD dwHook;
            hr = pfd->lpVtbl->Advise(pfd, pfde, &dwHook);


            if (SUCCEEDED(hr))
            {
                //flags
                DWORD dwFlags;
                hr = pfd->lpVtbl->GetOptions(pfd, &dwFlags);

                if (SUCCEEDED(hr))
                {
                    hr = pfd->lpVtbl->SetOptions(pfd, dwFlags | FOS_FORCEFILESYSTEM | FOS_PICKFOLDERS);

                    if (SUCCEEDED(hr))
                    {
                        hr = pfd->lpVtbl->Show(pfd, NULL);

                        if (SUCCEEDED(hr))
                        {
                            IShellItem *psiResult;
                            
                            hr = pfd->lpVtbl->GetResult(pfd, &psiResult);

                            // We are just going to print out the 
                                          // name of the file for sample sake.
                            PWSTR pszFilePath = NULL;
                            hr = psiResult->lpVtbl->GetDisplayName(pfd, SIGDN_FILESYSPATH,
                                &pszFilePath);
                            
                            if (SUCCEEDED(hr))
                            {
                                TaskDialog(NULL,
                                    NULL,
                                    L"CommonFileDialogApp",
                                    pszFilePath,
                                    NULL,
                                    TDCBF_OK_BUTTON,
                                    TD_INFORMATION_ICON,
                                    NULL);
                                CoTaskMemFree(pszFilePath);
                            }
                            psiResult->lpVtbl->Release(psiResult);
                        }
                    }
                }

            }
            pfd->lpVtbl->Unadvise(pfd, dwHook);
        }
        pfde->lpVtbl->Release(pfde);
    }
    pfd->lpVtbl->Release(pfd);


    return 0;
}


HRESULT STDMETHODCALLTYPE FileOK(IFileDialog *pfd)
{
    return 0;
}

HRESULT STDMETHODCALLTYPE SelectionChange(IFileDialog *pfd)
{
    return 0;
}

HRESULT STDMETHODCALLTYPE DirOverwrite(IFileDialog *pfd)
{
    return 0;
}

 OpenDirEventHandler(IFileDialogEvents *pfde)
{
     pfde->lpVtbl->OnFileOk = &FileOK;
     pfde->lpVtbl->OnSelectionChange = &SelectionChange;
     pfde->lpVtbl->OnOverwrite = &DirOverwrite;
}

c com dialog
1个回答
0
投票

“Ordinal 无法位于动态链接库”错误是由于 TaskDialog 需要链接到公共控件 dll,您可以按照此处的说明进行修复 https://stackoverflow.com/a/4308532 /403671,即将这一行添加到您的代码中:

#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

或者使用

app.manifest
文件,如下所述:启用视觉样式

然后你必须完全实现一个暴露给世界的COM接口,你不能只实现你需要的方法,并且你必须正确初始化v表,例如,像这样:

IFileDialogEvents pfde;

// build the full v-table
pfde.lpVtbl = malloc(sizeof(IFileDialogEventsVtbl)); // make sure you free sometimes in the future
pfde.lpVtbl->AddRef = &OnAddRefOrRelease;
pfde.lpVtbl->Release = &OnAddRefOrRelease;
pfde.lpVtbl->QueryInterface = &OnQueryInterface;
pfde.lpVtbl->OnFolderChange = &OnFolderChange;
pfde.lpVtbl->OnFolderChanging = &OnFolderChanging;
pfde.lpVtbl->OnSelectionChange = &OnSelectionChange;
pfde.lpVtbl->OnOverwrite = &OnOverwrite;
pfde.lpVtbl->OnFileOk = &OnFileOk;
pfde.lpVtbl->OnTypeChange = &OnTypeChange;
pfde.lpVtbl->OnShareViolation = &OnShareViolation;

// hook the Event Handler
DWORD dwHook;
hr = pfd->lpVtbl->Advise(pfd, &pfde, &dwHook);

现在,对于每个方法,您必须声明接口定义中声明的所有参数,包括作为第一个参数的“this”指针,如下所示:

HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialogEvents* this, IFileDialog* pfd, IShellItem* psiFolder)
{
    return S_OK;
}

HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialogEvents* this, IFileDialog* pfd)
{
    return S_OK;
}

HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialogEvents* this, IFileDialog* pfd, FDE_SHAREVIOLATION_RESPONSE* pResponse)
{
    return S_OK;
}

HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialogEvents* this, IFileDialog* pfd)
{
    return S_OK;
}

HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialogEvents* this, IFileDialog* pfd)
{
    return S_OK;
}

HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialogEvents* this, IFileDialog* pfd)
{
    return S_OK;
}

HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialogEvents* this, IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse)
{
    return S_OK;
}

ULONG STDMETHODCALLTYPE OnQueryInterface(IFileDialogEvents* this, REFIID riid, void** ppvObject)
{
    if (riid == &IID_IFileDialogEvents)
    {
        *ppvObject = this;
        return S_OK;
    }
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE OnAddRefOrRelease(IFileDialogEvents* this)
{
    // this is a hack, ok for sample, implement it properly
    return 1;
}

然后,GetDisplayName 中存在一个错误,您必须始终传递“this”(此处为

psiResult
)作为第一个参数:

hr = psiResult->lpVtbl->GetDisplayName(psiResult, SIGDN_FILESYSPATH, &pszFilePath);
© www.soinside.com 2019 - 2024. All rights reserved.