Solved

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

Posted on 2004-03-21
16
514 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
  • 8
  • 6
16 Comments
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
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
Comment Utility
how would you suggest I call a function after receiving data from WM_COPYDATA?
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility


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
 

Author Comment

by:bignateyk
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 39

Expert Comment

by:itsmeandnobodyelse
Comment Utility
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
Comment Utility
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
Comment Utility
>> 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
>> 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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

771 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now