Error c2712 cannot use try in functions that require object unwinding

I have a code that is called on a pointer that may be invalid (I have no control over its value):
  • Remove From My Forums
  • Question

  • I have a code that is called on a pointer that may be invalid (I have no control over its value):

    __try
    {
      CString str = (LPCTSTR)wParam;
    
      //Work with 'str' now
    }
    __except(1)
    {
      //Memory fault
    }
    

    But when I try to use it in a MFC project, it gives me this error:

    error C2712: Cannot use __try in functions that require object unwinding

Answers

  • /EHa is a compiler option, and you’ll find what it means in the documentation. (Along with _set_se_translator, you would use try/catch instead of _try/_except.) To use it on the smallest amount of code possible, create a file containing just that code, add
    it to your project, and modify the file’s properties to use asynchronous exception handling. BTW, if you follow Ted’s suggestion and continue to use _try/_except, I think you still have to use /EHa to ensure C++ objects on the stack are correctly destroyed
    when an SE is thrown. In general, it’s a very bad idea to use /EHa and SEH in C++ programs to deal with things like access violations, because it’s very easy to hide program bugs and put your program in an undefined state. Even wrapping your little bit
    of code in SEH exposes the CString construction code to undefined behavior if an access violation is thrown, because the author of the CString code surely didn’t consider what it would mean for every instruction to be able to throw a non-C++ exception. Exiting
    that little bit of code abnormally probably will not leave your program damaged, but the chance of wrecking your program’s state grows as you inflict /EHa on more and more code and catch SE’s further and further away from where they occur. And by «state» I
    mean consistency of the data it’s using, which includes all its data structures, files it’s manipulating, process state, and so forth.


    Doug Harrison (Visual C++ MVP)

    • Marked as answer by

      Tuesday, August 3, 2010 2:31 AM

  • __try
    {
      DoStuffWithWParam(wParam);
    }
    __except(1)
    {
      //Memory fault
    }

    void DoStuffWithWParam(WPARAM wParam) {

    CString str = (LPCTSTR)wParam;

      //Work with ‘str’ now
    }

    • Marked as answer by
      Yi Feng Li
      Tuesday, August 3, 2010 2:31 AM

I’ve got this loop here for a game bot which requires a __try __except to prevent insta-crashing when the code is injected. However, I’m getting the error: Cannot use __try in functions that require object unwinding fix.

I’ve looked through all function calls inside of this function, and not a single one of them contain a nested __try __except and I’m also building with /EHs.

Here’s my code;

void bot::logic::loop()
{
    while (true)
    {
        __try
        {
            if (bot::logic::should_close())
                exit(33062);

            om::refresh_minions();

            if (local_player::is_threatened())
                local_player::handle_threat();

            if (local_player::is_in_turret())
            {
                utils::move_to_suitable_pos();
                std::this_thread::sleep_for(12s);
            }

            object* localplayer = obj_local_player;
            bot::logic::calculate_buys(localplayer->current_gold);

            obj_manager* manager = (obj_manager*)(m_base + o_obj_manager);
            for (int32_t i = 0; i < manager->highest_index; i++)
            {
                object* this_object = manager->ptrs[i];

                if (this_object)
                {      
                    if (is_minion(this_object) == 3073)
                        if (local_player::object_is_enemy(this_object))
                            if (utils::is_object_mid(this_object))
                                if (is_alive(this_object) == TRUE)
                                    utils::Log("all passed");

                    if (local_player::object_is_enemy(this_object) && utils::is_object_mid(this_object) && is_alive(this_object) == TRUE && is_minion(this_object) == 3073)
                    {
                        object* enemy_minion = this_object;

                        for (int i = 0; i < game::minion_maxed_index; i++)
                        {
                            bot::logic::moving_to_cs_loop(om_ally_minions[i].minion_object, enemy_minion);
                            bot::logic::csing_loop();
                        }
                    }
                }
            }
            std::this_thread::sleep_for(100ms);
        }
        __except (EXCEPTION_EXECUTE_HANDLER) {};
    }
}

Can anyone tell me which objects ‘require unwinding’ and how I can prevent this error?

EDIT: I’ve found the error occurs within the code;

if (is_minion(this_object) == 3073)
    if (local_player::object_is_enemy(this_object))
        if (utils::is_object_mid(this_object))
            if (is_alive(this_object) == TRUE)
                utils::Log("all passed");

