SDK - Question

Started by JTaylor, July 14, 2018, 09:14:03 PM

Previous topic - Next topic

JTaylor

I am converting my CommControl Extender to C++ from C and have a question...

If I am passing a Control Handle as a parameter how do I need to assign that in the COMMAND_MAP and the function?

In C I used  an int in the Command Map and the following in the case statement

            HWND ControlHandle = LongToHandle(lpvvArg[0].x);

which generated a warning but it worked.

Can't make that work in C++ and have tried a few different things but going nowhere fast.   

Thanks.

Jim

td

C++ is strongly typed so you need to use a C style cast or the static_cast operator.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

I finally got        HWND ControlHandle = (HWND)IntToPtr(lpvvArg[0].x);        to work.   Is this a viable option or should I be doing something else?

What would be a valid static_cast if I went that route?  It doesn't let me static_cast to HWND when using lpvvArg[0].x.   


Jim

td

All IntToPtr does is perform a C style cast - (VOID *)(INT_PTR).  The problem with that is that it can sign extend the value.  Generally, we do not convert system handles to integers because they can be greater than the largest 32-bit integer in the 64-bit version of the dll or exe.  Instead, we pass them to extender function implementations as strings and the extender does the conversion from string to appropriately sized handle. 

When the static_cast operator reports an invalid cast almost all compilers include the recommendation to use reinterpret_cast instead.  So using static_cast should have lead to a solution without having to deep dive into C++ syntax.  The C++ cast operators generate the same machine instructions as C style casts but the operators better document the intent of the source code writer.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

To prevent things get too far off course, you can get by with passing window handles as integers for now as the 64-bit Windows kernel, at present, does not generate handles greater than max signed 32-bit integer  This is not the case for all Win32 handles and may not continue to be the case for windows handles in future releases of Windows.  This is why we have the coding standard set to not pass handles as integers.     
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Thanks.  Don't want to start something I have to go back and fix later if it can be avoided.  I am using VS 2105 and, unless I missed it, no mention of reinterpret_cast. 

Thanks.   That did the job.

I have been taking a C++ class this summer (hence the conversion) so I will, hopefully, understand what I am doing occasionally rather than just typing until something works and then wonder why it worked  :)

Jim

td

I guess MSFT decided that C++ coders are too simple-minded to be trusted with using a powerful operator like reinterpret_cast.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

They were probably thinking of me.

Jim

td

Perhaps they have rethought their position because VS 2017 adds this note to the static_cast error:

"note: Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast"
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

I give up...would someone be so kind as to tell me what I need to do to make this go away...I have 4 others but guessing if I know what to do with one of them I can fixed the others or fixing the one will fix all.

Error   LNK2019   unresolved external symbol __imp__CreateStatusWindowA@16 referenced in function "public: int __thiscall CDialogEx::sbCreateStatusBar(struct HWND__ *,struct HINSTANCE__ *,long *,struct vipervariable4 *,long)" (?sbCreateStatusBar@CDialogEx@@QAEHPAUHWND__@@PAUHINSTANCE__@@PAJPAUvipervariable4@@J@Z)   dlgex44i   C:\gbat\extenders\CommControl_Cpp\DialogEx.obj   1   

I have spent much time comparing my old project and this one but cannot see anything obvious.   Lots of googling hasn't been overly helpful due to my ignorance.   Not sure if has something to do with the ComCtl32.dll needing to be referenced somewhere or not.  Thought that might be the issue but not sure where that needs to go in VS if that is the case.   I seem to remember something that needed to be done on the old project but cannot remember what now.

Thanks.

Jim

td

It looks like you may have several issues.  The error is likely the result of not specifying the common control library (comctl32.lib) as linker input. 


Not related directly to the error but have you used extern "C"  { } around our extender interface include files? If you don't, you will likely have name mangling issues.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

THANK YOU!!!   That was what I needed.  I thought there was something I had to add on the C version but couldn't remember what or figure out where it needed to go for this one.   At least I was on the right track.   Amazing how much more sense most of this makes after taking a class :-)

