/* ** nextlink.CPP ** davidsan ** ** Next Link SSO */ #pragma warning(disable: 4237) // disable "bool" reserved #include "ssobase.h" #include "nextlink.h" //#include "resource.h" //#define DEBUGMEMLEAK #ifdef DEBUGMEMLEAK #include "crtdbg.h" _CrtMemState g_s1; #endif /*--------------------------------------------------------------------------+ | Local Prototypes | +--------------------------------------------------------------------------*/ HRESULT SSOGetNextURL(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOGetNextDescription(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOGetPreviousURL(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOGetPreviousDescription(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOGetNthURL(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOGetNthDescription(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOGetListCount(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOGetListIndex(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT SSOAbout(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff); HRESULT OnNewTemplate(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, LONG *plUser); HRESULT OnFreeTemplate(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, LONG *plUser); /*--------------------------------------------------------------------------+ | Globals We Have To Provide | +--------------------------------------------------------------------------*/ SSOMETHOD g_rgssomethod[] = { { L"GetNextURL", (PFNSSOMETHOD) SSOGetNextURL, 0 }, { L"GetNextDescription", (PFNSSOMETHOD) SSOGetNextDescription, 0 }, { L"GetPreviousURL", (PFNSSOMETHOD) SSOGetPreviousURL, 0 }, { L"GetPreviousDescription", (PFNSSOMETHOD) SSOGetPreviousDescription, 0 }, { L"GetNthURL", (PFNSSOMETHOD) SSOGetNthURL, 0 }, { L"GetNthDescription", (PFNSSOMETHOD) SSOGetNthDescription, 0 }, { L"GetListCount", (PFNSSOMETHOD) SSOGetListCount, 0 }, { L"GetListIndex", (PFNSSOMETHOD) SSOGetListIndex, 0 }, { L"About", (PFNSSOMETHOD) SSOAbout, 0 }, {c_wszOnNewTemplate, (PFNSSOMETHOD) OnNewTemplate, 0}, {c_wszOnFreeTemplate, (PFNSSOMETHOD) OnFreeTemplate, 0}, { NULL, NULL, 0 } }; PFNSSOMETHOD g_pfnssoDynamic = NULL; LPSTR g_szSSOProgID = "MSWC.NextLink"; BOOL g_fPersistentSSO = TRUE; GUID CDECL g_clsidSSO = CLSID_SSONextLink; /*--------------------------------------------------------------------------+ | Constants | +--------------------------------------------------------------------------*/ #define cnleNil -1 #define cchLinkMax 256 #define cchDescrMax 1024 #define DEFAULTSTRSIZE 1024 // size of localized text string /*--------------------------------------------------------------------------+ | CLinkFile | +--------------------------------------------------------------------------*/ // We use the CDataFile/CDataFileGroup classes from WCSUTIL.LIB to get // file lookup and hashing based on filename and notification when a file // is changed. Our CDataFile-derived CLinkFile builds a doubly-linked list // of NLE structures, one per line of the data file. typedef struct _nextlinkentry { struct _nextlinkentry *pnlePrev; struct _nextlinkentry *pnleNext; int inle; int urltype; char *szLink; OLECHAR *wszLink; char *szDescr; OLECHAR *wszDescr; } NLE, *PNLE; class CLinkFile : public CDataFile { public: CLinkFile(LPSTR szDataPath, CDataFileGroup *pdfg); ~CLinkFile(); PNLE NthPnle(int n); PNLE PnleForCurrentPage(SSSTUFF *pstuff); PNLE PnleHead() {return m_pnleHead;}; PNLE PnleTail() {return m_pnleTail;}; int Cnle(); virtual void FreeDataFile(void) { delete this; } private: int m_cnle; PNLE m_pnleHead; PNLE m_pnleTail; BOOL FLoadFile(); BOOL FParseData(char *szData); BOOL FAddEntry(char *szLink, char *szDescr); PNLE PnleForLink(char *szLink); void DeletePnleChain(PNLE pnle); }; /*--------------------------------------------------------------------------+ | CLinkFileGroup | +--------------------------------------------------------------------------*/ class CLinkFileGroup : public CDataFileGroup { public: virtual CDataFile *CreateDataFile(LPSTR szDataPath) { return((CDataFile*)(new CLinkFile(szDataPath, this))); } }; CLinkFileGroup g_dfg; /*--------------------------------------------------------------------------+ | CLinkFile | +--------------------------------------------------------------------------*/ CLinkFile::CLinkFile(LPSTR szDataPath, CDataFileGroup *pdfg) : CDataFile(szDataPath, pdfg) { m_cnle = cnleNil; m_pnleHead = NULL; m_pnleTail = NULL; } CLinkFile::~CLinkFile() { this->DeletePnleChain(m_pnleHead); #ifdef DEBUG ::FillMemory(this, sizeof(this), 0xAC); #endif } void CLinkFile::DeletePnleChain(PNLE pnle) { PNLE pnleNext; while (pnle) { pnleNext = pnle->pnleNext; if (pnle->wszLink) _MsnFree(pnle->wszLink); if (pnle->wszDescr) _MsnFree(pnle->wszDescr); if (pnle->szLink) _MsnFree(pnle->szLink); if (pnle->szDescr) _MsnFree(pnle->szDescr); _MsnFree(pnle); pnle = pnleNext; } } BOOL CLinkFile::FAddEntry(char *szLink, char *szDescr) { PNLE pnle = NULL; int cchLink = lstrlen(szLink); int cchDescr = lstrlen(szDescr); pnle = new NLE; if (!pnle) return FALSE; FillMemory(pnle, sizeof(NLE), 0); pnle->szLink = (char *)_MsnAlloc(cchLink + 1); pnle->szDescr = (char *)_MsnAlloc(cchDescr + 1); pnle->wszLink = (OLECHAR *)_MsnAlloc(sizeof(OLECHAR) * (cchLink + 1)); pnle->wszDescr = (OLECHAR *)_MsnAlloc(sizeof(OLECHAR) * (cchDescr + 1)); if (!pnle->wszLink || !pnle->wszDescr || !pnle->szLink || !pnle->szDescr) { if (pnle->wszLink) _MsnFree(pnle->wszLink); if (pnle->wszDescr) _MsnFree(pnle->wszDescr); if (pnle->szLink) _MsnFree(pnle->szLink); if (pnle->szDescr) _MsnFree(pnle->szDescr); _MsnFree(pnle); return FALSE; } lstrcpy(pnle->szLink, szLink); lstrcpy(pnle->szDescr, szDescr); MultiByteToWideChar(CP_ACP, 0, szLink, -1, pnle->wszLink, cchLink + 1); MultiByteToWideChar(CP_ACP, 0, szDescr, -1, pnle->wszDescr, cchDescr + 1); pnle->inle = ++m_cnle; pnle->urltype = UrlType(szLink); // possible cases: 1) no elements yet if (!m_pnleHead) { AssertSz(!m_pnleTail, "nice list handling"); AssertSz(m_cnle == 1, "nice list handling, doofus"); m_pnleHead = m_pnleTail = pnle; return TRUE; } else { AssertSz(m_pnleTail, "how can this be NULL"); } // 2) only one element if (m_pnleHead == m_pnleTail) { AssertSz(m_cnle == 2, "more nice list handling"); m_pnleTail = pnle; pnle->pnlePrev = m_pnleHead; m_pnleHead->pnleNext = pnle; return TRUE; } // 3) two or more elements AssertSz(m_cnle > 2, "ut oh, why do we have fewer than 3 elements in our list"); m_pnleTail->pnleNext = pnle; pnle->pnlePrev = m_pnleTail; m_pnleTail = pnle; return TRUE; } // The data file consists of a series of lines. Each line has at least two fields, // separated by exactly one tab character. The second field can be terminated either // by a tab character or by the end of the line. BOOL CLinkFile::FParseData(char *szData) { char *pch; char *pchLine; char *pchTab; char *szLink; char *szDescr; pch = szData; while (*pch) { pchLine = pch; while (*pch && (*pch != '\n' && *pch != '\r')) pch = CharNext(pch); // skip blank lines (this will also take care of crlf line termination) if (pch - pchLine <= 1) { pch++; continue; } pchTab = pchLine; while (pchTab < pch) { if (*pchTab == '\t') break; pchTab = CharNext(pchTab); } // there were no tabs on this line. skip the whole line. if (pchTab >= pch) continue; *pchTab++ = 0; szLink = pchLine; szDescr = pchTab; while (pchTab < pch) { if (*pchTab == '\t') break; pchTab = CharNext(pchTab); } if ((pchTab == pch) && *pch) pch++; *pchTab++ = 0; if (!this->FAddEntry(szLink, szDescr)) return FALSE; } return TRUE; } BOOL CLinkFile::FLoadFile() { BOOL fRet = FALSE; char *szData = NULL; DWORD cb; DWORD cbRead; HANDLE hfile = INVALID_HANDLE_VALUE; m_cs.Lock(); if (!m_cnle) { // there was a problem loading the file. goto LBail; } if (m_cnle != cnleNil) { // we've already successfully loaded! fRet = TRUE; goto LBail; } hfile = CreateFile(m_szDataPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hfile == INVALID_HANDLE_VALUE) goto LBail; cb = GetFileSize(hfile, NULL); if (cb == 0xFFFFFFFF) goto LBail; szData = (char *)_MsnAlloc(cb + 1); if (!szData) goto LBail; if (!ReadFile(hfile, szData, cb, &cbRead, NULL) || cb != cbRead) goto LBail; szData[cb] = 0; m_cnle = 0; fRet = this->FParseData(szData); if (fRet) { if (!this->FWatchFile()) fRet = FALSE; } LBail: m_cs.Unlock(); if (szData) _MsnFree(szData); if (hfile != INVALID_HANDLE_VALUE) CloseHandle(hfile); return fRet; } // returns pointer within szLink after any path info, so after the last // '/' or '\\' char * SzRelLink(char *szLink) { char *pchLastSlash = szLink - 1; while (*szLink) { if (*szLink == '/' || *szLink == '\\') pchLastSlash = szLink; szLink = CharNext(szLink); } return pchLastSlash + 1; } PNLE CLinkFile::PnleForLink(char *szLink) { PNLE pnle; char *szRelLink = NULL; if (!m_pnleHead || !m_pnleTail || !m_cnle) return NULL; pnle = m_pnleHead; while (pnle) { switch (pnle->urltype) { case URL_TYPE_ABSOLUTE: // we can't ever match absolute URLs ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANT_MATCH_ABSOLUTE_URLS); break; case URL_TYPE_LOCAL_ABSOLUTE: if (!lstrcmp(pnle->szLink, szLink)) return pnle; break; case URL_TYPE_RELATIVE: // only compute this once if (!szRelLink) szRelLink = SzRelLink(szLink); if (!lstrcmp(pnle->szLink, szRelLink)) return pnle; break; } pnle = pnle->pnleNext; } return NULL; } PNLE CLinkFile::PnleForCurrentPage(SSSTUFF *pstuff) { PNLE pnle = NULL; char *szLink; DWORD cb; IRequest *preq; VARIANT varPathInfo; IDispatch *pDispPathInfo; IScriptingContext *pcxt= NULL; HRESULT hr; m_cs.Lock(); if (this->FLoadFile()) { cb = MAX_PATH; if (FAILED(pstuff->punk->QueryInterface(IID_IScriptingContext, reinterpret_cast(&pcxt)))) goto LBail; if (FAILED(pcxt->get_Request(&preq))) goto LBail; hr = preq->get_Item(L"PATH_INFO", &pDispPathInfo); preq->Release(); if (FAILED(hr)) goto LBail; V_VT(&varPathInfo) = VT_DISPATCH; V_DISPATCH(&varPathInfo) = pDispPathInfo; szLink = _SzFromVariant(&varPathInfo); if (!szLink) goto LBail; pnle = this->PnleForLink(szLink); _MsnFree(szLink); } else { //char szError[256]; ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_OPEN_FILE); DebugOutputDebugString("MSWC.NextLink, bogus file, exception raised.\n"); } LBail: if (pcxt) { pcxt->Release(); } ::VariantClear(&varPathInfo); m_cs.Unlock(); return pnle; } // n is 1-based! PNLE CLinkFile::NthPnle(int n) { PNLE pnle = NULL; m_cs.Lock(); if (this->FLoadFile()) { pnle = m_pnleHead; while (pnle) { if (pnle->inle == n) break; pnle = pnle->pnleNext; } } m_cs.Unlock(); return pnle; } int CLinkFile::Cnle() { int cnle = 0; m_cs.Lock(); if (this->FLoadFile()) cnle = m_cnle; m_cs.Unlock(); return cnle; } /*--------------------------------------------------------------------------+ | External Interface | +--------------------------------------------------------------------------*/ // This is weird, but i hate checking cArgs all over the place. So since all // my exported APIs have one of two arg formats [either function("data file") // or function("data file", number)], I do all the arg checking in this // routine. If pn is non-NULL, it means we're expecting a number as a second // argument (note that since the args come in in reverse order, we look at // rgvarg[0]). HRESULT HrCheckParams(DISPPARAMS *pdispparams, int *pn) { unsigned int cArgs = 1; if (pn) cArgs = 2; if (pdispparams->cArgs < cArgs) return DISP_E_PARAMNOTOPTIONAL; if (pdispparams->cArgs > cArgs) return DISP_E_PARAMNOTFOUND; if (pn) { if (!_FIntFromVariant(&pdispparams->rgvarg[0], pn)) return E_FAIL; } return NOERROR; } HRESULT SSOGetNextURL(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; PNLE pnle; hr = HrCheckParams(pdispparams, NULL); if (FAILED(hr)) return hr; hr = SSOTranslateVirtualRoot(pdispparams->rgvarg, pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETNEXTURL); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; pnle = plf->PnleForCurrentPage(pstuff); if (pnle) { pnle = pnle->pnleNext; // if no more, loop if (!pnle) pnle = plf->PnleHead(); } else { pnle = plf->PnleTail(); } if (!pnle) return E_FAIL; ::VariantInit(pvarResult); pvarResult->vt = VT_BSTR; V_BSTR(pvarResult) = ::SysAllocString(pnle->wszLink); return NOERROR; } HRESULT SSOGetNextDescription(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; PNLE pnle; hr = HrCheckParams(pdispparams, NULL); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_BAD_PARAMETERS_GETNEXTDESCRIPTION); return hr; } hr = SSOTranslateVirtualRoot(pdispparams->rgvarg, pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETNEXTDESCRIPTION); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; pnle = plf->PnleForCurrentPage(pstuff); if (pnle) { pnle = pnle->pnleNext; // if no more, loop if (!pnle) pnle = plf->PnleHead(); } else { pnle = plf->PnleTail(); } if (!pnle) return E_FAIL; ::VariantInit(pvarResult); pvarResult->vt = VT_BSTR; V_BSTR(pvarResult) = ::SysAllocString(pnle->wszDescr); return NOERROR; } HRESULT SSOGetPreviousURL(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; PNLE pnle; hr = HrCheckParams(pdispparams, NULL); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_BAD_PARAMETERS_SSOGETPREVIOUSURL); return hr; } hr = SSOTranslateVirtualRoot(pdispparams->rgvarg, pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETPREVIOUSURL); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; pnle = plf->PnleForCurrentPage(pstuff); if (pnle) { pnle = pnle->pnlePrev; // if no more, loop if (!pnle) pnle = plf->PnleTail(); } else { pnle = plf->PnleHead(); } if (!pnle) return E_FAIL; ::VariantInit(pvarResult); pvarResult->vt = VT_BSTR; V_BSTR(pvarResult) = ::SysAllocString(pnle->wszLink); return NOERROR; } HRESULT SSOGetPreviousDescription(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; PNLE pnle; hr = HrCheckParams(pdispparams, NULL); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_BAD_PARAMETERS_GETPREVDESCRIPTION); return hr; } hr = SSOTranslateVirtualRoot(pdispparams->rgvarg, pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETPREVIOUSDDESCRIPTION); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; pnle = plf->PnleForCurrentPage(pstuff); if (pnle) { pnle = pnle->pnlePrev; // if no more, loop if (!pnle) pnle = plf->PnleTail(); } else { pnle = plf->PnleHead(); } if (!pnle) return E_FAIL; ::VariantInit(pvarResult); pvarResult->vt = VT_BSTR; V_BSTR(pvarResult) = ::SysAllocString(pnle->wszDescr); return NOERROR; } HRESULT SSOGetNthURL(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; PNLE pnle; int n; hr = HrCheckParams(pdispparams, &n); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_BAD_PARAMETERS_GETNTHURL); return hr; } hr = SSOTranslateVirtualRoot(&pdispparams->rgvarg[1], pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETNTHURL); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; pnle = plf->NthPnle(n); if (!pnle) pnle = plf->PnleTail(); if (!pnle) return E_FAIL; ::VariantInit(pvarResult); pvarResult->vt = VT_BSTR; V_BSTR(pvarResult) = ::SysAllocString(pnle->wszLink); return NOERROR; } HRESULT SSOGetNthDescription(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; PNLE pnle; int n; hr = HrCheckParams(pdispparams, &n); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_BAD_PARAMETERS_GETNTHDESCRIPTION); return hr; } hr = SSOTranslateVirtualRoot(&pdispparams->rgvarg[1], pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETNTHDESCRIPTION); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; pnle = plf->NthPnle(n); if (!pnle) pnle = plf->PnleTail(); if (!pnle) return E_FAIL; ::VariantInit(pvarResult); pvarResult->vt = VT_BSTR; V_BSTR(pvarResult) = ::SysAllocString(pnle->wszDescr); return NOERROR; } HRESULT SSOGetListCount(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; hr = HrCheckParams(pdispparams, NULL); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_BAD_PARAMETERS_GETLISTCOUNT); return hr; } hr = SSOTranslateVirtualRoot(pdispparams->rgvarg, pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETLISTCOUNT); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; ::VariantInit(pvarResult); pvarResult->vt = VT_I4; V_I4(pvarResult) = plf->Cnle(); return NOERROR; } HRESULT SSOGetListIndex(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { HRESULT hr; char szPathTranslated[MAX_PATH]; CLinkFile *plf; PNLE pnle; int inle; hr = HrCheckParams(pdispparams, NULL); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_BAD_PARAMETERS_GETLISTINDEX); return hr; } hr = SSOTranslateVirtualRoot(pdispparams->rgvarg, pstuff->punk, szPathTranslated, sizeof(szPathTranslated)); if (FAILED(hr)) { ExceptionId(g_clsidSSO, SSO_NEXTLINK, SSO_CANNOT_XLATE_VIRT_ROOT_GETLISTINDEX); return hr; } plf = (CLinkFile *)g_dfg.GetDataFile(szPathTranslated); if (!plf) return E_FAIL; pnle = plf->PnleForCurrentPage(pstuff); if (pnle) inle = pnle->inle; else inle = 0; ::VariantInit(pvarResult); pvarResult->vt = VT_I4; V_I4(pvarResult) = inle; return NOERROR; } HRESULT SSOAbout(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, SSSTUFF *pstuff) { char sz[MAX_PATH]; CHAR szNextLinkAboutFormat[DEFAULTSTRSIZE]; OLECHAR wsz[MAX_PATH]; #ifdef _DEBUG char *szVersion = "Debug"; #else char *szVersion = "Release"; #endif CchLoadStringOfId(SSO_NEXTLINK_ABOUT_FORMAT, szNextLinkAboutFormat, DEFAULTSTRSIZE); wsprintf(sz, szNextLinkAboutFormat, szVersion, __DATE__, __TIME__); ::MultiByteToWideChar(CP_ACP, 0, sz, -1, wsz, sizeof(wsz) / sizeof(OLECHAR)); VariantInit(pvarResult); pvarResult->vt = VT_BSTR; V_BSTR(pvarResult) = ::SysAllocString(wsz); return(NOERROR); } // ============================== OnNewTemplate =============================== HRESULT OnNewTemplate(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, LONG *plUser) { #ifdef DEBUGMEMLEAK // _MsnAlloc(100); #endif return NOERROR; } // ============================== OnFreeTemplate ============================== HRESULT OnFreeTemplate(WORD wInvokeFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult, LONG *plUser) { return NOERROR; } /*--------------------------------------------------------------------------+ | DllMain | +--------------------------------------------------------------------------*/ BOOL WINAPI DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: #ifdef DEBUGMEMLEAK int tmpDbgFlag; tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF; _CrtSetDbgFlag(tmpDbgFlag); _CrtMemCheckpoint(&g_s1); #endif break; case DLL_PROCESS_DETACH: #ifdef DEBUGMEMLEAK _CrtMemDumpAllObjectsSince(&g_s1); #endif break; default: break; } if (!SSODllMain(hInstance, ulReason, pvReserved)) return(FALSE); return(TRUE); }