Link to home
Start Free TrialLog in
Avatar of bignateyk
bignateyk

asked on

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

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
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

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
Avatar of bignateyk
bignateyk

ASKER

how would you suggest I call a function after receiving data from WM_COPYDATA?


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


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



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
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
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...
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

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.

>> 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
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.
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  


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.
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial