/* * links.c * * Implements the OleUIEditLinks function which invokes the complete * Edit Links dialog. * * Copyright (c)1992 Microsoft Corporation, All Right Reserved */ #include "precomp.h" #include "common.h" #include "utility.h" #include #include #include OLEDBGDATA // INTERNAL INFORMATION STARTS HERE #define OLEUI_SZMAX 255 #define LINKTYPELEN 30 // was 9, now I've more than tripled it #define szNULL TEXT("\0") typedef UINT (CALLBACK* COMMDLGHOOKPROC)(HWND, UINT, WPARAM, LPARAM); // Internally used structure typedef struct tagLINKINFO { DWORD dwLink; // app specific identifier of a link LPTSTR lpszDisplayName; // file based part of name LPTSTR lpszItemName; // object part of name LPTSTR lpszShortFileName; // filename without path LPTSTR lpszShortLinkType; // Short link type - progID LPTSTR lpszFullLinkType; // Full link type - user friendly name LPTSTR lpszAMX; // Is the link auto (A) man (M) or dead (X) ULONG clenFileName; // count of file part of mon. BOOL fSourceAvailable; // bound or not - on boot assume yes?? BOOL fIsAuto; // 1 =automatic, 0=manual update BOOL fIsMarked; // 1 = marked, 0 = not BOOL fDontFree; // Don't free this data since it's being reused BOOL fIsSelected; // item selected or to be selected } LINKINFO, FAR* LPLINKINFO; typedef struct tagEDITLINKS { // Keep this item first as the Standard* functions depend on it here. LPOLEUIEDITLINKS lpOEL; // Original structure passed. UINT nIDD; // IDD of dialog (used for help info) BOOL fClose; // Does the button read cancel (0) or // close (1)? BOOL fItemsExist; // TRUE, items in lbox, FALSE, none UINT nChgSrcHelpID; // ID for Help callback from ChangeSrc dlg TCHAR szClose[50]; // Text for Close button // (when Cancel button gets renamed) int nColPos[3]; // tab positions for list box int nHeightLine; // height of each line in owner draw listbox int nMaxCharWidth; // maximim width of text in owner draw listbox } EDITLINKS, *PEDITLINKS, FAR *LPEDITLINKS; // Internal function prototypes // LINKS.CPP INT_PTR CALLBACK EditLinksDialogProc(HWND, UINT, WPARAM, LPARAM); BOOL FEditLinksInit(HWND, WPARAM, LPARAM); BOOL Container_ChangeSource(HWND, LPEDITLINKS); HRESULT Container_AutomaticManual(HWND, BOOL, LPEDITLINKS); HRESULT CancelLink(HWND, LPEDITLINKS); HRESULT Container_UpdateNow(HWND, LPEDITLINKS); HRESULT Container_OpenSource(HWND, LPEDITLINKS); int AddLinkLBItem(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPLINKINFO lpLI, BOOL fGetSelected); VOID BreakString(LPLINKINFO); int GetSelectedItems(HWND, int FAR* FAR*); VOID InitControls(HWND hDlg, LPEDITLINKS lpEL); VOID UpdateLinkLBItem(HWND hListBox, int nIndex, LPEDITLINKS lpEL, BOOL bSelect); VOID ChangeAllLinks(HWND hLIstBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPTSTR lpszFrom, LPTSTR lpszTo); int LoadLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr); VOID RefreshLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr); /* * OleUIEditLinks * * Purpose: * Invokes the standard OLE Edit Links dialog box allowing the user * to manipulate ole links (delete, update, change source, etc). * * Parameters: * lpEL LPOLEUIEditLinks pointing to the in-out structure * for this dialog. * * Return Value: * UINT One of the following codes, indicating success or error: * OLEUI_SUCCESS Success * OLEUI_ERR_STRUCTSIZE The dwStructSize value is wrong */ STDAPI_(UINT) OleUIEditLinks(LPOLEUIEDITLINKS lpEL) { HGLOBAL hMemDlg = NULL; UINT uRet = UStandardValidation((LPOLEUISTANDARD)lpEL, sizeof(OLEUIEDITLINKS), &hMemDlg); if (OLEUI_SUCCESS != uRet) return uRet; // Validate interface. if (NULL == lpEL->lpOleUILinkContainer) { uRet = OLEUI_ELERR_LINKCNTRNULL; } else if(IsBadReadPtr(lpEL->lpOleUILinkContainer, sizeof(IOleUILinkContainer))) { uRet = OLEUI_ELERR_LINKCNTRINVALID; } if (OLEUI_SUCCESS != uRet) { return(uRet); } UINT nIDD = bWin4 ? IDD_EDITLINKS4 : IDD_EDITLINKS; // Now that we've validated everything, we can invoke the dialog. uRet = UStandardInvocation(EditLinksDialogProc, (LPOLEUISTANDARD)lpEL, hMemDlg, MAKEINTRESOURCE(nIDD)); return uRet; } /* * EditLinksDialogProc * * Purpose: * Implements the OLE Edit Links dialog as invoked through the * OleUIEditLinks function. * * Parameters: * Standard * * Return Value: * Standard */ INT_PTR CALLBACK EditLinksDialogProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { // Declare Win16/Win32 compatible WM_COMMAND parameters. COMMANDPARAMS(wID, wCode, hWndMsg); // This will fail under WM_INITDIALOG, where we allocate it. UINT uRet = 0; LPEDITLINKS lpEL = (LPEDITLINKS)LpvStandardEntry(hDlg, iMsg, wParam, lParam, &uRet); // If the hook processed the message, we're done. if (0 != uRet) return (BOOL)uRet; //Process help message from secondary dialog if ((iMsg == uMsgHelp) && (lpEL)) { PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp, wParam, lParam); return FALSE; } // Process the temination message if (iMsg == uMsgEndDialog) { EndDialog(hDlg, wParam); return TRUE; } switch (iMsg) { case WM_DESTROY: if (lpEL) { StandardCleanup(lpEL, hDlg); } break; case WM_INITDIALOG: return FEditLinksInit(hDlg, wParam, lParam); case WM_MEASUREITEM: { LPMEASUREITEMSTRUCT lpMIS = (LPMEASUREITEMSTRUCT)lParam; int nHeightLine; if (lpEL && lpEL->nHeightLine != -1) { // use cached height nHeightLine = lpEL->nHeightLine; } else { HFONT hFont; HDC hDC; TEXTMETRIC tm; hFont = (HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0L); if (hFont == NULL) hFont = (HFONT)GetStockObject(SYSTEM_FONT); hDC = GetDC(hDlg); hFont = (HFONT)SelectObject(hDC, hFont); GetTextMetrics(hDC, &tm); nHeightLine = tm.tmHeight; if (lpEL) { lpEL->nHeightLine = nHeightLine; lpEL->nMaxCharWidth = tm.tmMaxCharWidth; } ReleaseDC(hDlg, hDC); } lpMIS->itemHeight = nHeightLine; } break; case WM_DRAWITEM: { LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)lParam; LPLINKINFO lpLI = (LPLINKINFO)lpDIS->itemData; if ((int)lpDIS->itemID < 0) break; if ((ODA_DRAWENTIRE | ODA_SELECT) & lpDIS->itemAction) { HBRUSH hbr; COLORREF crText; if (ODS_SELECTED & lpDIS->itemState) { /*Get proper txt colors */ crText = SetTextColor(lpDIS->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)); lpLI->fIsSelected = TRUE; } else { hbr = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); lpLI->fIsSelected = FALSE; } FillRect(lpDIS->hDC, &lpDIS->rcItem, hbr); DeleteObject(hbr); int nOldBkMode = SetBkMode(lpDIS->hDC, TRANSPARENT); RECT rcClip; if (lpLI->lpszDisplayName) { TCHAR szTemp[MAX_PATH]; lstrcpy(szTemp, lpLI->lpszDisplayName); LPTSTR lpsz = ChopText( lpDIS->hwndItem, lpEL->nColPos[1] - lpEL->nColPos[0] - (lpEL->nMaxCharWidth > 0 ? lpEL->nMaxCharWidth : 5), szTemp, 0 ); rcClip.left = lpDIS->rcItem.left + lpEL->nColPos[0]; rcClip.top = lpDIS->rcItem.top; rcClip.right = lpDIS->rcItem.left + lpEL->nColPos[1] - (lpEL->nMaxCharWidth > 0 ? lpEL->nMaxCharWidth : 5); rcClip.bottom = lpDIS->rcItem.bottom; ExtTextOut( lpDIS->hDC, rcClip.left, rcClip.top, ETO_CLIPPED, (LPRECT)&rcClip, lpsz, lstrlen(lpsz), NULL ); } if (lpLI->lpszShortLinkType) { rcClip.left = lpDIS->rcItem.left + lpEL->nColPos[1]; rcClip.top = lpDIS->rcItem.top; rcClip.right = lpDIS->rcItem.left + lpEL->nColPos[2] - (lpEL->nMaxCharWidth > 0 ? lpEL->nMaxCharWidth : 5); rcClip.bottom = lpDIS->rcItem.bottom; ExtTextOut( lpDIS->hDC, rcClip.left, rcClip.top, ETO_CLIPPED, (LPRECT)&rcClip, lpLI->lpszShortLinkType, lstrlen(lpLI->lpszShortLinkType), NULL ); } if (lpLI->lpszAMX) { rcClip.left = lpDIS->rcItem.left + lpEL->nColPos[2]; rcClip.top = lpDIS->rcItem.top; rcClip.right = lpDIS->rcItem.right; rcClip.bottom = lpDIS->rcItem.bottom; ExtTextOut( lpDIS->hDC, rcClip.left, rcClip.top, ETO_CLIPPED, (LPRECT)&rcClip, lpLI->lpszAMX, lstrlen(lpLI->lpszAMX), NULL ); } SetBkMode(lpDIS->hDC, nOldBkMode); // restore orig colors if we changed them if (ODS_SELECTED & lpDIS->itemState) SetTextColor(lpDIS->hDC, crText); } if (ODA_FOCUS & lpDIS->itemAction) DrawFocusRect(lpDIS->hDC, &lpDIS->rcItem); } return TRUE; case WM_DELETEITEM: { LPDELETEITEMSTRUCT lpDIS = (LPDELETEITEMSTRUCT)lParam; UINT idCtl = (UINT)wParam; LPLINKINFO lpLI = (LPLINKINFO)lpDIS->itemData; if (lpLI->lpszDisplayName) OleStdFree((LPVOID)lpLI->lpszDisplayName); if (lpLI->lpszShortLinkType) OleStdFree((LPVOID)lpLI->lpszShortLinkType); if (lpLI->lpszFullLinkType) OleStdFree((LPVOID)lpLI->lpszFullLinkType); /* The ChangeSource processing reuses allocated space for ** links that have been modified. */ // Don't free the LINKINFO for the changed links if (lpLI->fDontFree) lpLI->fDontFree = FALSE; else { if (lpLI->lpszAMX) OleStdFree((LPVOID)lpLI->lpszAMX); OleStdFree((LPVOID)lpLI); } } return TRUE; case WM_COMPAREITEM: { LPCOMPAREITEMSTRUCT lpCIS = (LPCOMPAREITEMSTRUCT)lParam; LPLINKINFO lpLI1 = (LPLINKINFO)lpCIS->itemData1; LPLINKINFO lpLI2 = (LPLINKINFO)lpCIS->itemData2; // Sort list entries by DisplayName return lstrcmp(lpLI1->lpszDisplayName, lpLI2->lpszDisplayName); } case WM_COMMAND: switch (wID) { case IDC_EL_CHANGESOURCE: { BOOL fRet = Container_ChangeSource(hDlg, lpEL); if (!fRet) PopupMessage(hDlg, IDS_LINKS, IDS_FAILED, MB_ICONEXCLAMATION | MB_OK); InitControls(hDlg, lpEL); } break; case IDC_EL_AUTOMATIC: { CheckDlgButton(hDlg, IDC_EL_AUTOMATIC, 1); CheckDlgButton(hDlg, IDC_EL_MANUAL, 0); HRESULT hErr = Container_AutomaticManual(hDlg, TRUE, lpEL); if (hErr != NOERROR) PopupMessage(hDlg, IDS_LINKS, IDS_FAILED, MB_ICONEXCLAMATION | MB_OK); InitControls(hDlg, lpEL); } break; case IDC_EL_MANUAL: { CheckDlgButton(hDlg, IDC_EL_MANUAL, 1); CheckDlgButton(hDlg, IDC_EL_AUTOMATIC, 0); HRESULT hErr = Container_AutomaticManual(hDlg, FALSE, lpEL); if (hErr != NOERROR) PopupMessage(hDlg, IDS_LINKS, IDS_FAILED, MB_ICONEXCLAMATION | MB_OK); InitControls(hDlg, lpEL); } break; case IDC_EL_CANCELLINK: CancelLink(hDlg,lpEL); InitControls(hDlg, lpEL); break; case IDC_EL_UPDATENOW: Container_UpdateNow(hDlg, lpEL); InitControls(hDlg, lpEL); break; case IDC_EL_OPENSOURCE: { HRESULT hErr = Container_OpenSource(hDlg, lpEL); if (hErr != NOERROR) { InitControls(hDlg, lpEL); // Don't close dialog break; } SendMessage(hDlg, uMsgEndDialog, OLEUI_OK, 0L); } // fall through case IDC_EL_LINKSLISTBOX: if (wCode == LBN_SELCHANGE) InitControls(hDlg, lpEL); break; case IDCANCEL: SendMessage(hDlg, uMsgEndDialog, OLEUI_CANCEL, 0L); break; case IDC_OLEUIHELP: PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_EDITLINKS, 0)); break; } break; default: if (lpEL != NULL && iMsg == lpEL->nChgSrcHelpID) { PostMessage(lpEL->lpOEL->hWndOwner, uMsgHelp, (WPARAM)hDlg, MAKELPARAM(IDD_CHANGESOURCE, 0)); } if (iMsg == uMsgBrowseOFN && lpEL != NULL && lpEL->lpOEL && lpEL->lpOEL->hWndOwner) { SendMessage(lpEL->lpOEL->hWndOwner, uMsgBrowseOFN, wParam, lParam); } break; } return FALSE; } /* * FEditLinksInit * * Purpose: * WM_INITIDIALOG handler for the Edit Links dialog box. * * * Parameters: * hDlg HWND of the dialog * wParam WPARAM of the message * lParam LPARAM of the message * * Return Value: * BOOL Value to return for WM_INITDIALOG. */ BOOL FEditLinksInit(HWND hDlg, WPARAM wParam, LPARAM lParam) { // Copy the structure at lParam into our instance memory. HFONT hFont; LPEDITLINKS lpEL = (LPEDITLINKS)LpvStandardInit(hDlg, sizeof(EDITLINKS), &hFont); // PvStandardInit send a termination to us already. if (NULL == lpEL) return FALSE; LPOLEUIEDITLINKS lpOEL = (LPOLEUIEDITLINKS)lParam; lpEL->lpOEL = lpOEL; lpEL->nIDD = IDD_EDITLINKS; // metrics unknown so far lpEL->nHeightLine = -1; lpEL->nMaxCharWidth = -1; /* calculate the column positions relative to the listbox */ HWND hListBox = GetDlgItem(hDlg, IDC_EL_LINKSLISTBOX); RECT rc; GetWindowRect(hListBox, (LPRECT)&rc); int nStart = rc.left; GetWindowRect(GetDlgItem(hDlg, IDC_EL_COL1), (LPRECT)&rc); lpEL->nColPos[0] = rc.left - nStart; GetWindowRect(GetDlgItem(hDlg, IDC_EL_COL2), (LPRECT)&rc); lpEL->nColPos[1] = rc.left - nStart; GetWindowRect(GetDlgItem(hDlg, IDC_EL_COL3), (LPRECT)&rc); lpEL->nColPos[2] = rc.left - nStart; LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer; ULONG cLinks = LoadLinkLB(hListBox, lpOleUILinkCntr); if ((int)cLinks < 0) return FALSE; BOOL fDlgItem = (BOOL)cLinks; lpEL->fItemsExist = (BOOL)cLinks; InitControls(hDlg, lpEL); // Copy other information from lpOEL that we might modify. // If we got a font, send it to the necessary controls. if (NULL != hFont) { // Do this for as many controls as you need it for. // SendDlgItemMessage(hDlg, ID_, WM_SETFONT, (WPARAM)hFont, 0L); } // Show or hide the help button if (!(lpEL->lpOEL->dwFlags & ELF_SHOWHELP)) StandardShowDlgItem(hDlg, IDC_OLEUIHELP, SW_HIDE); /* * PERFORM OTHER INITIALIZATION HERE. ON ANY LoadString * FAILURE POST OLEUI_MSG_ENDDIALOG WITH OLEUI_ERR_LOADSTRING. */ // If requested disable UpdateNow button if ((lpEL->lpOEL->dwFlags & ELF_DISABLEUPDATENOW)) StandardShowDlgItem(hDlg, IDC_EL_UPDATENOW, SW_HIDE); // If requested disable OpenSource button if ((lpEL->lpOEL->dwFlags & ELF_DISABLEOPENSOURCE)) StandardShowDlgItem(hDlg, IDC_EL_OPENSOURCE, SW_HIDE); // If requested disable UpdateNow button if ((lpEL->lpOEL->dwFlags & ELF_DISABLECHANGESOURCE)) StandardShowDlgItem(hDlg, IDC_EL_CHANGESOURCE, SW_HIDE); // If requested disable CancelLink button if ((lpEL->lpOEL->dwFlags & ELF_DISABLECANCELLINK)) StandardShowDlgItem(hDlg, IDC_EL_CANCELLINK, SW_HIDE); // Change the caption if (NULL!=lpOEL->lpszCaption) SetWindowText(hDlg, lpOEL->lpszCaption); // Load 'Close' string used to rename Cancel button int n = LoadString(_g_hOleStdResInst, IDS_CLOSE, lpEL->szClose, sizeof(lpEL->szClose)/sizeof(TCHAR)); if (!n) { PostMessage(hDlg, uMsgEndDialog, OLEUI_ERR_LOADSTRING, 0L); return FALSE; } if (cLinks > 0) SetFocus(hListBox); else SetFocus(GetDlgItem(hDlg, IDCANCEL)); lpEL->nChgSrcHelpID = RegisterWindowMessage(HELPMSGSTRING); // Call the hook with lCustData in lParam UStandardHook(lpEL, hDlg, WM_INITDIALOG, wParam, lpOEL->lCustData); return FALSE; } /* * Container_ChangeSource * * Purpose: * Tunnel to File Open type dlg and allow user to select new file * for file based monikers, OR to change the whole moniker to what * the user types into the editable field. * * Parameters: * hDlg HWND of the dialog * LPEDITLINKS Pointer to EditLinks structure (contains all nec. * info) * * Return Value: * BOOL for now, because we are not using any ole functions * to return an HRESULT. * HRESULT HRESULT value indicating success or failure of * changing the moniker value */ BOOL Container_ChangeSource(HWND hDlg, LPEDITLINKS lpEL) { HWND hListBox = GetDlgItem(hDlg, IDC_EL_LINKSLISTBOX); int FAR* rgIndex; int cSelItems = GetSelectedItems(hListBox, &rgIndex); if (cSelItems < 0) return FALSE; if (!cSelItems) return TRUE; OLEUICHANGESOURCE cs; memset(&cs, 0, sizeof(cs)); cs.cbStruct = sizeof(cs); cs.hWndOwner = hDlg; if (lpEL->lpOEL->dwFlags & ELF_SHOWHELP) cs.dwFlags |= CSF_SHOWHELP; LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer; cs.lpOleUILinkContainer = lpOleUILinkCntr; for (int i = cSelItems-1; i >= 0; i--) { // allow caller to customize the change source dialog LPLINKINFO lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, rgIndex[i], 0); cs.lpszDisplayName = lpLI->lpszDisplayName; cs.dwLink = lpLI->dwLink; cs.nFileLength = lpLI->clenFileName; UINT uRet = UStandardHook(lpEL, hDlg, uMsgChangeSource, 0, (LPARAM)&cs); if (!uRet) uRet = (OLEUI_OK == OleUIChangeSource(&cs)); if (!uRet) break; // dialog canceled (cancel for all) if (!lpEL->fClose) { SetDlgItemText(hDlg, IDCANCEL, lpEL->szClose); lpEL->fClose = TRUE; } // update the list box item for the new name // (note: original lpszDisplayName already freed) lpLI->fSourceAvailable = (cs.dwFlags & CSF_VALIDSOURCE); lpLI->lpszDisplayName = cs.lpszDisplayName; UpdateLinkLBItem(hListBox, rgIndex[i], lpEL, TRUE); // if differed only in file name, allow user to change all links if (cs.lpszFrom != NULL && cs.lpszTo != NULL) ChangeAllLinks(hListBox, lpOleUILinkCntr, cs.lpszFrom, cs.lpszTo); // must free and NULL out the lpszFrom and lpszTo OUT fields OleStdFree(cs.lpszFrom); cs.lpszFrom = NULL; OleStdFree(cs.lpszTo); cs.lpszTo = NULL; } if (rgIndex != NULL) OleStdFree(rgIndex); return TRUE; } /* * Container_AutomaticManual * * Purpose: * To change the selected moniker to manual or automatic update. * * Parameters: * hDlg HWND of the dialog * FAutoMan Flag indicating AUTO (TRUE/1) or MANUAL(FALSE/0) * LPEDITLINKS Pointer to EditLinks structure (contains all nec. * info) * * this may change - don't know how the linked list * * of multi-selected items will work. * Return Value: * HRESULT HRESULT value indicating success or failure of * changing the moniker value */ HRESULT Container_AutomaticManual(HWND hDlg, BOOL fAutoMan, LPEDITLINKS lpEL) { HRESULT hErr = NOERROR; int cSelItems; int FAR* rgIndex; int i = 0; LPLINKINFO lpLI; LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer; HWND hListBox = GetDlgItem(hDlg, IDC_EL_LINKSLISTBOX); BOOL bUpdate = FALSE; OleDbgAssert(lpOleUILinkCntr); /* Change so looks at flag in structure. Only update those that need to be updated. Make sure to change flag if status changes. */ cSelItems = GetSelectedItems(hListBox, &rgIndex); if (cSelItems < 0) return ResultFromScode(E_FAIL); if (!cSelItems) return NOERROR; HCURSOR hCursorOld = HourGlassOn(); if (!lpEL->fClose) { SetDlgItemText(hDlg, IDCANCEL, lpEL->szClose); lpEL->fClose = TRUE; } for (i = 0; i < cSelItems; i++) { lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, rgIndex[i], 0); if (fAutoMan) { // If switching to AUTOMATIC if (!lpLI->fIsAuto) // Only change MANUAL links { OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::SetLinkUpdateOptions called\r\n")); hErr=lpOleUILinkCntr->SetLinkUpdateOptions( lpLI->dwLink, OLEUPDATE_ALWAYS ); OLEDBG_END2 lpLI->fIsAuto=TRUE; lpLI->fIsMarked = TRUE; bUpdate = TRUE; } } else // If switching to MANUAL { if (lpLI->fIsAuto) // Only do AUTOMATIC Links { OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::SetLinkUpdateOptions called\r\n")); hErr=lpOleUILinkCntr->SetLinkUpdateOptions( lpLI->dwLink, OLEUPDATE_ONCALL ); OLEDBG_END2 lpLI->fIsAuto = FALSE; lpLI->fIsMarked = TRUE; bUpdate = TRUE; } } if (hErr != NOERROR) { OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::SetLinkUpdateOptions returned"),hErr); break; } } if (bUpdate) RefreshLinkLB(hListBox, lpOleUILinkCntr); if (rgIndex) OleStdFree((LPVOID)rgIndex); HourGlassOff(hCursorOld); return hErr; } HRESULT CancelLink(HWND hDlg, LPEDITLINKS lpEL) { HRESULT hErr; LPMONIKER lpmk; int cSelItems; int FAR* rgIndex; int i = 0; LPLINKINFO lpLI; LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer; HWND hListBox = GetDlgItem(hDlg, IDC_EL_LINKSLISTBOX); BOOL bUpdate = FALSE; OleDbgAssert(lpOleUILinkCntr); lpmk = NULL; cSelItems = GetSelectedItems(hListBox, &rgIndex); if (cSelItems < 0) return ResultFromScode(E_FAIL); if (!cSelItems) return NOERROR; HCURSOR hCursorOld = HourGlassOn(); for (i = 0; i < cSelItems; i++) { lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, rgIndex[i], 0); UINT uRet = PopupMessage(hDlg, IDS_LINKS, IDS_CONFIRMBREAKLINK, MB_YESNO|MB_ICONQUESTION); if (uRet == IDNO) break; OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::CancelLink called\r\n")); hErr = lpOleUILinkCntr->CancelLink(lpLI->dwLink); OLEDBG_END2 if (!lpEL->fClose) { SetDlgItemText(hDlg, IDCANCEL, lpEL->szClose); lpEL->fClose = TRUE; } if (hErr != NOERROR) { OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::CancelLink returned"),hErr); lpLI->fIsMarked = TRUE; bUpdate = TRUE; } else { // Delete links that we make null from listbox SendMessage(hListBox, LB_DELETESTRING, (WPARAM) rgIndex[i], 0L); int i2; for (i2 = i + 1; i2 < cSelItems; i2++) { if (rgIndex[i2] > rgIndex[i]) rgIndex[i2]--; } } } if (bUpdate) RefreshLinkLB(hListBox, lpOleUILinkCntr); if (rgIndex) OleStdFree((LPVOID)rgIndex); HourGlassOff(hCursorOld); return hErr; } /* * Container_UpdateNow * * Purpose: * Immediately force an update for all (manual) links * * Parameters: * hDlg HWND of the dialog * LPEDITLINKS Pointer to EditLinks structure (contains all nec. info) * * this may change - don't know how the linked list * * of multi-selected items will work. * Return Value: * HRESULT HRESULT value indicating success or failure of * changing the moniker value */ HRESULT Container_UpdateNow(HWND hDlg, LPEDITLINKS lpEL) { HRESULT hErr; LPLINKINFO lpLI; int cSelItems; int FAR* rgIndex; int i = 0; LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer; HWND hListBox = GetDlgItem(hDlg, IDC_EL_LINKSLISTBOX); BOOL bUpdate = FALSE; OleDbgAssert(lpOleUILinkCntr); cSelItems = GetSelectedItems(hListBox, &rgIndex); if (cSelItems < 0) return ResultFromScode(E_FAIL); if (!cSelItems) return NOERROR; HCURSOR hCursorOld = HourGlassOn(); if (!lpEL->fClose) { SetDlgItemText(hDlg, IDCANCEL, lpEL->szClose); lpEL->fClose = TRUE; } for (i = 0; i < cSelItems; i++) { lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, rgIndex[i], 0); OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::UpdateLink called\r\n")); hErr = lpOleUILinkCntr->UpdateLink( lpLI->dwLink, TRUE, FALSE ); OLEDBG_END2 bUpdate = TRUE; lpLI->fIsMarked = TRUE; if (hErr != NOERROR) { OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::UpdateLink returned"),hErr); break; } } if (bUpdate) RefreshLinkLB(hListBox, lpOleUILinkCntr); if (rgIndex) OleStdFree((LPVOID)rgIndex); HourGlassOff(hCursorOld); return hErr; } /* * Container_OpenSource * * Purpose: * Immediately force an update for all (manual) links * * Parameters: * hDlg HWND of the dialog * LPEDITLINKS Pointer to EditLinks structure (contains all nec. * info) * * Return Value: * HRESULT HRESULT value indicating success or failure of * changing the moniker value */ HRESULT Container_OpenSource(HWND hDlg, LPEDITLINKS lpEL) { HRESULT hErr; int cSelItems; int FAR* rgIndex; LPLINKINFO lpLI; RECT rcPosRect; LPOLEUILINKCONTAINER lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer; HWND hListBox = GetDlgItem(hDlg, IDC_EL_LINKSLISTBOX); OleDbgAssert(lpOleUILinkCntr); rcPosRect.top = 0; rcPosRect.left = 0; rcPosRect.right = 0; rcPosRect.bottom = 0; cSelItems = GetSelectedItems(hListBox, &rgIndex); if (cSelItems < 0) return ResultFromScode(E_FAIL); if (cSelItems != 1) // can't open source for multiple items return NOERROR; HCURSOR hCursorOld = HourGlassOn(); if (!lpEL->fClose) { SetDlgItemText(hDlg, IDCANCEL, lpEL->szClose); lpEL->fClose = TRUE; } lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, rgIndex[0], 0); OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::OpenLinkSource called\r\n")); hErr = lpOleUILinkCntr->OpenLinkSource( lpLI->dwLink ); OLEDBG_END2 UpdateLinkLBItem(hListBox, rgIndex[0], lpEL, TRUE); if (hErr != NOERROR) { OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::OpenLinkSource returned"),hErr); } if (rgIndex) OleStdFree((LPVOID)rgIndex); HourGlassOff(hCursorOld); return hErr; } /* AddLinkLBItem ** ------------- ** ** Add the item pointed to by lpLI to the Link ListBox and return ** the index of it in the ListBox */ int AddLinkLBItem(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPLINKINFO lpLI, BOOL fGetSelected) { HRESULT hErr; DWORD dwUpdateOpt; int nIndex; OleDbgAssert(lpOleUILinkCntr && hListBox && lpLI); lpLI->fDontFree = FALSE; OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::GetLinkSource called\r\n")); hErr = lpOleUILinkCntr->GetLinkSource( lpLI->dwLink, (LPTSTR FAR*)&lpLI->lpszDisplayName, (ULONG FAR*)&lpLI->clenFileName, (LPTSTR FAR*)&lpLI->lpszFullLinkType, (LPTSTR FAR*)&lpLI->lpszShortLinkType, (BOOL FAR*)&lpLI->fSourceAvailable, fGetSelected ? (BOOL FAR*)&lpLI->fIsSelected : NULL ); OLEDBG_END2 if (hErr != NOERROR) { OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::GetLinkSource returned"),hErr); PopupMessage(hListBox, IDS_LINKS, IDS_ERR_GETLINKSOURCE, MB_ICONEXCLAMATION | MB_OK); goto cleanup; } OLEDBG_BEGIN2(TEXT("IOleUILinkContainer::GetLinkUpdateOptions called\r\n")); hErr=lpOleUILinkCntr->GetLinkUpdateOptions( lpLI->dwLink, (LPDWORD)&dwUpdateOpt ); OLEDBG_END2 if (hErr != NOERROR) { OleDbgOutHResult(TEXT("WARNING: IOleUILinkContainer::GetLinkUpdateOptions returned"),hErr); PopupMessage(hListBox, IDS_LINKS, IDS_ERR_GETLINKUPDATEOPTIONS, MB_ICONEXCLAMATION | MB_OK); goto cleanup; } if (lpLI->fSourceAvailable) { if (dwUpdateOpt == OLEUPDATE_ALWAYS) { lpLI->fIsAuto = TRUE; LoadString(_g_hOleStdResInst, IDS_LINK_AUTO, lpLI->lpszAMX, (int)OleStdGetSize((LPVOID)lpLI->lpszAMX) / sizeof (TCHAR)); } else { lpLI->fIsAuto = FALSE; LoadString(_g_hOleStdResInst, IDS_LINK_MANUAL, lpLI->lpszAMX, (int)OleStdGetSize((LPVOID)lpLI->lpszAMX) / sizeof (TCHAR)); } } else LoadString(_g_hOleStdResInst, IDS_LINK_UNKNOWN, lpLI->lpszAMX, (int)OleStdGetSize((LPVOID)lpLI->lpszAMX) / sizeof (TCHAR)); BreakString(lpLI); nIndex = (int)SendMessage(hListBox, LB_ADDSTRING, (WPARAM)0, (LPARAM)lpLI); if (nIndex == LB_ERR) { PopupMessage(hListBox, IDS_LINKS, IDS_ERR_ADDSTRING, MB_ICONEXCLAMATION | MB_OK); goto cleanup; } return nIndex; cleanup: if (lpLI->lpszDisplayName) OleStdFree((LPVOID)lpLI->lpszDisplayName); if (lpLI->lpszShortLinkType) OleStdFree((LPVOID)lpLI->lpszShortLinkType); if (lpLI->lpszFullLinkType) OleStdFree((LPVOID)lpLI->lpszFullLinkType); return -1; } /* BreakString * ----------- * * Purpose: * Break the lpszDisplayName into various parts * * Parameters: * lpLI pointer to LINKINFO structure * * Returns: * */ VOID BreakString(LPLINKINFO lpLI) { LPTSTR lpsz; if (!lpLI->clenFileName || (lstrlen(lpLI->lpszDisplayName)==(int)lpLI->clenFileName)) { lpLI->lpszItemName = NULL; } else { lpLI->lpszItemName = lpLI->lpszDisplayName + lpLI->clenFileName; } // search from last character of filename lpsz = lpLI->lpszDisplayName + lstrlen(lpLI->lpszDisplayName); while (lpsz > lpLI->lpszDisplayName) { lpsz = CharPrev(lpLI->lpszDisplayName, lpsz); if ((*lpsz == '\\') || (*lpsz == '/') || (*lpsz == ':')) break; } if (lpsz == lpLI->lpszDisplayName) lpLI->lpszShortFileName = lpsz; else lpLI->lpszShortFileName = CharNext(lpsz); } /* GetSelectedItems * ---------------- * * Purpose: * Retrieve the indices of the selected items in the listbox * Note that *lprgIndex needed to be free after using the function * * Parameters: * hListBox window handle of listbox * lprgIndex pointer to an integer array to receive the indices * must be freed afterwards * * Returns: * number of indices retrieved, -1 if error */ int GetSelectedItems(HWND hListBox, int FAR* FAR* lprgIndex) { DWORD cSelItems; DWORD cCheckItems; *lprgIndex = NULL; cSelItems = (DWORD)SendMessage(hListBox, LB_GETSELCOUNT, 0, 0L); if ((int)cSelItems < 0) // error return (int)cSelItems; if (!cSelItems) return 0; *lprgIndex = (int FAR*)OleStdMalloc((int)cSelItems * sizeof(int)); cCheckItems = (DWORD)SendMessage(hListBox, LB_GETSELITEMS, (WPARAM) cSelItems, (LPARAM) (int FAR *) *lprgIndex); if (cCheckItems == cSelItems) return (int)cSelItems; else { if (*lprgIndex) OleStdFree((LPVOID)*lprgIndex); *lprgIndex = NULL; return 0; } } /* InitControls * ------------ * * Purpose: * Initialize the state of the Auto/Manual button, Link source/type * static field, etc in the dialogs according to the selection in the * listbox * * Parameters: * hDlg handle to the dialog window */ VOID InitControls(HWND hDlg, LPEDITLINKS lpEL) { int cSelItems; HWND hListBox; int i; int FAR* rgIndex; LPLINKINFO lpLI; LPTSTR lpszType = NULL; LPTSTR lpszSource = NULL; int cAuto = 0; int cManual = 0; BOOL bSameType = TRUE; BOOL bSameSource = TRUE; TCHAR tsz[MAX_PATH]; LPTSTR lpsz; hListBox = GetDlgItem(hDlg, IDC_EL_LINKSLISTBOX); cSelItems = GetSelectedItems(hListBox, &rgIndex); if (cSelItems < 0) return; if ((cSelItems > 0) && (rgIndex == NULL)) return; StandardEnableDlgItem(hDlg, IDC_EL_AUTOMATIC, (BOOL)cSelItems); StandardEnableDlgItem(hDlg, IDC_EL_MANUAL, (BOOL)cSelItems); if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLECANCELLINK)) StandardEnableDlgItem(hDlg, IDC_EL_CANCELLINK, (BOOL)cSelItems); if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLEOPENSOURCE)) StandardEnableDlgItem(hDlg, IDC_EL_OPENSOURCE, cSelItems == 1); if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLECHANGESOURCE)) StandardEnableDlgItem(hDlg, IDC_EL_CHANGESOURCE, cSelItems == 1); if (lpEL && !(lpEL->lpOEL->dwFlags & ELF_DISABLEUPDATENOW)) StandardEnableDlgItem(hDlg, IDC_EL_UPDATENOW, (BOOL)cSelItems); for (i = 0; i < cSelItems; i++) { lpLI = (LPLINKINFO)SendDlgItemMessage(hDlg, IDC_EL_LINKSLISTBOX, LB_GETITEMDATA, rgIndex[i], 0); if (lpszSource && lpLI->lpszDisplayName) { if (bSameSource && lstrcmp(lpszSource, lpLI->lpszDisplayName)) bSameSource = FALSE; } else lpszSource = lpLI->lpszDisplayName; if (lpszType && lpLI->lpszFullLinkType) { if (bSameType && lstrcmp(lpszType, lpLI->lpszFullLinkType)) bSameType = FALSE; } else lpszType = lpLI->lpszFullLinkType; if (lpLI->fIsAuto) cAuto++; else cManual++; } CheckDlgButton(hDlg, IDC_EL_AUTOMATIC, cAuto && !cManual); CheckDlgButton(hDlg, IDC_EL_MANUAL, !cAuto && cManual); /* fill full source in static text box ** below list */ if (!bSameSource || !lpszSource) lpszSource = szNULL; lstrcpy(tsz, lpszSource); lpsz = ChopText(GetDlgItem(hDlg, IDC_EL_LINKSOURCE), 0, tsz, 0); SetDlgItemText(hDlg, IDC_EL_LINKSOURCE, lpsz); /* fill full link type name in static ** "type" text box */ if (!bSameType || !lpszType) lpszType = szNULL; SetDlgItemText(hDlg, IDC_EL_LINKTYPE, lpszType); if (rgIndex) OleStdFree((LPVOID)rgIndex); } /* UpdateLinkLBItem * ----------------- * * Purpose: * Update the linkinfo struct in the listbox to reflect the changes * made by the last operation. It is done simply by removing the item * from the listbox and add it back. * * Parameters: * hListBox handle of listbox * nIndex index of listbox item * lpEL pointer to editlinks structure * bSelect select the item or not after update */ VOID UpdateLinkLBItem(HWND hListBox, int nIndex, LPEDITLINKS lpEL, BOOL bSelect) { LPLINKINFO lpLI; LPOLEUILINKCONTAINER lpOleUILinkCntr; if (!hListBox || (nIndex < 0) || !lpEL) return; lpOleUILinkCntr = lpEL->lpOEL->lpOleUILinkContainer; lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, nIndex, 0); if (lpLI == NULL) return; /* Don't free the data associated with this listbox item ** because we are going to reuse the allocated space for ** the modified link. WM_DELETEITEM processing in the ** dialog checks this flag before deleting data ** associcated with list item. */ lpLI->fDontFree = TRUE; SendMessage(hListBox, LB_DELETESTRING, nIndex, 0L); nIndex = AddLinkLBItem(hListBox, lpOleUILinkCntr, lpLI, FALSE); if (bSelect) { SendMessage(hListBox, LB_SETSEL, TRUE, MAKELPARAM(nIndex, 0)); SendMessage(hListBox, LB_SETCARETINDEX, nIndex, MAKELPARAM(TRUE, 0)); } } /* ChangeAllLinks * -------------- * * Purpose: * Enumerate all the links in the listbox and change those starting * with lpszFrom to lpszTo. * * Parameters: * hListBox window handle of * lpOleUILinkCntr pointer to OleUI Link Container * lpszFrom prefix for matching * lpszTo prefix to substitution * * Returns: */ VOID ChangeAllLinks(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr, LPTSTR lpszFrom, LPTSTR lpszTo) { int cItems; int nIndex; int cFrom; LPLINKINFO lpLI; TCHAR szTmp[MAX_PATH]; BOOL bFound; cFrom = lstrlen(lpszFrom); cItems = (int)SendMessage(hListBox, LB_GETCOUNT, 0, 0L); OleDbgAssert(cItems >= 0); bFound = FALSE; #ifdef _DEBUG OleDbgPrint(3, TEXT("From : "), lpszFrom, 0); OleDbgPrint(3, TEXT(""), TEXT("\r\n"), 0); OleDbgPrint(3, TEXT("To : "), lpszTo, 0); OleDbgPrint(3, TEXT(""), TEXT("\r\n"), 0); #endif for (nIndex = 0; nIndex < cItems; nIndex++) { lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, nIndex, 0); // unmark the item lpLI->fIsMarked = FALSE; /* if the corresponding position for the end of lpszFrom in the ** display name is not a separator. We stop comparing this ** link. */ if (!*(lpLI->lpszDisplayName + cFrom) || (*(lpLI->lpszDisplayName + cFrom) == '\\') || (*(lpLI->lpszDisplayName + cFrom) == '!')) { lstrcpyn(szTmp, lpLI->lpszDisplayName, cFrom + 1); if (!lstrcmp(szTmp, lpszFrom)) { HRESULT hErr; int nFileLength; ULONG ulDummy; if (!bFound) { TCHAR szTitle[256]; TCHAR szMsg[256]; TCHAR szBuf[256]; int uRet; LoadString(_g_hOleStdResInst, IDS_CHANGESOURCE, szTitle, sizeof(szTitle)/sizeof(TCHAR)); LoadString(_g_hOleStdResInst, IDS_CHANGEADDITIONALLINKS, szMsg, sizeof(szMsg)/sizeof(TCHAR)); wsprintf(szBuf, szMsg, lpszFrom); uRet = MessageBox(hListBox, szBuf, szTitle, MB_ICONQUESTION | MB_YESNO); if (uRet == IDYES) bFound = TRUE; else return; } lstrcpy(szTmp, lpszTo); lstrcat(szTmp, lpLI->lpszDisplayName + cFrom); nFileLength = lstrlen(szTmp) - (lpLI->lpszItemName ? lstrlen(lpLI->lpszItemName) : 0); hErr = lpOleUILinkCntr->SetLinkSource( lpLI->dwLink, szTmp, (ULONG)nFileLength, (ULONG FAR*)&ulDummy, TRUE ); if (hErr != NOERROR) { lpOleUILinkCntr->SetLinkSource( lpLI->dwLink, szTmp, (ULONG)nFileLength, (ULONG FAR*)&ulDummy, FALSE); } lpLI->fIsMarked = TRUE; } } } /* have to do the refreshing after processing all links, otherwise ** the item positions will change during the process as the ** listbox stores items in order */ if (bFound) RefreshLinkLB(hListBox, lpOleUILinkCntr); } /* LoadLinkLB * ---------- * * Purpose: * Enumerate all links from the Link Container and build up the Link * ListBox * * Parameters: * hListBox window handle of * lpOleUILinkCntr pointer to OleUI Link Container * lpszFrom prefix for matching * lpszTo prefix to substitution * * Returns: * number of link items loaded, -1 if error */ int LoadLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr) { DWORD dwLink = 0; LPLINKINFO lpLI; int nIndex; int cLinks; cLinks = 0; while ((dwLink = lpOleUILinkCntr->GetNextLink(dwLink)) != 0) { lpLI = (LPLINKINFO)OleStdMalloc(sizeof(LINKINFO)); if (NULL == lpLI) return -1; lpLI->fIsMarked = FALSE; lpLI->fIsSelected = FALSE; lpLI->fDontFree = FALSE; lpLI->lpszAMX = (LPTSTR)OleStdMalloc((LINKTYPELEN+1)*sizeof(TCHAR)); lpLI->dwLink = dwLink; cLinks++; if ((nIndex = AddLinkLBItem(hListBox,lpOleUILinkCntr,lpLI,TRUE)) < 0) // can't load list box return -1; if (lpLI->fIsSelected) SendMessage(hListBox, LB_SETSEL, TRUE, MAKELPARAM(nIndex, 0)); } if (SendMessage(hListBox,LB_GETSELITEMS,(WPARAM)1,(LPARAM)(int FAR*)&nIndex)) SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex, MAKELPARAM(TRUE, 0)); return cLinks; } /* RefreshLinkLB * ------------- * * Purpose: * Enumerate all items in the links listbox and update those with * fIsMarked set. * Note that this is a time consuming routine as it keeps iterating * all items in the listbox until all of them are unmarked. * * Parameters: * hListBox window handle of listbox * lpOleUILinkCntr pointer to OleUI Link Container * * Returns: * */ VOID RefreshLinkLB(HWND hListBox, LPOLEUILINKCONTAINER lpOleUILinkCntr) { int cItems; int nIndex; LPLINKINFO lpLI; BOOL bStop; OleDbgAssert(hListBox); cItems = (int)SendMessage(hListBox, LB_GETCOUNT, 0, 0L); OleDbgAssert(cItems >= 0); do { bStop = TRUE; for (nIndex = 0; nIndex < cItems; nIndex++) { lpLI = (LPLINKINFO)SendMessage(hListBox, LB_GETITEMDATA, nIndex, 0); if (lpLI->fIsMarked) { lpLI->fIsMarked = FALSE; lpLI->fDontFree = TRUE; SendMessage(hListBox, LB_DELETESTRING, nIndex, 0L); nIndex=AddLinkLBItem(hListBox, lpOleUILinkCntr, lpLI, FALSE); if (lpLI->fIsSelected) { SendMessage(hListBox, LB_SETSEL, (WPARAM)TRUE, MAKELPARAM(nIndex, 0)); SendMessage(hListBox, LB_SETCARETINDEX, (WPARAM)nIndex, MAKELPARAM(TRUE, 0)); } bStop = FALSE; break; } } } while (!bStop); }