hellow's user avatar

hellow

11.9k7 gold badges52 silver badges73 bronze badges

asked Aug 6, 2018 at 6:06

siroot's user avatar

2

Anyway I would suggest you move the code within __try/__except to an own function then call it, that way the stack unwinding occurs in the other function.

e.g.

void loop()
{
  __try  { loopimpl(); }
  __except(EXCEPTION_EXECUTE_HANDLER) {};
}

void loopimpl()
{
  while (true) { ... }
}

answered Aug 6, 2018 at 6:14

AndersK's user avatar

AndersKAndersK

35.5k6 gold badges58 silver badges85 bronze badges

Move __try/__except upper in call hierarchy

void test() {
    myClass m;
    __try
    {
        m.run();
    }
    __except (GenerateDump(GetExceptionInformation())){}
}
int main()
{
    test();
}

Result: Error C2712 Cannot use __try in functions that require object unwinding …

But:

void test() {
    myClass m;  
    m.run();
}
int main()
{
    __try
    {
        test();
    }
    __except (GenerateDump(GetExceptionInformation())) {}
}

Result: OK

answered Feb 8, 2019 at 8:40

Piotr Sydow's user avatar

0

I’ve workarounded that by a labda function beginning from the C++11. Works specifically in the msvc (2015, 2017, …). The /EH* command line option must be used.

std::vector<...> a;

[&]() {
  __try {
    a.resize(...);
    ...
    [&]() {
      std::vector<...> b;
    }();
  }
  __finally {
    ... 
  }
}();

Or more universal variant, for example, in the main:

int main()
{
    std::vector<...> a;
    return [&]() -> int { __try {
        return [&]() -> int {
            std::vector<...> b;
            return 0;
        }();
    }
    __finally {
        // close all handles here...
    }
    return 0;
    }();
}

Some disadvantage of this is that you still can not return c++ objects and must assign them through all labda functions to the most outer scope out of the __try scope.

std::string foo()
{
    std::string ret;

    [&]() { __try {
        [&]() {
            // return std::string{"123"}; // error C2712: Cannot use __try in functions that require object unwinding
            ret = std::string{"123"};
        }();
    }
    __finally {
        // close all handles here...
    }
    }();

    return ret;
}

https://godbolt.org/z/Kxxqrc1hh

If you want to enable the __try/__except/__finally under GCC, then can look at something like that: http://www.programmingunlimited.net/siteexec/content.cgi?page=libseh

answered May 20, 2021 at 14:08

Andry's user avatar

AndryAndry

2,04228 silver badges28 bronze badges

I do not get it, why does code that needs unwinding inside __try block give me errors/warnings:

* warning C4509: nonstandard extension used: ‘someFunctionScope’ uses SEH and ‘someVariable’ has destructor

* error C2712: Cannot use __try in functions that require object unwinding

When /EHa (VC++ 2013) option is selected?

Isn’t /EHa supposed to force the compiler to assume exceptions can occur anywhere (aka. asynchronous) and it hence must record all the destructors (ie. cannot optimize out the non-explicit ones like access violations etc).

What? I don’t even … what is my sleepy head missing? I could have sworn that i have done this before without problems.

PS. Since it is bound to come up: i really-really need to attempt (in my case, the chances are actually very good) surviving memory trashing / broken code (something that is normally undesirable), so SEH is a must as is unwinding.

SEH is orthogonal to C++ exceptions in principle. Under the hood, C++ exceptions on Microsoft compilers might use SEH, but they are not safe to blend in general.

__try/__except is «Structured exception handling». It is Windows-specific, not part of the C++ standard, and (I believe) supported in C using MS’s tools.

Because these keywords have nothing to do with C++ exceptions, they do not perform stack unwinding like C++ exceptions do, and so the compiler is warning you that your destructors won’t be called (because the structured exception system doesn’t even know they’re a thing).

If you want to use exceptions, then use C++ try/except (note, no underscores).

Erm, you are confused or not expressing yourself clearly enough for me.

C++ exceptions are built on SEH. It will quite happily execute any C++ handlers along the way when unwinding. So, of course all the destructors etc will be called — as long as compiler did add them to the unwind stack to begin with. VC++ compiler is free to optimize out adding thous when it sees that there can not be any exceptions (default compile options). To do that it only considers explicit exceptions (throw) by default. That is where «/EHa» comes in — it disallows such optimizations and hence the entries will be there for even non-explicit exceptions (integer division by zero, access violation, etc).

My findings, based on and sanity-confirmed in practice:

https://msdn.microsoft.com/en-us/library/swezty51.aspx

https://msdn.microsoft.com/en-us/library/1deeycx5.aspx

My problem was caused by using «__try» in function scope that needs to unwind objects — which it cannot compile for some unknown reason i was not able to precisely pin down (might be some limitation of the function level handler that «__try» installs — ie. it can not add/remove unwind entries on the fly as functions with «try» can or more likely, the compiler is just not programmed to do so).

Which makes the solution obvious — move «__try» to a function scope that does not have objects to unwind. Unfortunately, in my case that would wreck readability — so, have to use «try catch(…)».

Examples for the benefit of passers by:

struct Test() {
    Test() { out << L"new Test"; }
    ~Test() { out << L"del Test"; }
    void crash() { out << *(int*)(0); }
}
 
void func() {
    Test foo; // Perfectly fine to unwind this object (Needs /EHa of couse as otherwise the code needed for unwind would be optimized out as "foo.crash" has no explicit "throw")
    foo.crash();
}
 
void test() {
    // Test notOkay; // Cannot compile this. Function uses __try and needs object unwinding.
    __try {
        func();
    } __except(EXCEPTION_EXECUTE_HANDLER) {
        out << L"crashed";
    }
}

C++ exceptions are built on SEH. It will quite happily execute any C++ handlers along the way when unwinding.

Really, this is your misunderstanding.

/EHa causes the compiler to emit code such that SEH exceptions are handled like C++ exception, meaning they’ll be caught by catch(…). Plain and simple. An SEH will not otherwise cause destructors to get invoked during unwinding, because the SEH mechanism knows nothing aout the C++ runtime model.

SEH are not C++ exceptions, unless you use /EHa. Only C++ exceptions invoke C++ destructors. You need to use try/catch (and not __try/__except) to use C++ exceptions.

I suspect the compiler is just trying to save you from the consequences of your misunderstanding.

Stephen M. Webb
Professional Free Software Developer

C++ exceptions are built on SEH. It will quite happily execute any C++ handlers along the way when unwinding.

Really, this is your misunderstanding.

I was stating a fact (it has been this way at least a decade). C++ exceptions are implemented using SEH functionality in VC++.

/EHa causes the compiler to emit code such that SEH exceptions are handled like C++ exception, meaning they’ll be caught by catch(…). Plain and simple.

Superficially true. To be specific:
* SEH exception filter for catch(…) does not select only C++ exceptions anymore (which it normally would).
* Optimizer can not rely on throws anymore and needs to emit all the unwind code it normally would omit.

An SEH will not otherwise cause destructors to get invoked during unwinding, because the SEH mechanism knows nothing aout the C++ runtime model.

That is messed up. SEH does not need to know anything about the unwind payload — C++ exceptions or otherwise.

SEH are not C++ exceptions, unless you use /EHa.

This is completely backwards.

Only C++ exceptions invoke C++ destructors.

Incorrect.

You need to use try/catch (and not __try/__except) to use C++ exceptions.

Incorrect in principle. C++ exception catching is done via SEH exception records where C++ exceptions have the exception code 0xe06d7363. You are free to handle C++ exceptions in your __except — which, granted, is quite silly.

I suspect the compiler is just trying to save you from the consequences of your misunderstanding.

Incorrect. Compiler just can not do object unwinding in a function scope that also has __try … which overloaded my sleepy brain — i just was not aware of that limitation (have Googled around since then and it is a well known limitation, but like i said — could not pinpoint any specific reason for it).

PS. You are well advised to assume i am not totally talking out of my ass. Example code:


struct Test {
    Test() { out << L"new Test"; }
    ~Test() { out << L"del Test"; }
    void panic() {
        throw 42;
    }
};

void snafu() {
    out << L"shit's gonna hit the fan ...";
    Test obj;
    obj.panic();
}

