/*************************************************************************** * * * MODULE : imagedit.c * * * * DESCRIPTION : Contains main entry-level routine for ImagEdit. * * * * FUNCTIONS : WinMain () - Program entry point. * * * * HISTORY : 3/14/89 - LR * * * ***************************************************************************/ #include "imagedit.h" #include "dialogs.h" #include "ids.h" #include #include #include #include /* * External declarations for the Windows variables that contain * command line information. */ extern INT __argc; extern CHAR **__argv; STATICFN BOOL NEAR InitApplication(VOID); STATICFN BOOL NEAR InitInstance(LPSTR lpCmdLine, INT cmdShow); STATICFN VOID NEAR PenWinRegister(VOID); STATICFN VOID NEAR ReadEnv(VOID); STATICFN VOID NEAR WriteEnv(VOID); STATICFN VOID NEAR SizeRibbons(HWND hwnd); STATICFN VOID NEAR CleanUp(VOID); static RECT grcAppPos; // Saves the app's window pos. static WORD gmsgHelp; // Registered help msg from commdlg.dll static BOOL fStartAsIcon = FALSE; // TRUE if app is started minimized. /* * Contains the address of the Pen Windows callback. */ typedef VOID ( APIENTRY *LPFNPENWIN)(WORD, BOOL); static LPFNPENWIN lpfnRegisterPenApp; /**************************************************************************** * * * FUNCTION :int PASCAL WinMain(hInstance,hPrevInstance,lpCmdLine,cmdShow) * * * * PURPOSE :Serves as program entry point and contains message loop * * * ****************************************************************************/ INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow) { MSG msg; DBGStackReport(TRUE); ghInst = hInstance; /* if this is the first instance then call initialization procedure */ if (!hPrevInstance) { if (!InitApplication()) return FALSE; } if (!InitInstance(lpCmdLine, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(ghwndMain, haccelTbl, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } DBGStackReport(FALSE); /* * Return the value from PostQuitMessage. */ return msg.wParam; } /**************************************************************************** * * * FUNCTION : InitApplication() * * * * PURPOSE : To create all ImagEdit's window classes, namely those of * * the parent window, edit window, mode window and "palette" * * window. * * * * RETURNS : TRUE if class registration was successful, FALSE otherwise * * * * SIDE EFFECTS: All class variables affected for all windows. * * * ****************************************************************************/ STATICFN BOOL NEAR InitApplication(VOID) { WNDCLASS wc; /* assign values and register the parent window class */ wc.style = 0; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = LoadIcon(ghInst, MAKEINTRESOURCE(IDICON_IMAGEDIT)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); wc.lpszMenuName = "imagedit"; wc.lpszClassName = szMainClass; if (!RegisterClass(&wc)) return FALSE; wc.style = CS_DBLCLKS; wc.lpfnWndProc = ColorBoxWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = (LPSTR)NULL; wc.lpszClassName = szColorBoxClass; if (!RegisterClass(&wc)) return FALSE; wc.style = 0; wc.lpfnWndProc = ColorLRWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = (LPSTR)NULL; wc.lpszClassName = szColorLRClass; if (!RegisterClass(&wc)) return FALSE; wc.style = CS_DBLCLKS; wc.lpfnWndProc = WorkWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = NULL; wc.hCursor = (HCURSOR)NULL; wc.hbrBackground = (HBRUSH)NULL; wc.lpszMenuName = (LPSTR)NULL; wc.lpszClassName = szWorkClass; if (!RegisterClass(&wc)) return FALSE; wc.style = 0; wc.lpfnWndProc = ToolboxWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = szToolboxClass; if (!RegisterClass(&wc)) return FALSE; wc.style = 0; wc.lpfnWndProc = ToolBtnWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szToolBtnClass; if (!RegisterClass(&wc)) return FALSE; wc.style = 0; wc.lpfnWndProc = ViewWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = ghInst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(LTGRAY_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = szViewClass; if (!RegisterClass(&wc)) return FALSE; return TRUE; } /**************************************************************************** * * * FUNCTION : InitInstance(lpCmdLine, cmdShow) * * * * PURPOSE : Load strings from resource file, make procedure instances * * of all dialog functions, create ImagEdit's windows, color * * "palettes", tool cursors and do a variety of other initial-* * izations. Also prepare ImagEdit if started up from cmd line* * with an argument. Some of these may be redundant, since a * * lot of pBrush stuff has been retained here. * * * * SIDE EFFECTS: numerous * * * ****************************************************************************/ STATICFN BOOL NEAR InitInstance( LPSTR lpCmdLine, INT cmdShow) { INT i; INT iScrollBarWidth; /* width of vertical scrollbar */ INT iScrollBarHeight; /* height of horizontal scrollbar */ INT iScreenWid; INT iScreenHgt; /* full screen width and height */ INT x; INT y; INT cx; INT cy; BOOL fMaximized; RECT rcColor; RECT rcClient; RECT rc; POINT pt; /* * Load the "Out of memory." string now, since we may not be able to * load it if/when it needs to be displayed. */ ids(IDS_OUTOFMEMORY); /* * Register for Pen Windows, if it is present. */ PenWinRegister(); /* register private ImagEdit clipboard format for icons and cursors */ if (!(ClipboardFormat = RegisterClipboardFormat("ImagEdit"))) return FALSE; if (!(haccelTbl = LoadAccelerators(ghInst, "imagedit"))) return FALSE; hcurWait = LoadCursor(NULL, IDC_WAIT); gaTools[TOOL_PENCIL].hcur = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_PENCIL)); gaTools[TOOL_BRUSH].hcur = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_BRUSH)); gaTools[TOOL_SELECT].hcur = gaTools[TOOL_LINE].hcur = gaTools[TOOL_RECT].hcur = gaTools[TOOL_SOLIDRECT].hcur = gaTools[TOOL_CIRCLE].hcur = gaTools[TOOL_SOLIDCIRCLE].hcur = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_CROSS)); gaTools[TOOL_FLOODFILL].hcur = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_FLOOD)); gaTools[TOOL_HOTSPOT].hcur = LoadCursor(ghInst, MAKEINTRESOURCE(IDCUR_HOTSPOT)); /* * Select the default tool. Since the toolbox is not created yet, * this just sets up some globals. */ ToolboxSelectTool(TOOL_FIRST); /* * Create a dark gray pen for use in borders later. */ if (!(hpenDarkGray = CreatePen(PS_SOLID, 1, RGB_DARKGRAY))) return FALSE; /* * Initialize the two color palettes to the default colors. */ for (i = 0; i < COLORSMAX; i++) { gargbColor[i] = gargbDefaultColor[i]; gargbMono[i] = gargbDefaultMono[i]; } /* get some system parameters */ iScrollBarWidth = GetSystemMetrics(SM_CXVSCROLL); iScrollBarHeight = GetSystemMetrics(SM_CYHSCROLL); iScreenWid = GetSystemMetrics(SM_CXFULLSCREEN); iScreenHgt = GetSystemMetrics(SM_CYFULLSCREEN); gcyBorder = GetSystemMetrics(SM_CYBORDER); /* * Build the help file name path. Assume the help file is in the * same directory as the executable. */ GetModuleFileName(ghInst, gszHelpFile, CCHMAXPATH); *FileInPath(gszHelpFile) = '\0'; lstrcat(gszHelpFile, ids(IDS_HELPFILE)); /* * Register the message for help from the common dialogs. */ gmsgHelp = RegisterWindowMessage(HELPMSGSTRING); /* * Hook the message filter stream so that we can detect F1 keystrokes. */ lpfnMsgFilterHookFunc = MakeProcInstance((FARPROC)MsgFilterHookFunc, ghInst); ghhkMsgFilter = SetWindowsHook(WH_MSGFILTER, lpfnMsgFilterHookFunc); if (!ReadWindowPos(szAppPos, &x, &y, &cx, &cy, &fMaximized)) { x = 2 * iScrollBarWidth; y = iScrollBarHeight; cx = min(iScreenWid - (4 * iScrollBarWidth), MAXDEFAULTAPPCX); cy = min(iScreenHgt - (6 * iScrollBarHeight), MAXDEFAULTAPPCY); fMaximized = FALSE; } /* create parent window */ ghwndMain = CreateWindow(szMainClass, ids(IDS_PGMTITLE), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, x, y, cx, cy, NULL, NULL, ghInst, NULL); if (ghwndMain == NULL) { Message(MSG_OUTOFMEMORY); return FALSE; } /* * Read the preferences data saved in the ini file. */ ReadEnv(); /* * Create the Toolbox and the View window (invisible). */ ToolboxCreate(); ViewCreate(); lpfnColorDlgProc = (WNDPROC)MakeProcInstance( (FARPROC)ColorDlgProc, ghInst); ghwndColor = CreateDialog(ghInst, MAKEINTRESOURCE(DID_COLOR), ghwndMain, lpfnColorDlgProc); ghwndWork = CreateWindow(szWorkClass, NULL, WS_CHILD | WS_BORDER, 0, 0, 0, 0, ghwndMain, NULL, ghInst, NULL); /* * Build the device table. */ InitDeviceList(); SetColorPalette(gnColors, giType, TRUE); SetScreenColor(grgbScreenDefault); if (!ReadWindowPos(szColorPos, &x, &y, &cx, &cy, &fMaximized)) { /* * The previous position of the Color palette couldn't be found. * Position the palette just below the bottom left corner of the * client area of the editor, but make sure it is completely * visible. */ GetWindowRect(ghwndColor, &rcColor); GetClientRect(ghwndMain, &rcClient); cx = rcColor.right - rcColor.left; cy = rcColor.bottom - rcColor.top; pt.x = rcClient.left + (2 * PALETTEMARGIN); pt.y = rcClient.bottom + (2 * PALETTEMARGIN); ClientToScreen(ghwndMain, &pt); SetRect(&rc, pt.x, pt.y, pt.x + cx, pt.y + cy); FitRectToScreen(&rc); x = rc.left; y = rc.top; } SetWindowPos(ghwndColor, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); SetFileName(NULL); /* * If the app was saved when maximized (and they didn't start it up * with some kind of an option to have it minimized or in some * other funny initial state from the shell), then cause it to * be maximized when shown. */ if (fMaximized && (cmdShow == SW_SHOWNORMAL || cmdShow == SW_SHOW)) cmdShow = SW_SHOWMAXIMIZED; ShowWindow(ghwndMain, cmdShow); UpdateWindow(ghwndMain); /* * Did the user start this app minimized from the program manager? */ if (IsIconic(ghwndMain)) { /* * Set a flag. The showing of the palettes will be deferred * until the app is restored. */ fStartAsIcon = TRUE; } else { /* * If they had the Toolbox/Color Palette before, show them now. */ ToolboxShow(gfShowToolbox); ColorShow(gfShowColor); } /* * If there was a command line argument specified, try and open * it as the initial file. */ if (__argc > 1) OpenCmdLineFile(__argv[1]); return TRUE; } /************************************************************************ * PenWinRegister * * This function will register for Pen Windows, if it is present. * ************************************************************************/ STATICFN VOID NEAR PenWinRegister(VOID) { HANDLE hmod; if (!(hmod = (HANDLE)GetSystemMetrics(SM_PENWINDOWS))) return; if (lpfnRegisterPenApp = (LPFNPENWIN)GetProcAddress(hmod, "RegisterPenApp")) (*lpfnRegisterPenApp)(1, TRUE); // Be Pen-Enhanced! } /************************************************************************ * MainWndProc * * Main window procedure for ImagEdit. * * History: * ************************************************************************/ WINDOWPROC MainWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: { RECT rc; /* * Create the PropBar window. */ lpfnPropBarDlgProc = (WNDPROC)MakeProcInstance( (FARPROC)PropBarDlgProc, ghInst); CreateDialog(ghInst, MAKEINTRESOURCE(DID_PROPBAR), hwnd, lpfnPropBarDlgProc); /* * Save away its height for sizing later (like when * the app is minimized then restored). */ GetWindowRect(ghwndPropBar, &rc); gcyPropBar = rc.bottom - rc.top; } break; case WM_NCCALCSIZE: /* * Save away what is going to be the new window position. */ if (!IsIconic(hwnd) && !IsZoomed(hwnd)) grcAppPos = *((LPRECT)lParam); /* * Now let the DefWindowProc calculate the client area normally. */ goto DoDefault; case WM_ACTIVATE: /* * If the main window is getting activated, there is no * currently active dialog. */ if (GET_WM_ACTIVATE_STATE(wParam, lParam)) gidCurrentDlg = 0; goto DoDefault; case WM_INITMENU: if (GetMenu(ghwndMain) == (HMENU)wParam) InitMenu((HMENU)wParam); break; case WM_COMMAND: MenuCmd(GET_WM_COMMAND_ID(wParam, lParam)); break; case WM_SIZE: SizeRibbons(hwnd); if (wParam != SIZEICONIC) WorkReset(); /* * Did the app start minimized and is it being restored * for the first time? If so, show the palettes as * the user has requested. */ if (fStartAsIcon && !IsIconic(hwnd)) { ToolboxShow(gfShowToolbox); ColorShow(gfShowColor); fStartAsIcon = FALSE; } break; case WM_MENUSELECT: if (GET_WM_MENUSELECT_FLAGS(wParam, lParam) & (MF_POPUP | MF_SYSMENU)) gMenuSelected = 0; else gMenuSelected = GET_WM_MENUSELECT_CMD(wParam, lParam); break; case WM_CLOSE: if (VerifySaveFile()) { DestroyWindow(hwnd); CleanUp(); } break; case WM_DESTROY: /* * Save the position of the app's window. */ WriteWindowPos(&grcAppPos, IsZoomed(hwnd), szAppPos); WinHelp(ghwndMain, gszHelpFile, HELP_QUIT, 0L); PostQuitMessage(0); break; case WM_QUERYENDSESSION: return VerifySaveFile(); default: /* * Is this the registered help message from one of the common * dialogs? If so, show the help for it. * * The check to be sure gmsgHelp is non-zero is just in * case the call to register the help message failed * (it will return zero) and there happens to be a zero * message that gets sent to this window somehow. */ if (msg == gmsgHelp && gmsgHelp) { ShowHelp(FALSE); return 0; } DoDefault: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } /************************************************************************ * ReadWindowPos * * This function retrieves the saved window position for a window and * returns it in the specified variables. It is used between sessions * to restore the application windows to the position they had when * the editor was last exited. * * Returns TRUE if the position could be read, or FALSE otherwise. * If FALSE is returned, the values in the specified variables are * not valid! The caller must be able to handle a FALSE return and * supply a default position for the window. * * Arguments: * PSTR pstrKeyName - KeyName the position was saved under. * PINT px - Saved x position. * PINT py - Saved y position. * PINT pcx - Saved width. * PINT pcy - Saved height. * BOOL *pfMaximized - Set to TRUE if window was maximized when saved. * * History: * ************************************************************************/ BOOL ReadWindowPos( PSTR pstrKeyName, PINT px, PINT py, PINT pcx, PINT pcy, BOOL *pfMaximized) { static CHAR szSep[] = " ,"; CHAR szBuf[CCHTEXTMAX]; PSTR pstr; if (!GetPrivateProfileString(ids(IDS_APPNAME), pstrKeyName, "", szBuf, CCHTEXTMAX, ids(IDS_IMAGEDITINI))) return FALSE; if (!(pstr = strtok(szBuf, szSep))) return FALSE; *px = atoi(pstr); if (!(pstr = strtok(NULL, szSep))) return FALSE; *py = atoi(pstr); if (!(pstr = strtok(NULL, szSep))) return FALSE; *pcx = atoi(pstr); if (!(pstr = strtok(NULL, szSep))) return FALSE; *pcy = atoi(pstr); /* * If there is a "1" following the coordinates, the window was * maximized when it was saved. */ *pfMaximized = FALSE; if ((pstr = strtok(NULL, szSep)) && atoi(pstr) == 1) *pfMaximized = TRUE; /* * Don't allow a zero sized window. */ if (*pcx == 0 || *pcy == 0) return FALSE; /* * Return success. */ return TRUE; } /************************************************************************ * WriteWindowPos * * This function writes the position of a window to the * editor's profile file under the specified keyname. * The ReadWindowPos function is the counterpart of this * function. * * Arguments: * PRECT prc - Rectangle for the "restored" window size. * BOOL fMaximized - TRUE if the window is maximized. * PSTR pstrKeyName - KeyName to save the position under. * * History: * ************************************************************************/ VOID WriteWindowPos( PRECT prc, BOOL fMaximized, PSTR pstrKeyName) { CHAR szBuf[CCHTEXTMAX]; wsprintf(szBuf, "%d %d %d %d", prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top); if (fMaximized) strcat(szBuf, " 1"); WritePrivateProfileString(ids(IDS_APPNAME), pstrKeyName, szBuf, ids(IDS_IMAGEDITINI)); } /************************************************************************* * ReadEnv * * This function initializes variables from their counterparts * in the private profile file for ImagEdit. The application * merely needs to construct an array of INIENTRY structures * to describe the variables that must be initialized. * * Note that the original value read from the profile is saved when * it is read. This allows us to optimize what needs to be written * out with WriteEnv. * * History: * *************************************************************************/ STATICFN VOID NEAR ReadEnv(VOID) { register INT i; HDC hdc; CHAR szBuf[CCHTEXTMAX]; DWORD rgb; for (i = 0; gaie[i].pstrKeyName; i++) { *gaie[i].pnVar = gaie[i].nSave = GetPrivateProfileInt(ids(IDS_APPNAME), gaie[i].pstrKeyName, gaie[i].nDefault, ids(IDS_IMAGEDITINI)); } /* * Look for the saved screen color. */ if (GetPrivateProfileString(ids(IDS_APPNAME), szrgbScreen, "", szBuf, CCHTEXTMAX, ids(IDS_IMAGEDITINI))) { rgb = (DWORD)atol(szBuf); } else { /* * The last screen color was not found. The default will be * the current system screen background color. */ rgb = GetSysColor(COLOR_BACKGROUND); } /* * Make the ImagEdit default screen color a solid color. */ hdc = GetDC(ghwndMain); grgbScreenDefault = GetNearestColor(hdc, rgb); ReleaseDC(ghwndMain, hdc); } /************************************************************************* * WriteEnv * * This function is the counterpart to ReadEnv. It saves values * in the profile file. * * History: * *************************************************************************/ STATICFN VOID NEAR WriteEnv(VOID) { register INT i; CHAR szBuf[CCHTEXTMAX]; for (i = 0; gaie[i].pstrKeyName; i++) { /* * Has the user changed the value since it was read? */ if (gaie[i].nSave != *gaie[i].pnVar) { /* * If the new value is the same as the default value, * erase the entry from the ini file. Otherwise, * write the user-specified value out. */ if (*gaie[i].pnVar == gaie[i].nDefault) { WritePrivateProfileString(ids(IDS_APPNAME), gaie[i].pstrKeyName, NULL, ids(IDS_IMAGEDITINI)); } else { itoa(*gaie[i].pnVar, szBuf, 10); WritePrivateProfileString(ids(IDS_APPNAME), gaie[i].pstrKeyName, szBuf, ids(IDS_IMAGEDITINI)); } } } /* * Save the current screen color. */ ltoa((LONG)grgbScreen, szBuf, 10); WritePrivateProfileString(ids(IDS_APPNAME), szrgbScreen, szBuf, ids(IDS_IMAGEDITINI)); } /************************************************************************ * SizeRibbons * * This function positions and sizes the child ribbons in the editor. * It needs to be called any time the size of the main windows changes. * * Arguments: * HWND hwnd - Parent window handle. * * History: * ************************************************************************/ STATICFN VOID NEAR SizeRibbons( HWND hwnd) { RECT rcClient; if (ghwndPropBar && !IsIconic(hwnd)) { /* * Get the client area. */ GetClientRect(hwnd, &rcClient); /* * Size/move the PropBar window to fit * the new client area. */ SetWindowPos(ghwndPropBar, NULL, 0, 0, rcClient.right - rcClient.left, min(rcClient.bottom - rcClient.top, gcyPropBar), SWP_NOACTIVATE | SWP_NOZORDER); } } /************************************************************************ * CleanUp * * Cleans up all the resources allocated by the editor. * * History: * ************************************************************************/ STATICFN VOID NEAR CleanUp(VOID) { WriteEnv(); if (ghdcANDMask) { DeleteDC(ghdcANDMask); DeleteObject(ghbmANDMask); } if (ghdcImage) { DeleteDC(ghdcImage); DeleteObject(ghbmImage); } ImageFreeUndo(); if (hpenDarkGray) DeleteObject(hpenDarkGray); if (ghbrLeft) DeleteObject(ghbrLeft); if (ghbrLeftSolid) DeleteObject(ghbrLeftSolid); if (ghbrRight) DeleteObject(ghbrRight); if (ghbrRightSolid) DeleteObject(ghbrRightSolid); if (ghbrScreen) DeleteObject(ghbrScreen); if (ghbrInverse) DeleteObject(ghbrInverse); if (ghpenLeft) DeleteObject(ghpenLeft); if (ghpenRight) DeleteObject(ghpenRight); ImageLinkFreeList(); if (lpfnMsgFilterHookFunc) { UnhookWindowsHook(WH_MSGFILTER, lpfnMsgFilterHookFunc); FreeProcInstance(lpfnMsgFilterHookFunc); } if (lpfnPropBarDlgProc) FreeProcInstance((FARPROC)lpfnPropBarDlgProc); if (lpfnColorDlgProc) FreeProcInstance((FARPROC)lpfnColorDlgProc); } /**************************************************************************** My_mbschr: strchr() DBCS version ****************************************************************************/ unsigned char * _CRTAPI1 My_mbschr( unsigned char *psz, unsigned short uiSep) { while (*psz != '\0' && *psz != uiSep) { psz = CharNext(psz); } if (*psz == '\0' && uiSep != '\0') { return NULL; } else { return psz; } } /**************************************************************************** My_mbstok: strtok() DBCS version ****************************************************************************/ unsigned char * _CRTAPI1 My_mbstok( unsigned char *pszSrc, unsigned char *pszSep) { static char *pszSave = NULL; char *pszHead; char *psz; if (pszSrc == NULL) { if (pszSave == NULL) { return NULL; } else { psz = pszSave; } } else { psz = pszSrc; } /*********************************************/ /* Skip delimiters to find a head of a token */ /*********************************************/ while (*psz) { if (IsDBCSLeadByte(*psz)) { break; } else if (NULL == My_mbschr(pszSep, *psz)) { break; } psz++; } if (*psz == '\0') { //No more token return (pszSave = NULL); } pszHead = psz; /******************************/ /* Search a Tail of the token */ /******************************/ while (*psz) { if (IsDBCSLeadByte(*psz)) { psz += 2; continue; } else if (NULL != My_mbschr(pszSep, *psz)) { break; } psz++; } if (*psz == '\0') { pszSave = NULL; } else { //Found next delimiter pszSave = psz + 1; *psz = '\0'; } return pszHead; } /**************************************************************************** My_mbsncat: ****************************************************************************/ unsigned char * _CRTAPI1 My_mbsncat( unsigned char *psz1, const unsigned char *psz2, size_t Length) { int nLen = (int)Length; unsigned char *pszSv = psz1; while ('\0' != *psz1) { psz1++; } while (0 < nLen) { if (*psz2 == '\0') { *psz1++ = '\0'; nLen--; } else if (IsDBCSLeadByte(*psz2)) { if (nLen == 1) { *psz1 = '\0'; } else { *psz1++ = *psz2++; *psz1++ = *psz2++; } nLen -= 2; } else { *psz1++ = *psz2++; nLen--; } } return pszSv; }