【问题标题】:MSVC ignores throw statementMSVC 忽略 throw 语句
【发布时间】:2021-11-15 17:08:15
【问题描述】:

目前我正在尝试测试 IAutoComplete COM 接口,这需要我使用 MSVC cpp 编译器。我面临着一个我在 MingGW 从未遇到过的问题。 MSVC 看到我的 throw 语句并完全忽略它。所以不知道有没有我没设置的设置。

好吧,我投了反对票,因为我举了一个不好的例子,这可能是我应得的。我认为它未能抛出,因为它在一个结构中,但尝试使用新的结构证明我错了。我可能无法提供可重现的示例,但我会尝试。

准备大量代码。

Jav/AutoObject.h

#ifndef JAV_WIN32_AUTO_OBJECT_HPP
#define JAV_WIN32_AUTO_OBJECT_HPP

#include <Jav/config.h>

namespace Jav
{

struct AutoObject
{
 virtual ~AutoObject(){}
 void* operator new(size_t sz);
};

AutoObject* shallowCopy(AutoObject*);
AutoObject* deleteObject(AutoObject*);

}

#endif // JAV_WIN32_AUTO_OBJECT_HPP

Jav/win32/widgets/widgets_ex.h

#ifndef JAV_WIN32_GUI_WIDGETS_EX_HPP
#define JAV_WIN32_GUI_WIDGETS_EX_HPP

#include <Jav/win32/widgets/widgets.h>


namespace Jav {  namespace win32 {

class Widget
{
 public:
    Widget(HWND widget=nullptr) : widget(widget){}
    operator HWND() { return widget; }

 public:
    void setId(int id) { SetWindowLong(widget,GWLP_ID,id); }
    void destroy()   { DestroyWindow(widget); widget = NULL; }
    void show()     { ShowWindow(widget,SW_SHOW); }
    void hide()     { ShowWindow(widget,SW_HIDE); }

 protected:
     HWND widget;
};

}}

#endif // JAV_WIN32_GUI_WIDGETS_EX_HPP

Jav/win32/window/Window.h

#include <Jav/win32/widgets/widgets_ex.h>
using Window = Widget;

Jav/win32/window/SimpleWindow.h

#ifndef JAV_WIN32_WINDOW_SIMPLE_WINDOW_HPP
#define JAV_WIN32_WINDOW_SIMPLE_WINDOW_HPP

#include <Jav/AutoObject.h>
#include <Jav/win32/window/Window.h>



namespace Jav  { namespace win32 {

struct Content__ : AutoObject
{
 virtual void onCreate(HWND,CREATESTRUCTA*) {}
 virtual void onDestroy() {}
 virtual void onSize(int w,int h) {}
 virtual void onDraw(Canvas&) {}
};

class SimpleWindow : public Window
{
 public:
    SimpleWindow(Content__*, const char *title, size_t w,size_t h,
                   int style=WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
                   int ex_style=0);

 public:
    bool isOpen();
    void close();
    const MSG& getMessage();
    const MSG& peekMessage();
    void dispatchMessage(const MSG&);

 private:
    static ATOM registerWindow();
    static LRESULT CALLBACK windowProc(HWND,UINT,WPARAM,LPARAM);
    static HWND createWindow(Content__*, const char *,HMENU, size_t,size_t, int,int);

 private:
    MSG msg;
};

}}

#endif // JAV_WIN32_WINDOW_SIMPLE_WINDOW_HPP

AutoObject.cpp

#include <Jav/AutoObject.h>
#include <unordered_map>
#include <objbase.h>


namespace {

struct AutoObjectsMap : std::unordered_map<Jav::AutoObject*,size_t>
{
 ~AutoObjectsMap() { for(auto &obj : *this) CoTaskMemFree(obj.first); }
};

AutoObjectsMap *alloc_objects_ptr;

struct AutoObjectsMapMgr
{
 ~AutoObjectsMapMgr() { delete alloc_objects_ptr; };
};

}

#define alloc_objects (*alloc_objects_ptr)

namespace Jav
{

void* AutoObject::operator new(size_t sz)
{
 auto mem = CoTaskMemAlloc(sz);
 if(!alloc_objects_ptr) alloc_objects_ptr = new AutoObjectsMap();
 alloc_objects[(AutoObject*)mem] = 1;
 return mem;
}

AutoObject* shallowCopy(AutoObject *r)
{
 auto elem = alloc_objects.find(r);
 if( elem != alloc_objects.end() ) ++alloc_objects[r];
 return r;
}

AutoObject* deleteObject(AutoObject *mem)
{
    auto elem = alloc_objects.find(mem);

    if( elem != alloc_objects.end() )
    {
        if(--elem->second == 0)
        {
         mem->~AutoObject();
         CoTaskMemFree(mem);
         alloc_objects.erase(elem);
         return nullptr;
        }
    }

    return mem;
}

}

SimpleWindow.cpp

#include <Jav/win32/window/SimpleWindow.h>


namespace Jav  { namespace win32 {

namespace {

LRESULT CALLBACK SimpleWindow::windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    Content__ *obj = (Content__*)GetWindowLongPtrA(hwnd,GWLP_USERDATA);