int filter(LPEXCEPTION_POINTERS e) {
    out << L"exception code: " << std::hex << e->ExceptionRecord->ExceptionCode;
    // second parameter in c++ exceptions is a pointer to thrown object (plain int in this case)
    out << L"C++ exception payload object: " << std::dec << *(int*)e->ExceptionRecord->ExceptionInformation[1];
    // yeah, we will take anything - including the C++ exception.
    return EXCEPTION_EXECUTE_HANDLER;
}

void test() {
    __try {
        snafu();
    } __except(filter(GetExceptionInformation())) {
        out << L"panic averted";
    }
}

Output (compiled with the default /EHsc option) as one would expect:

shit's gonna hit the fan ...
new Test
exception code: e06d7363
C++ exception payload object: 42
del Test
panic averted

Cheers.

Going back to OP (since I apparently missed it the first read through):

PS. Since it is bound to come up: i really-really need to attempt (in my case, the chances are actually very good) surviving memory trashing / broken code (something that is normally undesirable), so SEH is a must as is unwinding.

You can’t.

Crashing is the best case scenario in those cases — and the only thing you can safely do. If memory is trashed you aren’t even guaranteed a crash or even an exception. At least with a crash the OS can clean up your malfunctioning program and prevent it from causing even more damage.

Forget about SEH. Use C++ exceptions for error handling.

No shit sherlock *massive-facepalm*. Why did you even write that? Was it not crystal clear that discussions (at least without a lot more details) in that direction is undesired waste of everyone’s time?

As i wrote: «ATTEMPT surviving broken code /…/ something that is normally undesirable«.

PS. Since you like to ASS-U-ME stuff about what is or is not sensible for me to do in my specific case: the code runs in kernel land and some in user land via callbacks — there is no way for the OS to survive or cleanup anything when the program is broken (the process cannot even be terminated because it is in essence part of the kernel at that point — so, you get kernel panic … BSOD). However i can send a message and initiate a proper teardown and hope the corruption has not already wrecked the OS (the chances happen to be actually pretty good that the OS will remain unharmed [ie. all internal structures in valid state]). An approach that is highly desirable, in my case, while in development phase.

So, no, you could not be more wrong. Don’t assume you know the necessary context and details of what i am doing to ignore my PS’note in OP. It is exceedingly unhelpful.

To the best of my knowledge the /GX option will make the structured (windows) exception work more like a C++ exception and cause it to delete local objects as it unwinds the stack.  If you have objects, you should use this option.

What does object unwinding mean?

With the structured (windows not C++) exceptions, when an exception is thrown Windows removes the stack frame (local variables)  for each function it throws out of.  That is it removes local variables until it finaly gets back to a place where the exception is caught.  However, it doesn’t know what these local variables are, it just is removing them from the stack like they are dumb data.   This is fine if they are chars, ints, or dumb pointers.  But if they are objects, their destructors should be called so they can «clean up»  Windows can’t do that though, it doesn’t know about destructors.  In a regular C++ exception, the destrcutors will be called, which is why you should use C++ exceptions whereaver possible.  Using the /GX option is a good compromize, the compiler will try to destroy objects as it handles the windows exception, thus it will work more like a C++ exception.

