我写了一个基于CListCtrl的类CXXXListCtrl
然后用classwizard给这个类添加ON_WM_CREATE消息处理
但是跟踪发现程序运行起来根本没有进过
int CXXXListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)这个函数
难道CXXXListCtrl的ON_WM_CREATE没有得到响应吗?
请教

解决方案 »

  1.   

    似乎在对话框上码的就不行,对话框不处理它上面的控件的create,手工create的就行。不知道有什么解决办法
      

  2.   

    在对话框中通常需要把初始化工作放到 OnInitDialog 中
      

  3.   

    To dandycheung(珠穆朗玛):
    我知道,但我想尽量把这些东西封到listctrl里面,用这个控件的人最好不要做额外的工作
      

  4.   

    你需要重载 PreSubclassWindow() 函数。详细的信息,建议你到 MSDN 里以 PreSubclassWindow 关键字查询,在得到的结果里有一条应该是 2002 年 3 月份 MSDN Magazine 的 C++ Q & A 专栏,其标题为“Do You Have a License for that GIF? PreSubclassWindow, EOF in MFC, and More”。
      

  5.   

    Do You Have a License for that GIF? PreSubclassWindow, EOF in MFC, and More 
    --------------------------------------------------------------------------------
     
    Paul DiLascia C++ Q&A Archive 
     
    Download the code for this article: C0203.exe (383KB)
     

    fter my October 2001 column in which I showed how to use IPicture to display GIF and JPEG images, a number of readers sent e-mail asking whether they had to pay royalties to display GIF images. As many of you are aware (and as many of you are no doubt unaware), the Lempel Ziv Welch (LZW) algorithm used in the GIF format is patented by Unisys Corporation. If your program reads or writes GIF images, the law may require you to license the patent from Unisys.
    To get the full scoop, I went to http://www.unisys.com. Unfortunately, I could not decipher, even after several readings, the circumstances under which a developer would be required to pay a fee. If you're writing a GIF-to-BMP converter, do you have to pay? (Most likely.) What if all you do is display a GIF image in your About dialog? The issue is complicated by the fact that you may be using a commercial product that's already licensed the algorithm. To get clarification, I sent e-mail to the folks at Unisys. A few days later I received a Word document, a boilerplate questionnaire asking me about my application. When I reminded them I was wearing my writer's cap, not writing an application, I got a polite answer that amounted to: it's very complicated, and would I like to talk to their lawyers?
    What about Microsoft? Do the friendly Redmondtonians have anything to say about this? Knowledge Base article Q193543 says:Microsoft has obtained a license from Unisys to use the .gif file format and other LZW technologies covered by the Unisys-owned U.S. and foreign patents in a number of Microsoft products.
    However, this license does not extend to third-party developers using Microsoft development products to develop applications. Third-party developers must have a license from Unisys in the form of a written agreement. For more information...
    So the upshot is that, unfortunately, I can't give you any help. If you're writing a program that reads or writes GIFs, you should go to the Unisys site and try to decipher it yourself. The folks at Unisys will be happy to give you their lawyers' phone number. Needless to say, the whole GIF/LZW patent thing has created quite a controversy, one that stirs the hearts of free software libertarians around the planet. You can check out http://lzw.info for a quick overview or search the Web for "LZW patent".Q I have a subclass of CListBox. In order for it to provide its specialized behavior, the listbox must be owner-drawn. I overrode the virtual function PreCreateWindow to force the LBS_OWNERDRAWFIXED style to be set. This works fine if I create the listbox myself. If the listbox is part of a dialog loaded from a resource, PreCreateWindow is never called. How do I ensure the LBS_OWNERDRAWFIXED style is set in this case?Frank LagattutaA The short answer is: use PreSubclassWindow.
    The long answer follows. PreCreateWindow is a special CWnd virtual function that MFC calls, as you might guess, just before creating a window. When you call CWnd::Create or CWnd::CreateEx to create a window, MFC calls CWnd::PreCreateWindow before invoking Windows® to actually create your window for you.BOOL CWnd::CreateEx(...)
    {
      CREATESTRUCT cs;
      •••
      // init cs  if (!PreCreateWindow(cs)) {
        PostNcDestroy();
        return FALSE;
      }
      •••
      // create the window  return TRUE;
    }But dialogs aren't created in this fashion. Dialogs are created when you call CDialog::DoModal, in which case MFC loads your dialog template using ::CreateDlgIndirect, which is roughly equivalent to ::DialogBox. Either way, Windows creates the controls internally—CWnd::CreateEx is never invoked. So your control's PreCreateWindow never gets called.
    But when you connect your control to a CWnd-derived object instance, such as your specialized listbox, you have to call SubclassDlgItem, which calls SubclassWindow, and here MFC calls another specialized virtual function, PreSubclassWindow. This is your big chance in life to do things like change the style.void CMyListBox::PreSubclassWindow()
    {
      // turn on owner-draw
      ModifyStyle(0,LBS_OWNERDRAWFIXED);
    }In fact, PreSubclassWindow is the preferred place to do stuff like this because MFC also calls PreSubclassWindow when you create a window with CreateEx. In other words, PreSubclassWindow covers both cases—dialog or standalone creation—so if you set the style in PreSubclassWindow, you don't need to do it in PreCreateWindow, too.Q I'm using the CFile class in my app and I know how to open, write, and close the file using this class, but I don't know (as is most important) how to read the file at its end (EOF). I'm handling CFileException::endOfFile, but I get an infinite loop.Alessandro ChiodoA It does seem odd, doesn't it? I mean, when you read to the end of the file, you'd expect to get an end-of-file exception, right? What else would an endOfFile exception be good for? But as it turns out, MFC doesn't use CFileException::endOfFile in this case. To check for end-of-file, you have to test whether the number of bytes actually read is less than the number of bytes you requested.CFile file;
    file.Open();
    char mybuf[BUFSIZ];
    UINT nread;
    do (nread=file.read(buf, BUFSIZ)) {
      •••
    // process nread bytes} while (nread==BUFSIZ);It may seem strange to do it this way, but hey—I don't make the rules; I just report 'em.Q I want to debug a program I wrote in C++ that triggers from another application. Consider the following:
     
      

  6.   

    AppA -> calls plugin B -> calls my.dllI have no source code available for AppA or the plugin—only my.dll. I want to debug my.dll when called from AppA. How do I do this?Chamika GunathilakaA It's easy. In Visual Studio®, just go to Project | Settings and select the Debug tab. Normally, Visual Studio fills "executable for debug session" with the name of your executable, but you can enter any program you want. For example, you could use c:\SomeDir\AppA.exe. You can even specify a different working directory and arguments to pass to your program. Figure 1 shows the details. This technique is commonly used to debug DLLs, namespace extensions, COM objects, and other plug-ins invoked from some EXE other than your own.
    Figure 1 Debugging One App through AnotherQ I recently read your column describing a class called CPicture. It was most helpful, and is exceptionally easy to use. I am wondering if two problems that I am trying to solve could be handled as easily. I want to display JPGs, but in some cases I want to be able to rotate the display 90 degrees. Also, I'd like to be able to generate small bitmaps that could be used as thumbnail images in a list.Dan ByronA Well, I'm glad my class was so helpful. Now I suppose after flattering me, you expect me to answer your question, eh? Tell me, why do you want to rotate the image? Can't you tell the user to rotate his head? Do they expect you to do everything?
    OK, OK. You don't want your customers breaking their necks and filing a class action suit, so let's try to figure this thing out. One way to rotate is to map the pixels yourself. That is, represent the rotation as a matrix transformation in x,y space  cos A -sin A  sin A  cos Awhich, if you remember from high school trigonometry (the advanced course) or college linear algebra, means that if you have a point (x,y), the rotated point is (x*cos(A) + y*sin(A), -x*sin(A) + y*cos(A)), where A is the angle in radians (2p radians = 360 degrees). So you just load your bitmap, select it into a device context and call GetPixel and SetPixel to map all the pixels as described, and like magic you have your rotated image. It's not as bad as it seems for rotations by 90, 180, or -90 degrees, since then the sines and cosines are all +/-1 or 0.
    Still, I know what you're thinking. "No.... Please don't make me do all that! There's got to be a better way!" Well, you're right; there is. The cure for your rotation blues is GDI+. In case you've fallen behind a couple of years in your MSDN® Magazine reading (time flies, I know), GDI+ is the enhanced version of the GDI graphics library, accessible through C++. GDI+ is built into Windows XP and Microsoft .NET, but there's a redistributable for Windows 98, Windows NT®, and Windows 2000. (See http://www.microsoft.com/msdownload/ platformsdk/sdkupdate/psdkredist.htm.)
    GDI+ is a C++ API. It uses C++ classes and methods. To use GDI+ you have to #include <gdiplus.h> and link your project with gdiplus.lib, both of which are part of the latest Windows SDK. GDI+ is much more than I can describe in a wee column here; however, I did rewrite the ImgView program from my October 2001 column into a new program, ImgView2, which shows how to use GDI+ to rotate an image (see Figure 2).
    Figure 2 Rotating in ImgViewThe October column provided a class, CPicture, based on IPicture, the COM interface for manipulating an image. For ImgView2, I rewrote CPicture to use the Image class from GDI+. The conversion was relatively straightforward given that everything was already encapsulated in classes. Once I mapped CPicture to use Image instead of IPicture, all the other classes such as CPictureView and CPictureCtrl worked as before. Naturally, there were a couple of snags.
    The first thing, not a snag really but just a GDI+ requirement, is that you have to initialize and terminate the GDI library. The best place is in your app's InitInstance and ExitInstance functions (see Figure 3). CMyApp::m_gdiplusToken is a magic cookie you get from GdiplusStartup and pass to GdiplusShutdown; m_gdiplusStartupInput is a struct that holds some GDI+ startup parameters, the default constructor for which establishes intelligent default values, demonstrating once again that C++ is better than C.
    Once you've turned on GDI+, you can use it. The old CPicture held a pointer to IPicture; the new one holds a pointer to an Image. As before, there are overloaded Load functions to load a picture from various sources. For example, here's how the new CPicture loads from a path name:BOOL CPicture::Load(LPCTSTR pszPathName)
    {
      Free();
      USES_CONVERSION;
      m_pImage = Image::FromFile(A2W(pszPathName),
        m_bUseEmbeddedColorManagement);
      return m_pImage->GetLastStatus()==Ok;
    }
      

  7.   

    The main thing here is GDI+ uses wide strings, so you need USES_CONVERSION and A2W. The old CPicture had Load functions to load an image from a CFile, CArchive, resource ID, or stream. All the load functions eventually went to CPicture::Load(IStream*), the one that loads from a stream. But when I began to use Images instead of IPicture, using a GDI+ function to load from streams, nothing worked. Too bad, so sad. The problem turned out to be MFC's CArchiveStream class, the one that implements a stream on a CArchive (see last month's column. For whatever reason—probably CArchiveStream doesn't implement all the IStream methods properly—Image::FromStream doesn't work with a stream based on CArchiveStream. Worst of all, it reports OK, but fails later when you try to display or delete the Image.
    To work around this, I rewrote CPicture::Load(UINT nID) to use CreateStreamOnHGlobal. This handy API function creates a stream on a block of global memory.// Allocate global memory on which to create stream
    HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
    BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
    memcpy(pmem,lpRsrc,len);
    IStream* pstm;
    CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);Here lpRsrc already points to the image resource in memory. So the basic idea is to load the image resource, copy it into global memory, create a stream on the memory, and then use Image::FromStream to create an Image. Figure 4 shows the details. CPicture automatically frees the global memory when the object is destroyed or someone loads a different picture. As for loading from CFile or CArchive—well, I never really needed those anyway.
    So much for loading an Image. To display it, you have to use another GDI+ class, Graphics—like a device context (HDC or CDC) in the old GDI—and one of its methods, DrawImage.BOOL CPicture::Render(CDC* pDC, CRect rc) const
    {
      &#8226;&#8226;&#8226;
      Graphics graphics(pDC->m_hDC);
      graphics.DrawImage(m_pImage,
        rc.left, rc.top, rc.Width(), rc.Height());
    }The full details are in Figure 4. Rendering is simpler with Images instead of IPicture: Image::GetWidth and Image::GetHeight get the width and height in pixels, which is what you want instead of the HIMETRIC units you get with IPicture. In general, GDI+ is pretty easy to program. For example, here's how to rotate.void CPicture::Rotate(RotateFlipType rft)
    {
      if (m_pImage) {
        m_pImage->RotateFlip(rft);
      }
    }This rotates the image 90 degrees clockwise. Figure 5 shows the full possibilities for RotateFlipType. GDI+ has other functions to stretch and shear an image. There's even a function Image::GetThumbnailImage to solve your thumbnail problem, which I'll leave for you as a homework exercise.
    I encourage you to explore GDI+. Some programmers don't like it because it's slow, but the documentation has some tips for improving performance. For example, there's a CachedBitmap class that holds a bitmap in a device-optimized format. You probably wouldn't use GDI+ for graphics-intensive applications like a video game or high-end image editor (for those you can use DirectX&reg;), but for everyday graphics tasks, it's a big improvement over GDI.
    Ciao!Send questions and comments for Paul to [email protected]..
     --------------------------------------------------------------------------------
    Paul DiLascia is a freelance writer, consultant, and Web/UI designer-at-large. He is the author of Windows++: Writing Reusable Windows Code in C++(Addison-Wesley, 1992). Paul can be reached at [email protected] or http://www.dilascia.com.