Solved

Function crashes when called inside of WndProc, but not when run in InitInstance or other places??

Posted on 2004-03-21
16
523 Views
Last Modified: 2012-05-04
ok, so I have a function called void test();

Just for testing purposes I had the function being called at the very end of
"BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)"

What I really wanted was to have the function called in
"LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)"

whenever a WM_COPYDATA message was received.

Whenever I put it in the WndProc function instead of at the end if InitInstance, it runs void test(), for the first few lines, but then when it enters a while loop it crashes.

There only difference is where it is being called from. There is nothing special in the funcion, just a while loop:



--------------------------------------------------------------------------------
void test()
{
calXY();
long lResult;
int y = 0;
ShowWindow(gMainHwnd,SW_HIDE);
UpdateWindow(gMainHwnd);
MessageBox(NULL,"RUNNING",NULL,NULL);
while(!GetAsyncKeyState(VK_CONTROL))
{
ProcessLoop();
}

ShowWindow(gMainHwnd,SW_SHOW);
UpdateWindow(gMainHwnd);

}
-------------------------------------------------------------------------------------------

ProcessLoop is just another void function.

void processloop()
{
if(boolfunction ==true)
{
}
else
{
}
}

it enters processloop, but crashes during the call to boolfunction. It doesnt ever enter boolfunction though...


What is the difference between where the function is called from?  How can I get it to run in there?

Thanks,

-Nate
0
Comment
Question by:bignateyk
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 6
16 Comments
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10645623
WndProc is a function that is called with any dispatched Windows Message.

However, your function test() produces a lot of messages itself (ShowWindow, UpdateWindow, MessageBox, GetAsyncKeyState, ...). Thus it is recursively called again and again and again .... You must not use Windows messages within WndProc.

Regards, Alex
0
 

Author Comment

by:bignateyk
ID: 10646078
how would you suggest I call a function after receiving data from WM_COPYDATA?
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10647558


Can you post the implementation of WndProc?

Normally it's something like this:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{  
    switch (message)
   {        
   case WM_COMMAND:
                   ....
                   break;
   case WM_COPYDATA:
           test();
           break;
   case ...
   };

That would be safe if none of the function calls within test() would send any WM_COPYDATA message again, thus producing an infinite recursion.


>> while(!GetAsyncKeyState(VK_CONTROL))

I'm not sure but it's very likely that this call is the reason for the crash: MSDN says to the return value of  GetAsyncKeyState():

>> The return value is zero if a window in another thread or process currently has the keyboard focus.

As test()  called MessageBox() the main thread might have lost the focus, GetAsyncKeyState will return zero and the while loop is running infinitely producing a stack overflow in a little while. In any case it's a failure when GetAsyncKeyState returns 0 and you shouldn't call it within a while condition. I would suggest to call GetAsyncKeyState when handling WM_KEYDOWN message and save the result in a BOOL variable.

Regards, Alex


0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:bignateyk
ID: 10655378
ok, in test(), I got rid of all the showwindow & updatewindow calls, as well as the getasynckeystate call, and any messageboxes.

I deleted everything that wasnt absoultely necessary in the wndproc function, and am left with:

      case WM_COPYDATA:
            main_loop();
                                break;

Its kind of complicated since main_loop() branches into about 30 other functions ultimatly, but ive narrowed it down to this line about 5 functions into main_loop():

-------------------------------------
memcpy(m_pbi, pbi, nb);
-------------------------------------

where m_pbi, pbi are LPBITMAPINFOHEADER's



0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10656780
I assume your program crashes at that memcpy statement?