On the include file question...I am using the WilExtender example and have simply changed some names and then added in my code along with the necessary COMMAND_MAP and class additions.   Assuming, maybe wrongly, that everything else should be good.

Jim

td

If by WIL Extender example you mean the C++ example and not the C example then all is good.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

I do.   Thanks again.

Jim

JTaylor

I think I found a bug in the C++ Starter Extender.   Doesn't "nCount" need to be defined outside the "for" loop in order to use it in the "return"?   Or did I waste my time and money this summer :)

Jim

Code (c) Select


BOOL CWilExtender::Initalization(HWND hWnd,           // hWnd of parent application.
                                 HINSTANCE hInst,     // hInstance of parent application.
                                 LPLONG lpLong,       // Pointer to your 32 bits.
                                 LPVIPERVAR lpvvArg,  // Pointer to byte buffer.
                                 LONG nArgCount)      // Size of lpvvArg in bytes.
{
   BOOL bInterfaceOk = FALSE;


   if ( m_lpViperStruct->dwLevel >= EXTENDER_FEATURE_LEVEL ) {
     
      bInterfaceOk = TRUE;
   }
   
   if ( bInterfaceOk == FALSE )  {
     
      lstrcpy((LPTSTR)lpvvArg,_T("Need newer version of WIL DLL"));
      return -1;  // Error.
   }
   
   // Get the function map.
   LPCOMMAND_MAP pMap = GetCommandMap();
   if ( !pMap )
      return -1;  // Error.

   // Count then number of entries in the command table map.
   for (int nCount = 0; pMap[nCount].t.ident != -1; nCount++);

   return (int nCount);  // Number of entries.


td

Not sure what wasting time this summer has to do with it but MSFT compilers have a setting for for-loop conformance (/Zc:forScope- if you want the scope of loop control variable to extend past a for-loops block.  It was the default for MSFT's C++ compiler for many years).  C++ has had many standards changes over the years and MSFT has supported or ignored those standard changes at various and sundry times.  MSFT has only gotten standards religion in the last 3 or 4 years. 

Familiarizing yourself with a compilers command line switches and the Visual Studio UI equivalents is kinda important basic stuff.

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

I took a C++ class this summer so I might occasionally understand what I am doing rather than just hacking away at something until it works.   Thanks for the explanation.   

So, ignoring what compilers let one ignore or not and out of curiosity, would the nCount variable be out of scope from a purely C++ coding standard?   Seems it could create problems if one starts ignoring such things as Scope.

Jim

td

The scope modified by the previously mentioned compiler switch only applies to for loop control variables.  Basically, the setting reverts C++ for loop scope to C loop control variable scope rules.   In fact, a case can be made that C scope rules for the for loop is actually better than the  C++ rule for the loop control variable.  That is probably why MSFT made C for loop scope rules the default until they got a case of standards religion when their new CEO came on the scene.  The big issue with a none standard compiler settings is that you may need to change your code if you ever chose to use a different compiler writer's compiler.   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

I think you have confused me, which isn't hard obviously.   My understanding of C and C++ (assuming you are using a version that allows the definition) is that defining the nCount variable in the first clause of the for-loop definition would confine the scope to the for-loop block.  Did some more reading before posting this and what I found seemed to agree with this (hard to tell for certain because everyone got in an argument about whether & when one could define a variable in that fashion).  So back to my question...

What is the "standard" way to code such a thing so the scope is correct without the compiler having to do something special to accommodate bad coding as you have noted in your reply?   What you did in the extender is contrary to everything I have learned, read and can find and VS doesn't like it either but, as noted, MS isn't the always the best ones to consult on what is "standard".

Jim

td

Me thinks you are stirring up a tempest in a teapot. 

All versions of MSFT's C++ compiler defaulted to allow the for loop control variable to have encapsulating block scope until VS 2015.  MSFT changed the default with VS 2015.  You can still set the for LCV scope either way with newer versions of the VS C++ compiler.  This includes VS 2017.  IIRC, there are 3 different compiler switches that relate to this.  Also note that even VS 2017's C++ compiler does not support the more recent ISO C++ versions of the standard.

Ths C99 standard was the first C standard to allow the declaration of LCVs in the first argument to the for statement.  Not may compilers were ever written to the strict  C99 standard. MFST generally supported C99 but its C compiler is far from strictly compliant.   That is how "standards" work in the real world.

You need to understand that despite what you may have learned very few if any compilers are completely compliant to the standard as set by the ISO committee (ISO/IEC JTC1 (Joint Technical Committee 1) / SC22 (Subcommittee 22) / WG21 (Working Group 21)).  The standard is also open to interpretation so it is very rare for two compilers to enforce exactly the same syntax in a programming language as complex as C++.  It is also the case that the standards committee doesn't always get it right but can be very slow to admit it.   Again, this is how the world outside of committees and academia works.

So declare your LCVs as you choose and feel appropriately self-rightness about it.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Actually I thought I was asking for a straight-forward answer to a question (and I am not stupid enough to think everyone adheres to all the standards of anything) but it appears I have wasted time for us both.  You said that " The big issue with a none standard compiler settings is that you may need to change your code if you ever chose to use a different compiler writer's compiler."   I was simply trying to figure out how I should code it so this isn't an issue since you are saying that VS is doing it in a non-standard way by asking a variable to be defined in the scope in which it is being used (or at least seeing a variable being defined in the for-loop definition as being in the for-loop scope).  Sorry to have bothered you but appreciate you taking the time.  Guess I will just define my variables in the scope they are being used and hope for the best.

Thanks again.

Jim

td

The C++ standard states that an LCV declared as the first item of a for loop statement should have the same scope as a variable declared within the for loop bock:

Code (c) Select
int FooBar()
{
   for( int i = 1; 10; i++ )
   {
      // This is the for loop block
      // i is in scope
   }

   // This is the block enclosing the for loop block.

   // The default compiler setting for the VS 2015 compiler
   // i is not in scope.  This is conformant to the ISO standard.
 
   // However, i is in scope for VS compilers preceding VS 2015
   // and this is not conformant to the ISO standard.

   return i;
}


You have two choices.  You can write your code to be conformant to the standard and move the LVC declaration out of the for statement.  Or you can set the appropriate compiler setting to make "i" visible outside the for loop's block.   There is no one right answer.  If you asked 100 C++ developers, probably 98 would say stick to the standard but there are situations where that may not be the preferred option.  It is up to you and I am certainly not going to tell you which is the best choice for you.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Thank you.  Hope that wasn't too painful ;) 

That conforms to everything I know and understand.   Your previous answers were leading me to believe coding it so the "i" would be in scope outside the For-Loop was inappropriate and, while it *might* work with the proper compiler settings, could lead to problems in the future.

Jim

td

"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Quote from: JTaylor on July 23, 2018, 11:29:07 AM

Your previous answers were leading me to believe coding it so the "i" would be in scope outside the For-Loop was inappropriate and, while it *might* work with the proper compiler settings, could lead to problems in the future.


The point was that coding outside the standard could cause a problem in the future but in this case, the odds are low and the problem trivial.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

You are confusing me again because I was advocating coding within the standard but you seemed to indicate that would be a problem.   My initial post was asking if coding the Sample Extender the way it was done would be  a problem because it doesn't adhere to the standard as you explained it.   That wasn't my code I was asking about originally, that was the Extender as it was packaged.

Jim

td

Quote from: JTaylor on July 24, 2018, 11:11:24 AM
You are confusing me again because I was advocating coding within the standard but you seemed to indicate that would be a problem.   

I have no idea how you can to that conclusion so I have no response.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Just chalk it up to me being an idiot and we can move on :)     

The whole point to the discussion was I thought the SDK should be changed so the code in it would adhere to the C++ standard.   I have made that change on my side and you, of course, can do as you think best.

Thanks again and sorry for any of your time I have wasted.

Jim