2025-04-27 07:49:33 -04:00

993 lines
22 KiB
C++

/*
** 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<void **>(&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);
}