Let me know if you have questions.

  • Home
  • VBForums
  • Other Languages
  • C and C++
  • Try Function Error C2712

  1. Jan 22nd, 2017, 12:03 PM


    #1

    luckydead is offline

    Thread Starter


    Addicted Member


    Try Function Error C2712

    Code:

    BOOL CMapServerManager::LoadData(char* lpszFileName)
    {
    	if ( (lpszFileName == NULL) || ( strcmp(lpszFileName, "")== 0 ) ) 
    	{
    		MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : File Name Error");
    		return FALSE;
    	}
    
    	EnterCriticalSection(&this->m_critSVRCODE_MAP);
    
    	__try
    	{
    		this->Clear();
    
    		SMDFile = fopen(lpszFileName, "r");
    
    		if ( SMDFile == NULL )
    		{
    			MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : fopen() : %s",
    				lpszFileName);
    
    			return FALSE;
    		}
    
    		int type = -1;
    		SMDToken Token;
    
    		while ( true )
    		{
    			Token = GetToken();
    
    			if ( Token == END )
    				break;
    
    			type = TokenNumber;
    
    			while ( true )
    			{
    				if ( type == 0 )
    				{
    					short sSVR_CODE = -1;
    					short sMAPSVR_GROUP = -1;
    					int iInitSetVal = 1;
    					char szIpAddr[16]={0};
    					WORD wPortNum = 0;
    					
    					Token = GetToken();
    
    					if ( !strcmp("end", TokenString))
    						break;
    
    					sSVR_CODE = TokenNumber;
    
    					Token = GetToken();
    					sMAPSVR_GROUP = TokenNumber;
    
    					Token = GetToken();
    					iInitSetVal = TokenNumber;
    
    					Token = GetToken();
    					memcpy(szIpAddr, &TokenString[1], 16);
    					szIpAddr[15] =0;
    
    					Token = GetToken();
    					wPortNum = TokenNumber;
    
    					if ( sSVR_CODE < 0 )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : sSVR_CODE < 0 (SVR:%d) - 1",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					if ( iInitSetVal != -1 && iInitSetVal != 0 && iInitSetVal != 1 )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : iInitSetting Value:%d (SVR:%d) - 1",
    							iInitSetVal, sSVR_CODE);
    
    						return FALSE;
    					}
    
    					if ( !strcmp(szIpAddr, ""))
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : No IpAddress (SVR:%d)",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					if ( CHECK_LIMIT(sMAPSVR_GROUP, MAX_MAP_GROUPS) == FALSE )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : Map Server Group Index (IDX:%d)",
    							sMAPSVR_GROUP);
    
    						return FALSE;
    					}
    
    					if ( this->m_iMAPSVR_GROUP_COUNT[sMAPSVR_GROUP] >= MAX_MAP_SUBGROUPS )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : No Space to Save SvrInfo (SVR:%d)",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					_MAPSVR_DATA * lpMapSvrData = NULL;
    
    					lpMapSvrData= &this->m_MAPSVR_DATA[sMAPSVR_GROUP][this->m_iMAPSVR_GROUP_COUNT[sMAPSVR_GROUP]];
    
    					lpMapSvrData->Clear(iInitSetVal);
    					lpMapSvrData->m_bIN_USE = TRUE;
    					lpMapSvrData->m_sSVR_CODE = sSVR_CODE;
    					lpMapSvrData->m_btMAPSVR_GROUP = sMAPSVR_GROUP;
    					lpMapSvrData->m_wPORT = wPortNum;
    					memcpy(lpMapSvrData->m_cIPADDR, szIpAddr, 16);
    					lpMapSvrData->m_cIPADDR[15] = 0;
    					
    					this->m_mapSVRCODE_MAP.insert(std::pair<int,_MAPSVR_DATA *>(sSVR_CODE, lpMapSvrData));
    					this->m_iMAPSVR_GROUP_COUNT[sMAPSVR_GROUP]++;
    				}
    				else if ( type == 1 )
    				{
    					short sSVR_CODE = -1;
    					BYTE btNotMoveOption = 0;
    					WORD wMapNum = 0;
    					short sDEST_SVR_CODE = -1;
    					_MAPSVR_DATA * lpMapSvrData = NULL;
    
    					Token = GetToken();
    
    					if ( !strcmp("end", TokenString))
    						break;
    
    					sSVR_CODE = TokenNumber;
    
    					Token = GetToken();
    					btNotMoveOption = TokenNumber;
    
    					Token = GetToken();
    					wMapNum = TokenNumber;
    
    					Token = GetToken();
    					sDEST_SVR_CODE = TokenNumber;
    
    					if ( sSVR_CODE < 0 )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : sSVR_CODE < 0 (SVR:%d) - 2",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					if ( sDEST_SVR_CODE < -2 )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : sDEST_SVR_CODE < -1 (SVR:%d, DEST_SVR:%d) - 2",
    							sSVR_CODE, sDEST_SVR_CODE);
    
    						return FALSE;
    					}
    
    					std::map<int  ,_MAPSVR_DATA *>::iterator it = this->m_mapSVRCODE_MAP.find(sSVR_CODE);
    
    					if ( it == this->m_mapSVRCODE_MAP.end() )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : sSVR_CODE wasn't registered (SVR:%d)",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					lpMapSvrData = it->second;
    
    					if ( lpMapSvrData == NULL )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : lpMapSvrData == NULL (SVR:%d)",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					if ( lpMapSvrData->m_bIN_USE == FALSE )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : lpMapSvrData->m_bIN_USE == FALSE (SVR:%d)",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					if ( lpMapSvrData->m_sSVR_CODE != sSVR_CODE )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : lpMapSvrData->m_sSVR_CODE != sSVR_CODE (SVR:%d)",
    							sSVR_CODE);
    
    						return FALSE;
    					}
    
    					if ( btNotMoveOption != 0 && btNotMoveOption != 1 )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : lpMapSvrData->m_sSVR_CODE != sSVR_CODE (SVR:%d, OPT:%d)",
    							sSVR_CODE, btNotMoveOption);
    
    						return FALSE;
    					}
    
    					if ( CHECK_LIMIT(wMapNum, MAX_NUMBER_MAP) == FALSE )
    					{
    						MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : Map Number is out of bound (SVR:%d, MAP:%d)",
    							sSVR_CODE, wMapNum);
    
    						return FALSE;
    					}
    
    					switch ( btNotMoveOption )
    					{
    						case 0:
    							lpMapSvrData->m_sMAP_MOVE[wMapNum] = sDEST_SVR_CODE;
    							break;
    						case 1:
    							lpMapSvrData->m_sMAP_MOVE[wMapNum] = -3;
    							break;
    						default:
    							MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : lpMapSvrData->m_sSVR_CODE != sSVR_CODE (SVR:%d, OPT:%d)",
    								sSVR_CODE, btNotMoveOption);
    							break;
    					}
    				}	// if type
    			}	// while ( true )
    		}	// while ( true )
    
    		fclose(SMDFile);
    
    		std::map<int  ,_MAPSVR_DATA *>::iterator it = this->m_mapSVRCODE_MAP.find(gGameServerCode);
    
    		if ( it != this->m_mapSVRCODE_MAP.end() )
    		{
    			this->m_lpThisMapSvrData = it->second;
    		}
    		else
    		{
    			this->m_lpThisMapSvrData = NULL;
    		}
    
    		if ( this->m_lpThisMapSvrData == NULL )
    		{
    			MsgBox("[MapServerMng] CMapServerManager::LoadData() - file load error : This GameServerCode (%d) doesn't Exist at file '%s' != sSVR_CODE",
    				gGameServerCode, lpszFileName);
    
    			return FALSE;
    		}
    
    		this->m_bMapDataLoadOk = TRUE;
    	}
    	__finally
    	{
    		LeaveCriticalSection(&this->m_critSVRCODE_MAP);
    	}
    
    	return TRUE;
    }

    Got Error: Error C2712: Cannot use __try in functions that require object unwinding
    I Use: Yes (/EHsc)


  2. Jan 22nd, 2017, 05:39 PM


    #2

    Re: Try Function Error C2712

    You can’t use __try(…) with the /EHSc option together with objects that require unwinding. See https://msdn.microsoft.com/en-us/library/xwtb73ad.aspx for further info and possible work-arounds.

    All advice is offered in good faith only. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/

    C++23 Compiler: Microsoft VS2022 (17.4.4)


  3. Jan 23rd, 2017, 04:01 AM


    #3

    luckydead is offline

    Thread Starter


    Addicted Member


    Re: Try Function Error C2712

    yes i had already found and fix this issue from project propertise


  • Home
  • VBForums
  • Other Languages
  • C and C++
  • Try Function Error C2712


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
  • BB code is On
  • Smilies are On
  • [IMG] code is On
  • [VIDEO] code is On
  • HTML code is Off

