Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/svn/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在缓冲区内分离数据时出现问题(WinAPI)_C++_C_Winapi_Buffer - Fatal编程技术网

C++ 在缓冲区内分离数据时出现问题(WinAPI)

C++ 在缓冲区内分离数据时出现问题(WinAPI),c++,c,winapi,buffer,C++,C,Winapi,Buffer,我在网上找到了这段代码,它承诺将加载到缓冲区中的数据分开,我需要它,这样我就可以在屏幕上单独显示每个.bmp图像 BOOL OpenBmpFile(char* filePath, char* fileName, int* offset, HWND hwnd) { OPENFILENAME ofn; char szFileName[256]; char szFilePath[256]; BOOL FileOK;

我在网上找到了这段代码,它承诺将加载到缓冲区中的数据分开,我需要它,这样我就可以在屏幕上单独显示每个.bmp图像

BOOL OpenBmpFile(char* filePath, char* fileName, int* offset, HWND hwnd)
{
    OPENFILENAME ofn;            
    char szFileName[256];    
    char szFilePath[256];
    BOOL FileOK;         

    memset(&ofn, 0, sizeof(ofn));
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = TEXT("Bitmap Files (*.bmp)\0*.bmp\0\0");
    ofn.nFilterIndex = 1;
    strcpy(szFilePath, "*.bmp");
    ofn.lpstrFile = (LPWSTR)szFilePath;
    //
    // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
    // use the contents of szFile to initialize itself.
    //
    ofn.lpstrFile[0] = '\0';
    ofn.nMaxFile = sizeof(szFilePath);
    ofn.lpstrFileTitle = (LPWSTR)szFileName;
    ofn.nMaxFileTitle = sizeof(szFileName);
    ofn.lpstrTitle = TEXT("Open BMP File");
    ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_ALLOWMULTISELECT | OFN_EXPLORER;


    // show the common dialog "Open BMP File"
    FileOK = GetOpenFileName(&ofn);

    // if cancel, exit
    if (!FileOK)
        return FALSE;

    // else store the selected filename
    strcpy(fileName, szFileName);
    //I use this because strcpy stops after the first NULL
    memcpy(filePath, szFilePath, sizeof(szFilePath));
    *offset = ofn.nFileOffset;

    if(szFilePath[ofn.nFileOffset-1] != '\0')
    {
    MessageBox(hwnd,L"Single Selection",L"Open Debug 1",MB_OK);
    }
    else
    {
    MessageBox(hwnd,L"Multiple Selection",L"Open Debug 2",MB_OK);
    }

    return TRUE;
}
但是,每次使用以下行调用此函数时,都会导致错误:

OpenBmpFile((char*)file, (char*)file2, pTest, hWnd);
错误:pTest是空ptr


我想我的问题是,如何有效地使用此功能来显示我的图像

nFileOffset
是从
lpstrFile
开头到文件名的偏移量:

如果
lpstrFile
指向以下字符串
“c:\dir1\dir2\file.ext”
,则此成员包含值13,以指示
“file.ext”
字符串的偏移量。如果用户选择多个文件,
nFileOffset
是第一个文件名的偏移量

据此,
szFilePath[ofn.nFileOffset-1]
将指向
\
lpStrFile
定义为:

…如果设置了OFN_ALLOWMULTISELECT标志且用户选择了多个文件,则缓冲区包含当前目录,后跟所选文件的文件名。对于资源管理器样式的对话框,目录和文件名字符串是空分隔的,最后一个文件名后面有一个额外的空字符

因此,要确定用户是否选择了多个文件,请转到
lpstrFile
的末尾(即第一个空值),然后检查后面是否有另一个空值,如果没有,则用户选择了多个文件


要构造每个文件的完整路径和文件名,请重复使用零件直至
nFileOffset
,并连接每个文件名。返回时,使用调试器检查ofn的所有详细信息。

Microsoft建议使用更现代的(自Windows Vista以来可用)而不是
GetOpenFileName()。

使用此API,您无需拆分文件名缓冲区,也无需在提供的缓冲区太小时处理错误条件(这将要求您使用更大的缓冲区再次调用API)。在您的代码中,缓冲区(szFilePath)对于多个选择结果来说太小了,因此如果用户选择了许多文件,您很快就会遇到这种错误情况

我将首先提供一个简短的示例,仅显示用于多个选择的API调用序列

简短示例(向下滚动查看完整代码) 为简洁起见,以下代码根本没有错误处理!您应该检查每个COM API调用的HRESULT是否失败,我将在后面的完整示例中显示

// Prepare the file open dialog.
CComPtr<IFileOpenDialog> dlg;
dlg.CoCreateInstance( CLSID_FileOpenDialog );

dlg->SetOptions( fos | FOS_ALLOWMULTISELECT );

// Show the file open dialog.
dlg->Show( hwndOwner );
if( hr == S_OK ) // If user clicked OK button...
{
    CComPtr<IShellItemArray> items;
    dlg->GetResults( &items );

    DWORD numItems = 0;
    items->GetCount( &numItems );

    // Loop over all files selected by the user.
    for( DWORD i = 0; i < numItems; ++i )
    {
        CComPtr<IShellItem> item;
        items->GetItemAt( i, &item );

        CComHeapPtr<WCHAR> path;
        item->GetDisplayName( SIGDN_FILESYSPATH, &path );

        std::wcout << std::wstring( path ) << std::endl;
    }
}
如何调用此代码并处理异常:

#include <iostream>

int main()
{
    ::CoInitialize(0);  // call once at application startup

    try 
    {
        HWND hwnd = nullptr;  // In a GUI app, specify handle of parent window instead.
        auto paths = ShowFileOpenDialog( hwnd, {{ L"Bitmap Files (*.bmp)", L"*.bmp" }},
                                         FOS_ALLOWMULTISELECT );
        if( paths.empty() )
        {
            // Cancel button clicked.
            std::cout << "No file(s) selected.\n";
        }
        else
        {
            // OK button clicked.
            for( const auto& path : paths )
                std::wcout << path << L"\n";
        }
    }
    catch( std::system_error& e )
    {
        std::cout 
            << "Could not show 'file open dialog'."
            << "\n\nCause: " << e.what()
            << "\nError code: " << e.code() << "\n";
    }

    ::CoUninitialize();  // match call of ::CoInitialize()
    return 0;
}
#包括
int main()
{
::CoInitialize(0);//在应用程序启动时调用一次
尝试
{
HWND HWND=nullptr;//在GUI应用程序中,指定父窗口的句柄。
自动路径=ShowFileOpenDialog(hwnd,{L“位图文件(*.bmp)”,L“*.bmp”},
FOS_ALLOWMULTISELECT);
if(path.empty())
{
//单击“取消”按钮。

std::cout您犯的最大错误是将ANSI和Unicode混合在一起。您使用的是
char[]
buffers并将它们强制转换为
LPWSTR
指针,以便将它们分配给
OPENFILENAME
字段。由于您使用的是API的
TCHAR
版本,这意味着您的项目是针对Unicode而不是ANSI编译的。因此API需要Unicode缓冲区,并将输出Unicode字符串。Which还意味着您要告诉API,两倍于缓冲区分配空间的空间可用于接收字符,因为您正在将
ofn.nMaxFile
ofn.nMaxFileTitle
字段设置为字节计数而不是字符计数。因此,您可能会导致缓冲区溢出

您不能仅将8位缓冲区类型转换为16位数据类型。您必须首先为缓冲区使用正确的数据类型,并取消类型转换。在这种情况下,这意味着使用
WCHAR
/
WCHAR\u t
(或至少
TCHAR
)缓冲区而不是
char
buffers。但是,由于在函数参数中使用
char
,因此应该使用ANSI版本的API,而不是
TCHAR
/Unicode版本

选择多个文件时,尤其是文件名较长的文件,生成的字符数据很容易超出固定长度缓冲区的大小。如下所示:

lpstrFile
类型:LPTSTR

用于初始化文件名编辑控件的文件名。如果不需要初始化,则此缓冲区的第一个字符必须为空。当
GetOpenFileName
GetSaveFileName
函数成功返回时,此缓冲区包含所选文件的驱动器标识符、路径、文件名和扩展名

如果设置了OFN_ALLOWMULTISELECT
标志,并且用户选择了多个文件,则缓冲区包含当前目录,后跟所选文件的文件名。对于资源管理器样式对话框,目录和文件名字符串是空分隔的,最后一个文件名后面有一个额外的空字符。对于旧样式对话框框中,字符串以空格分隔,函数使用短文件名作为带空格的文件名。您可以使用
FindFirstFile
函数在长文件名和短文件名之间进行转换。如果用户仅选择一个文件,则
lpstrFile
字符串在路径和文件名之间没有分隔符

如果缓冲区太小,函数返回
FALSE
,而
CommDlgExtendedError
函数返回
FNERR\u BUFFERTOOSMALL
。在这种情况下,
lpstrFile
缓冲区的前两个字节包含所需大小,以字节或字符为单位

nMaxFile
类型:德沃德<
#include <iostream>

int main()
{
    ::CoInitialize(0);  // call once at application startup

    try 
    {
        HWND hwnd = nullptr;  // In a GUI app, specify handle of parent window instead.
        auto paths = ShowFileOpenDialog( hwnd, {{ L"Bitmap Files (*.bmp)", L"*.bmp" }},
                                         FOS_ALLOWMULTISELECT );
        if( paths.empty() )
        {
            // Cancel button clicked.
            std::cout << "No file(s) selected.\n";
        }
        else
        {
            // OK button clicked.
            for( const auto& path : paths )
                std::wcout << path << L"\n";
        }
    }
    catch( std::system_error& e )
    {
        std::cout 
            << "Could not show 'file open dialog'."
            << "\n\nCause: " << e.what()
            << "\nError code: " << e.code() << "\n";
    }

    ::CoUninitialize();  // match call of ::CoInitialize()
    return 0;
}
BOOL OpenBmpFiles(char **filePath, char** fileNames, HWND hwnd)
{
    *filePath = NULL;
    *fileNames = NULL;

    size_t iMaxFileSize = MAX_PATH;
    char *lpFileBuffer = (char*) malloc(iMaxFileSize);
    if (!lpFileBuffer)
        return FALSE;

    char szFileTitle[MAX_PATH];
    BOOL bResult = FALSE;

    OPENFILENAMEA ofn;            
    memset(&ofn, 0, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = "Bitmap Files (*.bmp)\0*.bmp\0\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = lpFileBuffer;
    ofn.nMaxFile = iMaxFileSize;
    ofn.lpstrFileTitle = szFileTitle;
    ofn.nMaxFileTitle = MAX_PATH;
    ofn.lpstrTitle = "Open BMP File";
    ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_ALLOWMULTISELECT | OFN_EXPLORER;

    do
    {
        //
        // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
        // use the contents of lpstrFile to initialize itself.
        //
        ofn.lpstrFile[0] = '\0';

        // show the common dialog "Open BMP File"
        if (GetOpenFileNameA(&ofn))
            break;

        // if cancel, exit           
        if (CommDlgExtendedError() != FNERR_BUFFERTOOSMALL)
            goto cleanup;

        // reallocate the buffer and try again
        iMaxFileSize = * (WORD*) lpFileBuffer;
        char *lpNewFileBuffer = (char*) realloc(lpFileBuffer, iMaxFileSize);
        if (!lpNewFileBuffer)
            goto cleanup;

        lpFileBuffer = lpNewFileBuffer;

        ofn.lpstrFile = lpFileBuffer;
        ofn.nMaxFile = iMaxFileSize;
    }
    while (true);

    if (lpFileBuffer[ofn.nFileOffset-1] != '\0')
    {
        MessageBox(hwnd, TEXT("Single Selection"), TEXT("Open Debug 1"), MB_OK);

        // copy the single filename and make sure it is double-null terminated

        size_t len = strlen(&lpFileBuffer[ofn.nFileOffset]) + 2;

        *fileNames = (char*) malloc(len);
        if (!*fileNames)
            goto cleanup;

        strncpy(*fileNames, &lpFileBuffer[ofn.nFileOffset], len);

        // copy the directory path and make sure it is null terminated

        lpFileBuffer[ofn.nFileOffset] = '\0';

        *filePath = strdup(lpFileBuffer);
        if (!*filePath)
        {
            free(*fileNames);
            *fileNames = NULL;
            goto cleanup;
        }
    }
    else
    {
        MessageBox(hwnd, TEXT("Multiple Selection"), TEXT("Open Debug 2"), MB_OK);

        // copy the directory path, it is already null terminated

        *filePath = strdup(lpFileBuffer);
        if (!*filePath)
            goto cleanup;

        // copy the multiple filenames, they are already double-null terminated

        size_t len = (ofn.nMaxFile - ofn.nFileOffset);

        *fileNames = (char*) malloc(len);
        if (!*fileNames)
        {
            free(*filePath);
            *filePath = NULL;
            goto cleanup;
        }

        // have to use memcpy() since the filenames are null-separated
        memcpy(*fileNames, &lpFileBuffer[ofn.nFileOffset], len);
    }

    bResult = TRUE;

cleanup:
    free(lpFileBuffer);
    return bResult;
}
char *path, *filenames;
if (OpenBmpFiles(&path, &filenames, hwnd))
{
    char *filename = filenames;
    do
    {
        // use path + filename as needed...
        /*
        char *fullpath = (char*) malloc(strlen(path)+strlen(filename)+1);
        PathCombineA(fullpath, path, filename);
        doSomethingWith(fullpath);
        free(fullpath);
        */

        filename += (strlen(filename) + 1);
    }
    while (*filename != '\0');

    free(path);
    free(filenames);
}
BOOL OpenBmpFiles(char** fileNames, HWND hwnd)
{
    *fileNames = NULL;

    size_t iMaxFileSize = MAX_PATH;
    char *lpFileBuffer = (char*) malloc(iMaxFileSize);
    if (!lpFileBuffer)
        return FALSE;

    char szFileTitle[MAX_PATH];
    BOOL bResult = FALSE;

    OPENFILENAMEA ofn;            
    memset(&ofn, 0, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = "Bitmap Files (*.bmp)\0*.bmp\0\0";
    ofn.nFilterIndex = 1;
    ofn.lpstrFile = lpFileBuffer;
    ofn.nMaxFile = iMaxFileSize;
    ofn.lpstrFileTitle = szFileTitle;
    ofn.nMaxFileTitle = MAX_PATH;
    ofn.lpstrTitle = "Open BMP File";
    ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_ALLOWMULTISELECT | OFN_EXPLORER;

    do
    {
        //
        // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
        // use the contents of lpstrFile to initialize itself.
        //
        ofn.lpstrFile[0] = '\0';

        // show the common dialog "Open BMP File"
        if (GetOpenFileNameA(&ofn))
            break;

        // if cancel, exit           
        if (CommDlgExtendedError() != FNERR_BUFFERTOOSMALL)
            goto cleanup;

        // reallocate the buffer and try again
        iMaxFileSize = * (WORD*) lpFileBuffer;
        char *lpNewFileBuffer = (char*) realloc(lpFileBuffer, iMaxFileSize);
        if (!lpNewFileBuffer)
            goto cleanup;

        lpFileBuffer = lpNewFileBuffer;

        ofn.lpstrFile = lpFileBuffer;
        ofn.nMaxFile = iMaxFileSize;
    }
    while (true);

    if (lpFileBuffer[ofn.nFileOffset-1] != '\0')
    {
        MessageBox(hwnd, TEXT("Single Selection"), TEXT("Open Debug 1"), MB_OK);

        // copy the single filename and make sure it is double-null terminated

        size_t len = strlen(lpFileBuffer) + 2;

        *fileNames = (char*) malloc(len);
        if (!*fileNames)
            goto cleanup;

        strncpy(*fileNames, lpFileBuffer, len);
    }
    else
    {
        MessageBox(hwnd, TEXT("Multiple Selection"), TEXT("Open Debug 2"), MB_OK);

        // calculate the output buffer size

        char *path = lpFileBuffer;
        size_t pathLen = strlen(path);
        bool slashNeeded = ((path[pathLen-1] != '\\') && (path[pathLen-1] != '/'));
        size_t len = 1;

        char *filename = &lpFileBuffer[ofn.nFileOffset];
        while (*filename != '\0')
        {
            int filenameLen = strlen(filename);
            len += (pathLen + filenameLen + 1);
            if (slashNeeded) ++len;
            filename += (filenameLen + 1);
        }

        // copy the filenames and make sure they are double-null terminated

        *fileNames = (char*) malloc(len);
        if (!*fileNames)
            goto cleanup;

        char *out = *fileNames;

        filename = &lpFileBuffer[ofn.nFileOffset];
        while (*filename != '\0')
        {
            strncpy(out, path, pathLen);
            out += pathLen;
            if (slashNeeded) *out++ = '\\';

            int filenameLen = strlen(filename);
            strncpy(out, filename, filenameLen);
            out += filenameLen;
            *out++ = '\0';

            filename += (filenameLen + 1);
        }

        *out = '\0';
    }

    bResult = TRUE;

cleanup:
    free(lpFileBuffer);
    return bResult;
}
char *filenames;
if (OpenBmpFiles(&filenames, hwnd))
{
    char *filename = filenames;
    do
    {
        // use filename as needed...
        /*
        doSomethingWith(filename);
        */

        filename += (strlen(filename) + 1);
    }
    while (*filename != '\0');

    free(filenames);
}