    auto getWidth  = [lParam](){ return LOWORD(lParam); };
    auto getHeight = [lParam](){ return HIWORD(lParam); };
    auto getX = [lParam](){ return LOWORD(lParam); };
    auto getY = [lParam](){ return HIWORD(lParam); };
    auto getWidget     = [lParam](){ return (HWND)lParam; };
    auto widgetId      = [wParam](){ return LOWORD(wParam); };
    auto widgetEvent   = [wParam](){ return HIWORD(wParam); };
    auto menuType      = [wParam](){ return LOWORD(wParam); };
    auto eventId       = [wParam](){ return LOWORD(wParam); };

    switch (uMsg)
    {
     case WM_CREATE:
        {
         CREATESTRUCT *cs = ((CREATESTRUCTA*)lParam);
         obj = (Content__*)cs->lpCreateParams;
         SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)obj);
         obj->onCreate(hwnd,cs);
         return 0;
        }

     case WM_DESTROY:
        obj->onDestroy();
        deleteObject(obj);
        return 0;

     case WM_SIZE:
        obj->onSize(getWidth(),getHeight());
        return 0;

     default: return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

ATOM SimpleWindow::registerWindow()
{
 WNDCLASSEX wincl = {};

 wincl.cbSize = sizeof(WNDCLASSEX);
 wincl.lpszClassName = "JavWin32WindowSimpleWindow";
 wincl.lpfnWndProc = SimpleWindow::windowProc;
 wincl.style = CS_HREDRAW|CS_VREDRAW;
 wincl.hIcon = LoadIcon(NULL,IDI_APPLICATION);;
 wincl.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
 wincl.hCursor = LoadCursor(NULL,IDC_ARROW);
 wincl.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
 wincl.cbWndExtra = WINDOW_WND_EXTRA_BYTES;

 return RegisterClassEx(&wincl);
}

SimpleWindow::SimpleWindow(Content__ *obj,const char *title, size_t w,size_t h, int style,int ex_style)
 : Window( createWindow(obj,title,NULL, w,h, style,ex_style) ),
   app_ctx(*this)
{
 msg.message = 0;
 show();
}

bool SimpleWindow::isOpen()
{
 return msg.message != WM_QUIT;
}

void SimpleWindow::close()
{
 DestroyWindow(*this);
}

const MSG& SimpleWindow::getMessage()
{
 GetMessageA(&msg,*this,0,0);
 return msg;
}

const MSG& SimpleWindow::peekMessage()
{
 PeekMessageA(&msg,*this,0,0,PM_REMOVE);
 return msg;
}

void SimpleWindow::dispatchMessage(const MSG &msg)
{
 TranslateMessage(&msg);
 DispatchMessage(&msg);
}

}}

main.cpp

#include <Jav/AutoObject.h>
#include <Jav/win32/window/SimpleWindow.h>


using namespace Jav::win32;

class Content : public Content__
{
    IAutoComplete *pac = NULL;
    IAutoComplete2 *pac2 = NULL;
    //IUnknown *punkSource;
    //ColumnList columnList;

 public:
    ~Content()
    {
        if(pac) pac->Release();
        if(pac2) pac2->Release();
    }

    void onCreate(HWND hwnd,CREATESTRUCTA*)override
    {
        throw; //doesn't throw or terminate
        HWND textBox; // pretend this is an edit control
        attachAutoCompleteObject(textBox); //doesn't throw either
    }

    void attachAutoCompleteObject(HWND hwnd)
    { 
        HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pac));
        if(FAILED(hr)) throw "Failed to create AutoComplete Object\n";
    
        hr = pac->Init(hwnd, &columnList, NULL, NULL);
        if(FAILED(hr)) throw "Failed to attach auto complete object\n";
    
        hr = pac->QueryInterface(IID_PPV_ARGS(&pac2)); rep(pac2);
        if (FAILED(hr)) throw "Failed to set autocomplete options\n";

        hr = pac2->SetOptions(ACO_AUTOSUGGEST);
    }
};

int main()
{ 
    Content content;
    SimpleWindow win(&content,"",640,480);

    while(win.isOpen())
    {
     auto &msg = win.getMessage();
     win.dispatchMessage(msg);
    }
}

【问题讨论】:

  • 这甚至无法编译
  • 你应该扔一个物体...
  • 我的意思是终止程序。但是程序继续运行,就好像没有遇到任何抛出一样。我确实尝试了 throw object 版本。

标签: c++ exception visual-c++ throw


【解决方案1】:

因此,您似乎拥有throw "literal",而不仅仅是您最初发布的throw;。那么它确实应该抛出。这里的问题是您尝试抛出通过 Windows DLL 的异常,例如 GetMessage/DispatchMessage 函数或 COM 方法调度,这不能保证工作。

【讨论】:

  • 非常非常非常感谢。我是按照这些思路思考的,因为我有经验从外部 C 抛出不起作用,但我找不到任何具体的东西。我仍然不完全理解这是一个问题,因为我的函数来自 Cpp 上下文并且不是对 win32 函数的回调,但至少你所说的听起来是有效的。
  • 回头看,我的代码是在窗口过程回调中运行的。 MinGw 能够在窗口过程回调中抛出异常,但 MSVC 不能。你的答案是正确的。
  • @user13947194,MSVC 使用 SEH——结构化异常处理。 MinGW 使用 SJLJ SetJump LongJump 或 Dwarf-2 gcc.gnu.org/wiki/WindowsGCCImprovements 。这些机制对 MSVC 编译的代码不可见。没有办法让 MSVC 使用 SEH 以外的其他机制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-28
相关资源
最近更新 更多