Forum Rules


Click Here to Expand Forum to Full Width

This article is related to the latest patch I made for the Emotiv EPOC driver for the OpenViBE Acquisition Server.

The main motivation for that patch is the time we consume on support for the Emotiv EPOC users, that needed to compile manually the software to have the driver.
As this headset is quiet cheap, aiming mass market, many people using it were not particularly comfortable with SVN, C++ compilation, scripts and technical computer stuff.

The manufacturer, namely Emotiv, agreed to let us redistribute a binary version of the driver, without providing its proprietary DLL.
Doing so, the binary version of OpenViBE will work with the Emotiv EPOC headset once users provide a valid DLL they purchased from Emotiv (Emotiv SDK Research Edition or above).

Solution : load the DLL only at runtime, with a clean error handling if the DLL is not present.

When developing this patch, I was totally newbie to DLL delayed loading, and I faced one big problem : the lack of documentation and example, even on the official MSDN website.
The purpose of that article is to give feedback and sample code in one place, for those who may need it in the future. It’s not clearly OpenViBE related as you may notice 🙂

The environment

Here is the specifications of the setup I used:

  • OS : Windows 7 64bits
  • Visual Studio 2010 Ultimate
  • CMake 2.8.3
  • OpenViBE svn 3065 (18 Aug 2011)
  • Standard cup of coffee