If so, you should check that

  - 'm_pbi' points to a storage that has allocated at least 'nb' bytes
  - 'm_pbi' wasn't deleted by any destructor or init() function
  - 'nb' is greater 0 and  nb == pbi->biSize
  - 'pbi' is a valid pointer to a bitmap header created by a source similar to that

  HBITMAP LoadResourceBitmap(HINSTANCE hInstance, LPSTR lpString,
                                               HPALETTE FAR* lphPalette)
 {
    HRSRC  hRsrc;
    HGLOBAL hGlobal;
    HBITMAP hBitmapFinal = NULL;
    LPBITMAPINFOHEADER  lpbi;
    HDC hdc;
    int iNumColors;

    if (hRsrc = FindResource(hInstance, lpString, RT_BITMAP))
       {
       hGlobal = LoadResource(hInstance, hRsrc);
       lpbi = (LPBITMAPINFOHEADER)LockResource(hGlobal);

       hdc = GetDC(NULL);
       *lphPalette =  CreateDIBPalette ((LPBITMAPINFO)lpbi, &iNumColors);
       if (*lphPalette)
          {
          SelectPalette(hdc,*lphPalette,FALSE);
          RealizePalette(hdc);
          }

       hBitmapFinal = CreateDIBitmap(hdc,
                   (LPBITMAPINFOHEADER)lpbi,
                   (LONG)CBM_INIT,
                   (LPSTR)lpbi + lpbi->biSize + iNumColors * sizeof(RGBQUAD),
                   (LPBITMAPINFO)lpbi,
                   DIB_RGB_COLORS );

       ReleaseDC(NULL,hdc);
       UnlockResource(hGlobal);
       FreeResource(hGlobal);
       }
     return (hBitmapFinal);
    }

Hope, that helps

Alex
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10656864
Two more comments:

1. Did you consider that a BITMAPINFOHEADER always is embedded in a struct BITMAPINFO
   that has a dynamically sized RGBQUAD array to hold all colors of the bitmap?

typedef struct tagBITMAPINFO { // bmi
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD          bmiColors[1];
} BITMAPINFO;

So  nb should be calculated this way:

   nb = pbi->biSize + numColors*sizeof(RGBQUAD);

and the storage m_pbi points to should be big enough.

2. After FreeResource(hGlobal) the pointer pbi isn't valid anymore.

Regards, Alex
0
 

Author Comment

by:bignateyk
ID: 10658226
I guess what im having a hard time understanding is why this would be giving an error only when called inside of wndproc.  It is definatly a problem with the size of nb though.

Here are the functions I use:

------------------------------------------------------------------------------------------
static int BmiRowSize(const LPBITMAPINFOHEADER pbi)
{
    return ((pbi->biBitCount * pbi->biWidth) + 31) / 32 * 4;
}

//Used by SetImage
static int BmiColors(const LPBITMAPINFOHEADER pbi)
{
    int nColors = pbi->biClrUsed;
    if (nColors == 0) {
        nColors = (1 << pbi->biBitCount) & 0x1FF;
    }
    return nColors;
}

//used by SetImage
static size_t BmiSize(const LPBITMAPINFOHEADER pbi)
{
    size_t s = pbi->biSize + BmiColors(pbi) * sizeof (RGBQUAD);
    if (pbi->biSizeImage) {
        s += pbi->biSizeImage;
    } else {
        s += pbi->biHeight * BmiRowSize(pbi);
    }
    return s;
} // BmiSize

//used by SetImage
static BYTE* BmiFindBits(LPBITMAPINFOHEADER pbi)
{
    BYTE* lp = (BYTE*)pbi;
    return lp + pbi->biSize + BmiColors(pbi) * sizeof (RGBQUAD);
} // BmiFindBits

//Function to get a bitmap out of memory
void SetImage(LPBITMAPINFOHEADER pbi)
{
      
    if (m_pbi) {
        free(m_pbi); m_pbi = NULL; m_lpbits = NULL;
    }
      
    if (pbi) {
        size_t nb = BmiSize(pbi);
        m_pbi = (LPBITMAPINFOHEADER)malloc(nb);
        memcpy(m_pbi, pbi, nb);
        m_lpbits = BmiFindBits(m_pbi);
    }

}
---------------------------------------------------------------------------------

both m_lpbits and m_pbi are global variables

setImage is called after I have an image in memory...
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10660064
There might be two causes for the crash:

1. The pointer pbi isn't valid (maybe because memory has been freed or because a GDI
   function allocated a new storage).
