/* GeneticImages.cpp * J Scott Cameron * Windows GUI for Genetic Images */ #include "ParentContainer.h" #include #include #include #include #include #include #include "resource.h" /* population window size and division settings, don't change*/ #define SUBDIVIDE 8 #define WIDTH 80 #define HEIGHT 80 /* index for selected image*/ int selected = 0; /* handle to the selected bitmap */ HBITMAP selectedBM; HINSTANCE hInst; /* handle to main apps handle */ HWND g_hWnd; /* handle to population window */ HWND pa_wnd; /* handle to parent window */ int iCmd; int bitmapWidth,bitmapHeight; /* main population container */ PopulationContainer pc; /* map of all the Node Viewers and their associated Node Containers*/ map nodeMap; /* parent container */ ParentContainer parents(&pc); /* handle for parent window */ HWND parentWnd; bool parent_visible = false; /* Windows structs for opening and saving files */ static OPENFILENAME ofn; static OPENFILENAME bmOfn; static char szFileName[_MAX_PATH]; static char szTitleName[_MAX_FNAME + _MAX_EXT]; /* function to update all the bitmaps */ void UpdateMaps(); /* Window/Dialog Procedure Callback functions * these control the effects that actions within their * have. This is where all the heavy lifting in the application * is done */ /*Population(Main) Window*/ LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; /* Node View Window(s) */ LRESULT CALLBACK ViewerWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); /* Parent Window */ LRESULT CALLBACK ParentWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); /* Create new Populaiton Dialog */ BOOL CALLBACK CreatePopDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); /* Set Bitmap size Dialog*/ BOOL CALLBACK SetSizeDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); /* draws a bitmap to the given device context */ void DrawBitmap(HDC hdc, HBITMAP hBitmap, int xStart, int yStart); /* generates a bitmap from the given node */ HBITMAP getBitmapFromNode(Node* node,int xSize,int ySize); /* functions that call Windows Save/Open dialog boxes */ void GenFileInitialize(HWND ); BOOL GenFileOpenDlg(HWND , PSTR pstrFileName, PSTR pstrTitleName); BOOL GenFileSaveDlg(HWND , PSTR pstrFileName, PSTR pstrTitleName); BOOL BmpFileSaveDlg(HWND , PSTR pstrFileName, PSTR pstrTitleName); /* Windows funcitons for creaing bitmaps */ PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp); void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC) ; /* The main application function */ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static char szAppName[] = "Genetic Images" ; HWND hwnd ; MSG msg ; WNDCLASSEX wndclass ; ////////// Begin Population creation///////////// pc.init(); ///////// End Population Creation //////// /* initialize the main window */ wndclass.cbSize = sizeof (WNDCLASSEX) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = "PopulationMenu" ; wndclass.lpszClassName = szAppName ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; RECT client; client.top=0; client.left=0; client.right=SUBDIVIDE*WIDTH; client.bottom = SUBDIVIDE*HEIGHT; AdjustWindowRect(&client,WS_OVERLAPPEDWINDOW,true); /* create the main window */ hwnd = CreateWindow (szAppName, "Genetic Images", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, client.right-client.left,client.bottom-client.top, NULL, NULL, hInstance, NULL) ; g_hWnd = hwnd; hInst = hInstance; iCmd = iCmdShow; /* show window */ ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; /* initialize windows dialogs */ GenFileInitialize(g_hWnd); /* go into loop checking for messages */ while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } /* draws the bitmap to the screen */ void DrawBitmap(HDC hdc, HBITMAP hBitmap, int xStart, int yStart) { BITMAP bm; HDC hdcMem; // DWORD dwSize; POINT ptSize, ptOrg; hdcMem = CreateCompatibleDC(hdc); /* select bitmap into a memory context*/ SelectObject(hdcMem, hBitmap); SetMapMode (hdcMem, GetMapMode(hdc)); GetObject(hBitmap, sizeof(BITMAP), (LPVOID) &bm); ptSize.x = bm.bmWidth; ptSize.y = bm.bmHeight; DPtoLP(hdc,&ptSize,1); ptOrg.x =0; ptOrg.y = 0; DPtoLP(hdcMem,&ptOrg,1); /* blit from bitmat memory context to screen memory context */ BitBlt(hdc, xStart, yStart,ptSize.x,ptSize.y, hdcMem, ptOrg.x,ptOrg.y,SRCCOPY); DeleteDC(hdcMem); } /* creates a bitmap compatible to the given device context */ HBITMAP MakeCompatibleBitmap(HDC hdc, HBITMAP hBmp) { BITMAP bmp; GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp); /* fill a bitmap struct with appropriate info */ PBITMAPINFO pBitInfo = CreateBitmapInfoStruct(g_hWnd, hBmp); PBITMAPINFOHEADER pbih; pbih = (PBITMAPINFOHEADER) pBitInfo; /* create the new bitmap */ HBITMAP dib = CreateDIBitmap(hdc,pbih,CBM_INIT,bmp.bmBits,pBitInfo,0); HDC newHdc = CreateCompatibleDC ( hdc ); HBITMAP newhBmp = CreateCompatibleBitmap(hdc, bmp.bmHeight,bmp.bmHeight); SelectObject ( newHdc, newhBmp ); DrawBitmap(newHdc,dib,0,0); /* cleanup */ DeleteObject(dib); DeleteObject(hBmp); DeleteDC(newHdc); return newhBmp; } /* iterates through all the images and draws them to the window */ void DrawMaps(HDC hdc) { for(int i = 0; in == NULL) { MessageBox(hwnd,"Failure to open File","Error",NULL); } HWND childWnd; /* initialize a window to hold the image */ WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (WNDCLASSEX) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = ViewerWndProc; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInst ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); wndclass.lpszMenuName = "ImageMenu" ; wndclass.lpszClassName = "Node Viewer" ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; RECT client; client.top=0; client.left=0; client.right=200; client.bottom = 200; AdjustWindowRect(&client,WS_OVERLAPPEDWINDOW,true); /* create the window */ childWnd = CreateWindow ("Node Viewer", "Node Viewer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, client.right-client.left,client.bottom-client.top, NULL, NULL, hInst, NULL) ; /* save the window handle to the map so we know who * belongs to who */ nodeMap.insert(map::value_type(childWnd,nc) ); ShowWindow (childWnd, iCmd) ; UpdateWindow (childWnd) ; } return 0; case GP_EXIT: /* exit app */ SendMessage (hwnd, WM_CLOSE, 0, 0L); return 0; case GP_NEW_POPULATION: /* reset the population */ pc.reset(); InvalidateRect(hwnd,NULL,TRUE); return 0; case GP_NEW_PARENT: /* open the parent window */ if(!parent_visible) /* check to make sure it's not already * showing */ { /* initialize a window for the parent container */ WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (WNDCLASSEX) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = ParentWndProc; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInst ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = "ParentMenu" ; wndclass.lpszClassName = "Parent Library" ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; RECT client; client.top=0; client.left=0; client.right=240; client.bottom = 80; AdjustWindowRect(&client,WS_OVERLAPPEDWINDOW | WS_HSCROLL,true); /* create the window */ parentWnd = CreateWindow ("Parent Library", "Parent Library", WS_OVERLAPPEDWINDOW | WS_HSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, client.right-client.left,client.bottom-client.top, NULL, NULL, hInst, NULL) ; /* show the window */ ShowWindow (parentWnd, iCmd) ; UpdateWindow (parentWnd) ; parent_visible =true; } return 0; case GP_ABOUT: /* displays a rather lame "about" box */ MessageBox(hwnd, "Genetic Images - J Scott Cameron", "Genetic Images", MB_ICONINFORMATION | MB_OK); return 0; } return 0; case WM_LBUTTONDOWN :/* an image has been chosen! * generate a new population * from its mutant children */ m_x = LOWORD(lParam); m_y = HIWORD(lParam); m_x/=WIDTH;m_y/=HEIGHT; if((m_x < SUBDIVIDE) && (m_y trees[m_x*SUBDIVIDE+m_y])); HWND childWnd; /* initialize a new window to hold the image */ WNDCLASSEX wndclass ; wndclass.cbSize = sizeof (WNDCLASSEX) ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = ViewerWndProc; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInst ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = "ImageMenu" ; wndclass.lpszClassName = "Node Viewer" ; wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ; RegisterClassEx (&wndclass) ; RECT client; client.top=0; client.left=0; client.right=200; client.bottom = 200; AdjustWindowRect(&client,WS_OVERLAPPEDWINDOW,true); /* create the window */ childWnd = CreateWindow ("Node Viewer", "Node Viewer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, client.right-client.left,client.bottom-client.top, NULL, NULL, hInst, NULL) ; /* record the handle for future reference */ nodeMap.insert( map::value_type(childWnd,nc) ); /* show the window */ ShowWindow (childWnd, iCmd) ; UpdateWindow (childWnd) ; } case WM_SIZE: /* nothing happens on resize */ cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; return 0 ; case WM_PAINT: /* redraw all the images */ hdc = BeginPaint (hwnd, &ps) ; DrawMaps(hdc); EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: /* destroy the app */ PostQuitMessage (0) ; return 0 ; } /* catch any unused commands with default window procedure*/ return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } /* Node viewer procedures */ LRESULT CALLBACK ViewerWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc ; /* reference to windows spot in the Node View map */ map::iterator itr; /* menu handle */ HMENU hMenu; /* equation to create image */ string equation; PAINTSTRUCT ps ; switch (iMsg) { case WM_COMMAND: hMenu = GetMenu (hwnd); switch(LOWORD(wParam)) { case GI_SAVE : /* save the equation to file */ /* find this windows node Container */ itr = nodeMap.find(hwnd); if(itr != nodeMap.end()) { /*use a Platform Save Dialog to get file path*/ if(GenFileSaveDlg(hwnd,szFileName,szTitleName)) /* save if a file name is given */ {(*itr).second->save(szFileName); } } return 0; case GI_EXIT: /* kill window */ SendMessage (hwnd, WM_CLOSE, 0, 0L); return 0; case GI_VIEW_EQUATION: /* opens a message box *that shows equation */ itr = nodeMap.find(hwnd); if(itr != nodeMap.end()) { equation = (*itr).second->n->print(); for(int i=80;iwidth; bitmapHeight = (*itr).second->height; /*query user for dimensions of bitmap*/ DialogBox (hInst, "SETSIZE", hwnd,SetSizeDlgProc) ; /* create new bitmap of given dimensions*/ HBITMAP newBitmap = (*itr).second-> pc->getBitmapFromNode( (*itr).second->n, bitmapWidth,bitmapHeight,0,0,1,1); PBITMAPINFO bitInfo = CreateBitmapInfoStruct( hwnd,newBitmap); /* use Platform Save Dialog to get path/name */ if(BmpFileSaveDlg(hwnd,szFileName,szTitleName)) /* save the file */ {CreateBMPFile(hwnd,szFileName, bitInfo, newBitmap,GetDC(hwnd)); } /* delete temporary bitmap from memory*/ DeleteObject(newBitmap); } } return 0; } return 0; case WM_PAINT:/* repaint bitmap */ hdc = BeginPaint (hwnd, &ps) ; /* find this window's node Container */ itr = nodeMap.find(hwnd); /* if the iterator is valid, draw the bitmap */ if(itr != nodeMap.end()) { DrawBitmap(hdc,(*itr).second->bitmap,0,0); } EndPaint (hwnd, &ps) ; return 0; case WM_SIZE: /* redraw the bitmap with new dimensions */ /* find this window's node Container */ itr = nodeMap.find(hwnd); /* if the iterator is valid, resize/draw the bitmap */ if(itr != nodeMap.end()) { (*itr).second->changeSize( LOWORD (lParam), HIWORD (lParam)); InvalidateRect(hwnd,NULL,TRUE); } return 0 ; case WM_DESTROY: /* kill the window */ /* find this window's node Container */ itr = nodeMap.find(hwnd); /* if the iterator is valid then destroy the node * container, bitmap and pull the window from * the map */ if(itr != nodeMap.end()) { DeleteObject( (*itr).second->bitmap ); delete( (*itr).second); nodeMap.erase(itr); } return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } /* Parent window procedure */ LRESULT CALLBACK ParentWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDC hdc ; HMENU hMenu; static int HScroll; /* scrollbar */ PAINTSTRUCT ps ; switch (iMsg) { case WM_COMMAND: hMenu = GetMenu (hwnd); switch(LOWORD(wParam)) { case GPA_LOAD : /* load an image from file */ if(GenFileOpenDlg(hwnd,szFileName,szTitleName)) { /* create a node container */ NodeContainer* nc = new NodeContainer(&pc, szFileName,80,80); if(nc->n == NULL) { MessageBox(hwnd, "Failure to open File", "Error",NULL); } /* show new image */ nc->updateMap(); /* add node to parent container */ parents.addNode(nc); /* update scrollbar */ SetScrollRange(hwnd,SB_HORZ,0,parents.ncs.size()-1, true); SetScrollPos(hwnd,SB_HORZ,0,true); InvalidateRect(hwnd,NULL,TRUE); } return 0; case GPA_EMPTY: /* empty the parent container */ { parents.emptyContainer(); InvalidateRect(hwnd,NULL,TRUE); } return 0; case GPA_CREATE_NEW_POP: /* generate a new population*/ /* if there's some one in the window...*/ if(parents.ncs.size()>0) { /* call the Create Population Dialog to get info * from user */ DialogBox (parents.hinstance, "CreatePopulation", hwnd, CreatePopDlgProc) ; /* regenerate population using this info*/ parents.generateNewPopulation(); InvalidateRect(g_hWnd,NULL,TRUE);} else /* if the window is empty, complain */ { MessageBox(hwnd, "You must have at least one\n specimen in the library", "Error",NULL); } return 0 ; case GPA_EXIT: /* close window */ SendMessage (hwnd, WM_CLOSE, 0, 0L); return 0; } return 0; case WM_CREATE: /* initialize window */ SetScrollRange(hwnd,SB_HORZ,0,1,true); SetScrollPos(hwnd,SB_HORZ,1,true); parents.hinstance = ((LPCREATESTRUCT) lParam)->hInstance; return 0; case WM_HSCROLL:/* take care of scrolling commands */ switch(LOWORD (wParam)) { case SB_LINEUP: HScroll -= 1; break; case SB_LINEDOWN: HScroll += 1; break; case SB_PAGEUP: HScroll -= 1; break; case SB_PAGEDOWN: HScroll += 1; break; case SB_THUMBPOSITION : HScroll = HIWORD(wParam); break; default: break; } if (HScroll != GetScrollPos(hwnd,SB_HORZ)) { SetScrollPos(hwnd, SB_HORZ,HScroll,TRUE); InvalidateRect(hwnd,NULL,TRUE); } return 0; case WM_PAINT:/* repaint the images */ hdc = BeginPaint (hwnd, &ps) ; int i,j; /* check to see what the scrollbar is showing */ for(i = GetScrollPos(hwnd,SB_HORZ) , j=0; ibitmap,j*80,0); } EndPaint (hwnd, &ps) ; return 0; case WM_DESTROY:/* kill the window */ parent_visible =false; return 0 ; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } /* Create Population Dialog Procedures */ BOOL CALLBACK CreatePopDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { string rate; switch (iMsg) { case WM_INITDIALOG: /* initialize the dialog with mutation on*/ parents.percMutation = .01f; parents.crossover =false; parents.mutate = true; CheckDlgButton(hDlg,GPA_MUTATION,BST_CHECKED); SetDlgItemText(hDlg,GPA_RATE,".01"); return TRUE; case WM_COMMAND : switch (LOWORD (wParam)) { case IDOK : case IDCANCEL : /*pull info from dialog */ GetDlgItemText(hDlg, GPA_RATE,(char*) rate.c_str() , 30); parents.percMutation = atof(rate.c_str()); EndDialog (hDlg, 0) ; return TRUE ; case GPA_MUTATION:/* handle clicks to the mutation checkbox*/ if(parents.mutate ){ parents.mutate = false; CheckDlgButton(hDlg,GPA_MUTATION,BST_UNCHECKED); } else{ parents.mutate = true; CheckDlgButton(hDlg,GPA_MUTATION,BST_CHECKED); } return TRUE; case GPA_CROSSOVER:/* handle clicks to the crossover checkbox*/ if(parents.crossover){ parents.crossover = false; CheckDlgButton(hDlg,GPA_CROSSOVER,BST_UNCHECKED); } else{ parents.crossover= true; CheckDlgButton(hDlg,GPA_CROSSOVER,BST_CHECKED); } return TRUE; } break ; } return FALSE; } /* Procedure for setting bitmap size */ BOOL CALLBACK SetSizeDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { case WM_INITDIALOG: /* initializes dialog with * the size of the current * bitmap */ SetDlgItemInt(hDlg,GI_WIDTH,bitmapWidth,TRUE); SetDlgItemInt(hDlg,GI_HEIGHT,bitmapHeight,TRUE); return TRUE; case WM_COMMAND : switch (LOWORD (wParam)) { case IDOK : case IDCANCEL : /* pull info from dialog */ bitmapWidth = GetDlgItemInt(hDlg,GI_WIDTH,NULL,TRUE); bitmapHeight = GetDlgItemInt(hDlg,GI_HEIGHT,NULL,TRUE); EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE; } /* initializes windows open/save file structs */ void GenFileInitialize(HWND hwnd) { static char szFilter[] = "Genetic Images (*.GI1)\0*.gi1\0"; ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner =hwnd; ofn.hInstance = NULL; ofn.lpstrFilter = szFilter; ofn.lpstrCustomFilter =NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = NULL; ofn.nMaxFile = _MAX_PATH; ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; ofn.lpstrInitialDir =NULL; ofn.lpstrTitle = NULL; ofn.Flags = 0; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = "gi1"; ofn.lCustData = 0L; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; static char szBmpFilter[] = "Bitmap (*.BMP)\0*.bmp\0"; bmOfn.lStructSize = sizeof(OPENFILENAME); bmOfn.hwndOwner =hwnd; bmOfn.hInstance = NULL; bmOfn.lpstrFilter = szBmpFilter; bmOfn.lpstrCustomFilter =NULL; bmOfn.nMaxCustFilter = 0; bmOfn.nFilterIndex = 0; bmOfn.lpstrFile = NULL; bmOfn.nMaxFile = _MAX_PATH; bmOfn.lpstrFileTitle = NULL; bmOfn.nMaxFileTitle = _MAX_FNAME + _MAX_EXT; bmOfn.lpstrInitialDir =NULL; bmOfn.lpstrTitle = NULL; bmOfn.Flags = 0; bmOfn.nFileOffset = 0; bmOfn.nFileExtension = 0; bmOfn.lpstrDefExt = "bmp"; bmOfn.lCustData = 0L; bmOfn.lpfnHook = NULL; bmOfn.lpTemplateName = NULL; } /* dialog for opening images as functions*/ BOOL GenFileOpenDlg(HWND hwnd, PSTR pstrFileName, PSTR pstrTitleName) { ofn.hwndOwner = hwnd; ofn.lpstrFile = pstrFileName; ofn.lpstrFileTitle = pstrTitleName; ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT; return GetOpenFileName(&ofn); } /* Dialog for save images as functions */ BOOL GenFileSaveDlg(HWND hwnd, PSTR pstrFileName, PSTR pstrTitleName) { ofn.hwndOwner = hwnd; ofn.lpstrFile = pstrFileName; ofn.lpstrFileTitle = pstrTitleName; ofn.Flags = OFN_OVERWRITEPROMPT; return GetSaveFileName(&ofn); } /* Dialog for saving images as bitmaps */ BOOL BmpFileSaveDlg(HWND hwnd, PSTR pstrFileName, PSTR pstrTitleName) { bmOfn.hwndOwner = hwnd; bmOfn.lpstrFile = pstrFileName; bmOfn.lpstrFileTitle = pstrTitleName; bmOfn.Flags = OFN_OVERWRITEPROMPT; return GetSaveFileName(&bmOfn); } /* error handler */ void errhandler(PSTR err, HWND hwnd) { MessageBox(hwnd,err,"Error",NULL); } /* Creates a bitmap header, taken from Microsoft Platform SDK*/ PBITMAPINFO CreateBitmapInfoStruct(HWND hwnd, HBITMAP hBmp) { BITMAP bmp; PBITMAPINFO pbmi; WORD cClrBits; // Retrieve the bitmap's color format, width, and height. if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) errhandler("GetObject", hwnd); // Convert the color format to a count of bits. cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); if (cClrBits == 1) cClrBits = 1; else if (cClrBits <= 4) cClrBits = 4; else if (cClrBits <= 8) cClrBits = 8; else if (cClrBits <= 16) cClrBits = 16; else if (cClrBits <= 24) cClrBits = 24; else cClrBits = 32; // Allocate memory for the BITMAPINFO structure. (This structure // contains a BITMAPINFOHEADER structure and an array of RGBQUAD // data structures.) if (cClrBits != 24) pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits)); // There is no RGBQUAD array for the 24-bit-per-pixel format. else pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); // Initialize the fields in the BITMAPINFO structure. pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbmi->bmiHeader.biWidth = bmp.bmWidth; pbmi->bmiHeader.biHeight = bmp.bmHeight; pbmi->bmiHeader.biPlanes = bmp.bmPlanes; pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; if (cClrBits < 24) pbmi->bmiHeader.biClrUsed = (1<bmiHeader.biCompression = BI_RGB; // Compute the number of bytes in the array of color // indices and store the result in biSizeImage. // For Windows NT/2000, the width must be DWORD aligned unless // the bitmap is RLE compressed. This example shows this. // For Windows 95/98, the width must be WORD aligned unless the // bitmap is RLE compressed. pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 * pbmi->bmiHeader.biHeight; // Set biClrImportant to 0, indicating that all of the // device colors are important. pbmi->bmiHeader.biClrImportant = 0; return pbmi; } /* creates a Bitmap File, take from Microsoft Platform SDK*/ void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC) { HANDLE hf; // file handle BITMAPFILEHEADER hdr; // bitmap file-header PBITMAPINFOHEADER pbih; // bitmap info-header LPBYTE lpBits; // memory pointer DWORD dwTotal; // total count of bytes DWORD cb; // incremental count of bytes BYTE *hp; // byte pointer DWORD dwTmp; pbih = (PBITMAPINFOHEADER) pbi; lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); if (!lpBits) errhandler("GlobalAlloc", hwnd); // Retrieve the color table (RGBQUAD array) and the bits // (array of palette indices) from the DIB. if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih->biHeight, lpBits, pbi, DIB_RGB_COLORS)) { errhandler("GetDIBits", hwnd); } // Create the .BMP file. hf = CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL); if (hf == INVALID_HANDLE_VALUE) errhandler("CreateFile", hwnd); hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M" // Compute the size of the entire file. hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; // Compute the offset to the array of color indices. hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed * sizeof (RGBQUAD); // Copy the BITMAPFILEHEADER into the .BMP file. if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL)) { errhandler("WriteFile", hwnd); } // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD), (LPDWORD) &dwTmp, ( NULL)) ) errhandler("WriteFile", hwnd); // Copy the array of color indices into the .BMP file. dwTotal = cb = pbih->biSizeImage; hp = lpBits; if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL)) errhandler("WriteFile", hwnd); // Close the .BMP file. if (!CloseHandle(hf)) errhandler("CloseHandle", hwnd); // Free memory. GlobalFree((HGLOBAL)lpBits); }