Delay load library

In Visual Studio

To load a dll at runtime in an application compiled by Visual Studio, you must tell the linker to do so. Specify the delay loaded libraries in the project properties (linker > entries > delay load library).
The resulting command line option is :

/linker /DELAYLOAD:MyDLL.dll

To do the job, Visual studio relies on the library Delayimp.lib that you must link against at compilation time.
You can add it in the project properties (linker > entries > additional library)

Build your project.

When running your application, the DLL will be loaded only at the first call to a function within the DLL.
If you remove the DLL and run the application again, it should fail at the same moment,  with an unhandled exception “MODULE NOT FOUND”.
It should definitely not fail at startup with “missing MyDLL.dll.

With CMake

The OpenViBE software platform uses CMake for compilation over several operating system.

We add the following linker option into the cmake command line:

-DCMAKE_EXE_LINKER_FLAGS=" /DELAYLOAD:MyDLL.dll"

We also need to link the project with Delayimp.lib.
This is done in the CMake script that initializes cmake properly to compile the Acquisition Server, thanks to the command :

TARGET_LINK_LIBRARIES(${PROJECT_NAME}-dynamic Delayimp.lib

Exception handling

My program now works fine if I have the DLL on board, and fails when not present with an unhandled exception.
To perform a clean exception handling, one solution is to safely guard the first call to our DLL using Structured Exception Handling (__try/__except) clauses.
Please not that this require your code to #include <windows.h>.

 __try
 {    
   int result = functionInMyDLL();
 }
 __except(EXCEPTION_EXECUTE_HANDLER)
 {
    //fail nicely   
 }

In my case, I guard the first call to the Emotiv DLL in the driver initialization. If the exception rises, I print an error and return false, stopping the execution of the driver.
I am sure that not a single call to any of the DLL functions can be performed if this one fails.

Error C2712

As all developers know, when it comes to programming, nothing goes as expected.

Everything was fine until I tried to improve the driver. The following code resulted in a compilation error C2712 (yeah that famous one. or not.)

...
CObject l_oObject();
l_oObject.doStuff();
...
__try
 {    
   int result = functionInMyDLL();
 }
 __except(EXCEPTION_EXECUTE_HANDLER)
 {
    //fail nicely   
 }
...

The error C2712 means : “cannot use __try in functions that require object unwinding”
In other words, you cannot use objects with destructors in a function that uses __try/__except.

My CObject class has a destructor, I cannot instantiate it in my function.

Solution selected : refactor my code to be able to do:

...
this->doStuffOnObject();
...
__try
 {    
   int result = functionInMyDLL();
 }
 __except(EXCEPTION_EXECUTE_HANDLER)
 {
    //fail nicely   
 }
...

This error happened because our project is compiled with the Error Handling Model /EHs:

s    The exception-handling model that catches C++ exceptions only and tells the compiler to assume that extern C functions do throw an exception.

Conclusion

This article may not be very complete, as I didn’t want to just copy paste pieces of code too much specialized  to openvibe.
My goal is just to keep record of my experience with delayload library on windows, for anyone who may need it (including myself 😉 )

Cheers.

Sources:

MSDN official documentation : <http://msdn.microsoft.com/en-us/library/151kt790.aspx>

“Delay Load Dlls Error Recovery” by Tomer Margolin: <http://www.codemaestro.com/articles/6>

Error C2712: <http://msdn.microsoft.com/en-us/library/xwtb73ad%28v=vs.80%29.aspx>

Понравилась статья? Поделить с друзьями:
  • Error c2601 main недопустимые локальные определения функций
  • Error c2589 illegal token on right side of
  • Error c2563 mismatch in formal parameter list
  • Error c2561 main функция должна возвращать значение
  • Error c2504 не определен базовый класс