2. The length 'nb' isn't properly calculated.

That part of your code is strange for me:

    if (pbi->biSizeImage) {
        s += pbi->biSizeImage;
    } else {
        s += pbi->biHeight * BmiRowSize(pbi);
    }

I couldn't verify from MSDN that the size could be calculated this way.

Look at declaration of BITMAPINFO

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER    bmiHeader;
    RGBQUAD             bmiColors[1];
} BITMAPINFO;

Here, the array bmiColors is determined by member biClrUsed (or biBitCount) and i couldn't see that the bitmap bits as declared in struct BITMAP have been appended to that info struct.

Also the calculation of numColors seems to be strange:

>> //Used by SetImage
>> static int BmiColors(const LPBITMAPINFOHEADER pbi)
>> {
>>    int nColors = pbi->biClrUsed;
>>    if (nColors == 0) {
>>        nColors = (1 << pbi->biBitCount) & 0x1FF;
>>    }
>>    return nColors;
>> }

Just in case pbi->ClrUsed == 0 then nColors = (1 << pbi->biBitCount) & 0x1FF;

However pbi->biBitCount is 0, 4, 8, 16, 24 or 32  and i suppose it's one of the last three values giving 2^16, 2^24 or 2^32 With & 0x1FF you got 0, 0 and 1 as result, what couldn't be right.

Regards, Alex

0
 

Author Comment

by:bignateyk
ID: 10661547
originally when it worked, I had the call to test() before it ever ran the main message loop:

      // Main message loop:
      
      while (GetMessage(&msg, NULL, 0, 0))
      {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
            }
      }

Since test() is a while loop, it didnt ever run the main message loop.

Now that I have it inside of wndProc, it is running that main message loop before.  This is the only difference I can think of.

I see your points about the code, but it worked fine before, which leads me to believe that the code itself is ok.

I think there is something wrong with the memory for pbi, like you said.  I'm just not sure what would be causing the difference.

0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10661688
>> I think there is something wrong with the memory for pbi, like you said.  

A wrong memory could cause a function to crash if called in a context that uses a lot of heap storage as within a message loop. The same function might work in a user context where a memory that has been freed still has a valid contents as it got not overwritten by a concurrent memory request.

Try to debug watch into the pbi and nb variable, once called from InitInstance and once called from WndProc and check for invalid pointers or overwritten structs.

Regards, Alex
0
 

Author Comment

by:bignateyk
ID: 10663774
ok, after some more debugging, I have narrowed it down to this:

I am using the logitech quickcam SDK to work with a webcam, and there is a call:

-----------------------------------------------------------------------------
pBuffer = (BYTE*)malloc(lSize); // allocate buffer
gpVideo->PictureToMemory(0, 24, (long)pBuffer, &lSize, NULL, &lResult );
LPBITMAPINFOHEADER pbi = (LPBITMAPINFOHEADER)(pBuffer + sizeof (BITMAPFILEHEADER));
SetImage(pbi);
free(pBuffer);
----------------------------------------------------------------------------

PictureToMemory is the logitech SDK function that takes a frame from the webcam and puts in into memory.  I am sure that the value of lSize is correct that I am giving it.

When used in WndProc, pBuffer is filled with garbage after the logitech SDK call.  When used in initinstance, it is fine.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 10665695
With Google i found that you can get correct lSize by a call of

     gpVideo->PictureToMemory(0, 24, NULL, &lSize, NULL, &lResult );

passing a NULL buffer.

If you got lSize you should pass it as an argument to SetImage.

//Function to get a bitmap out of memory
void SetImage(LPBITMAPINFOHEADER pbi, long lSize)
{
     
    if (m_pbi) {
        free(m_pbi); m_pbi = NULL; m_lpbits = NULL;
    }
     
    if (pbi) {
        size_t nb = (size_t)lSize;  // BmiSize(pbi);
        m_pbi = (LPBITMAPINFOHEADER)malloc(nb);
        memcpy(m_pbi, pbi, nb);
        m_lpbits = BmiFindBits(m_pbi);
    }

}

Then, i found this sample function:

void mexFunction( int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[] )
{
      using namespace quickcam;
      CoInitialize(NULL);

      IVideoPortalPtr spCam;
      testhr( spCam.CreateInstance( CLSID_VideoPortal), "Couldn't instantiate coclass." );

      try
      {
            long res = 0;
            testhr( spCam->ConnectCamera2(&res), "ConnectCamera2 call failed." );
            if (res == 0) mexErrMsgTxt( "connect to cam failed." );

            long width = 640;
            long height = 480;
            testhr( spCam->SetVideoFormat( width, height, 24, 0, &res ), "SetVideoFormat call failed." );
            if (res == 0) mexErrMsgTxt( "failed to set video format." );

            long size = 0;
            testhr( spCam->PictureToMemory( 0, 24, NULL, &size, _bstr_t(), &res ),
                  "PictureToMem call failed." );
            if (res == 0) mexErrMsgTxt( "couldn't get image size." );

            void* buf = mxMalloc( size );
            testhr( spCam->PictureToMemory( 0, 24, long(buf), &size, _bstr_t(), &res ),
                  "PictureToMem call(2) failed." );
            if ( res == 0 ) mexErrMsgTxt( "couldn't grab image." );

            plhs[0] = mxCreateNumericMatrix( height, width*3, mxUINT8_CLASS, mxREAL );
            char* pData = (char*) mxGetData( plhs[0] );

            char* pSrc = 54 + (char*)( buf );
            for (int y = 0; y < height; y++)
            {
                  for (int x = 0; x < width; x++)
                  {
                        long offset = x * height + y;
                        pData[ offset ] = pSrc[0];
                        pData[ offset + width * height ] = pSrc[1];
                        pData[ offset + 2 * width * height ] = pSrc[2];
                        pSrc += 3;
                  }
            }

      }
      catch (_com_error& ex)
      {
            mexErrMsgTxt( (char*)_bstr_t(ex.ErrorMessage()) );
      }

      plhs[0] = mxCreateDoubleMatrix( 1, 1, mxREAL );
      *(mxGetPr(plhs[0])) = 1;
}

You can see from

    char* pSrc = 54 + (char*)( buf );

that there is an offset of 54 bytes to bitmap data.

I checked the sizes of all bitmap structures; none of them has 54 bytes:

   BITMAP                      24
   BITMAPINFOHEADER  40
   BITMAPINFO              44       or 40 + numColors * 4
   BITMAPFILEHEADER   14
   BITMAPCOREHEADER 12
   BITMAPCOREINFO      16       or 12 + numColors * 4

The best guess to get an offset of 54 is a BITMAPFILEHEADER +  BITMAPINFOHEADER. Maybe you should check your LogiTech SDK docu for more information.

Hope, that helps

Alex  


0
 

Author Comment

by:bignateyk
ID: 10667964
unfortunatly the logitech sdk is notoriously poorly documented and supported.

I am using that first function to get the size, but I wasnt passing it into setimage.  The problem is that the call to picturetomemory fills pBuffer with garbage.  Ill have a look at your second function and see if theres anything in there.

thanks.
0
 
LVL 39

Accepted Solution

by:
itsmeandnobodyelse earned 250 total points
ID: 10670474
>> I am using that first function to get the size, but I wasnt passing it into setimage

Even if pBuffer contains garbage the size info of PictureToMemory is most likely correct. So, if you are calculating a different size, there are only two bad choices:

1. The calculated size is less than the buffer size. Then, you copy less memory than pBuffer contains
     and the copied bitmap most likely is corrupted.
2. The calculated size is bigger than the buffer size and you are copying from unallocated memory.
    That can make your program crash if you try to access protected memory.

I would suggest not to copy at all, just take the buffer as is:

    m_pbi = (LPBITMAPINFOHEADER)pbi;

However, you have to remove the

         free(buffer);

statement below the SetImage(...) call.

Regards, Alex
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

739 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question