Figure 2 Grabbing Dynamic Content
Public Function GetForecast(sAirport As String) As String
Dim oIE As New InternetExplorer
On Error Resume Next
' Check for offline mode
If (oIE.Offline = True) Then
GetForecast = "Offline"
Exit Function
End If
' Don't show any dialogs
oIE.Silent = True
' Post the data to the server
oIE.Navigate "https://www.msnbc.com/news/wea_front.asp?faa=" & _
sAirport & "&view=local&area=usa"
' Wait for the results
Dim iCount
Do While True
If (oIE.ReadyState = 3) Then
If (oIE.Document.ReadyState = "interactive") Then
Dim iPos As Integer, iLen As Integer, sDocument As String
Const sConditions = "strConditions="""
Const sForecast = "strForecast="""
sDocument = oIE.Document.Body.innerHTML
' Parse out the local conditions
iPos = InStr(1, sDocument, sConditions) + _
Len(sConditions)
iLen = InStr(iPos, sDocument, """;") - iPos
If (iPos > 15 And iLen >< 0) Then
GetForecast = Mid(sDocument, iPos, iLen)
' Parse out the forecast
iPos = InStr(1, sDocument, sForecast) + _
Len(sForecast)
iLen = InStr(iPos, sDocument, """;") - iPos
GetForecast = GetForecast + "!" + Mid(sDocument, _
iPos, iLen)
Exit Do
End If
End If
End If
iCount = iCount + 1
If iCount > 60 Then Exit Do ' Timeout is set for 30 seconds
Sleep 500 ' Wait 1/2 second
Loop
' Close and quit this copy of Internet Explorer
oIE.Quit
Set oIE = Nothing
End Function
Figure 4 Creating a Table
function ChangeTime()
{
var e = window.event.srcElement;
var group = e.parentElement.children;
for(var i=0; i<group.length; i++)
group[i].style.fontWeight = "normal";
e.style.fontWeight = 'bold';
DisplayHeadcount(); //causes the table to be refreshed
}
function GenerateTableHeader(s, e, oTable)
{
var sMonths = new Array('January','February','March','April','May','June','July','August','September',
'October','November','December');
var nMonths = 0;
oRow = oTable.insertRow();
oCell = oRow.insertCell();
oCell.innerHTML = " ";
oCell.rowSpan = 2;
oCell.style.borderBottom = "1px solid black";
for(var dt= new Date(s); dt<=e; dt.setMonth(dt.getMonth()+1),nMonths++)
{
oCell = oRow.insertCell();
oCell.innerHTML = sMonths[dt.getMonth()];
oCell.style.fontWeight = "bold";
oCell.align = "center";
oCell.colSpan = 2;
}
oRow = document.all.hc_headcount.insertRow();
for(var i=0; i<nMonths; i++)
{
oCell = oRow.insertCell();
oCell.style.padding = "4px";
oCell.style.borderBottom = "1px solid black";
oCell.innerHTML = "Budget";
oCell = oRow.insertCell();
oCell.innerHTML = "Actual";
oCell.style.padding = "4px";
oCell.style.borderBottom = "1px solid black";
}
return nMonths;
}
function BuildHeadcount(d, s, e)
{
var oTable = document.all.hc_headcount;
// Remove old rows
with(oTable)
{
while(rows.length > 0)
deleteRow();
}
// Build the query
var sSQL = "SELECT Month, SUM(ActualHC) AS Actual,
Sum(BudgetHC) AS Budget
FROM HeadCount h "
// Query the database
var r = oConn.Execute(sSQL);
// Generate header
var nMonths = GenerateTableHeader(s, e, oTable);
// Generate HTML
while(!r.EOF)
{
// Put in the month's numbers (budget & actual)
oCell = oRow.insertCell();
oCell.align = "right";
oCell.innerHTML = r("Budget").Value;
oCell = oRow.insertCell();
oCell.align = "right";
oCell.innerHTML = r("Actual").Value;
// Advance to the next record
r.moveNext();
}
}
Figure 6 Start Nugget Wrapper Arguments
Argument |
Description |
sNugget |
Unique ID of the nugget |
sTitle |
Title to place in the title bar of the nugget |
iHeight |
Default height of the nugget |
fMinimized |
Indicates whether the nugget should start in the minimized state |
Figure 7 Nugget Wrapper
<style type="text/css">
.nugget { border: 1px solid black; background-color: white }
.nuggetTitle { cursor:default; border:2px groove lightsteelblue; font: 11pt; color: white; background-color: steelblue; width:100% }
.nuggetButtonWrapper { background-color: steelblue; border: 2px groove lightsteelblue; vertical-align:middle }
</style>
function StartNuggetWrapper(sNugget, sTitle, iHeight, fMinimized)
{
var sStyle = "style='";
var sHTML = "<div class='nugget' id='" + sNugget + "'>" &_
"<table id='nuggetTable' border='0' cellpadding='0'" &_
"cellspacing='0'><tr><td nowrap width='100%'>";
sHTML += "<span id='maximize' ondblclick='toggleMaxMin();'" &_
"title='Double click to maximize' valign='center' ";
sHTML += "class='nuggetTitle'>" + sTitle + "</span></td>" &_
"<td nowrap class='nuggetButtonWrapper'>";
sHTML += "<img id='toggle' src='images/close.gif' width='13px'" &_
"height='17px' title='Hide'>";
sHTML += "</td></tr></table><div ";
if (0 != iHeight)
sStyle += "height:" + iHeight;
if (true == fMinimized)
sStyle += ";display:none";
if ("style='" != sStyle)
sHTML += sStyle + "'";
sHTML += " valign='top' id='content' width='100%'>";
return sHTML;
}
Figure 8 toggleMaxMin
function toggleMaxMin()
{
var e = window.event.srcElement;
var p = FindParentElement(e, "DIV");
var t = FindParentElement(p, "TABLE");
with(p.style)
{
if ('absolute' == position)
{
position = '';
height = '';
width = '';
left = '';
top = '';
zIndex = '';
e.title = 'Double click to maximize';
ToggleSiblingDisplay(p);
}
else
{
position = 'absolute';
height = t.parentElement.clientHeight;
width = t.clientWidth;
left = t.offsetLeft;
top = t.offsetTop;
zIndex = 100;
e.title = 'Double click to minimize';
ToggleSiblingDisplay(p);
}
}
p.document.recalc(true);
}
Figure 9 Building a Pivot Table
<html>
<body>
<OBJECT classid=clsid:0002E520-0000-0000-C000-000000000046
id=cht style="HEIGHT: 100%; WIDTH: 100%">
<PARAM NAME="ScreenUpdating" VALUE="-1" ></OBJECT>
<script defer language="javascript">
var oTable = document.all.cht;
oTable.ConnectionString = "provider=msolap;data source=c:\\warecube.cub";
oTable.DataMember = "MyCube";
var oView = oTable.ActiveView; // Get the view
var oConstants = oTable.Constants; // Get the constants
oView.AutoLayout(); // Clear the view
// For more samples see
// Programming Office 2000 Web Components
with(oView)
{
FilterAxis.InsertFieldSet(FieldSets("Product"));
// Allow filtering of the data by product
RowAxis.InsertFieldSet(FieldSets("Column"));
// Put time on the left
ColumnAxis.InsertFieldSet(FieldSets("Store"));
// and Store on the top
DataAxis.InsertTotal(Totals("Units Ordered"));
DataAxis.InsertTotal(Totals("Units Shipped"));
// here are the data fields
DataAxis.InsertTotal(Totals("Store Invoice"));
Totals("Units Ordered").NumberFormat = "#,##0";
// format the numbers
Totals("Units Shipped").NumberFormat = "#,##0";
// format the numbers
Totals("Store Invoice").NumberFormat = "$#,##0";
// format the numbers
}
</script>
</body>
</html>
Figure 11 Generating an Offline Cube
D Dim cnCube As ADODB.Connection
Dim s As String
Dim strProvider As String
Dim strDataSource As String
Dim strSourceDSN As String
Dim strSourceDSNSuffix As String
Dim strCreateCube As String
Dim strInsertInto As String
On Error GoTo Error_cmdCreateCubeFromDatabase
'*
'* Add Provider that will process the connection string.
'*
strProvider = "PROVIDER=MSOLAP"
'*
'* Add DataSource, the name of the cube file (.cub)
'* that will be created.
'*
strDataSource = "DATA SOURCE=c:\warecube.cub"
'*
'* Add Source DSN, the connection string for where the data comes from.
'* We need to quote the value so it is parsed as one value.
'* This can either be an ODBC connection string or
'* an OLE DB connection string.
'* (As returned by the Data Source Locator component.)
'*
'* strSourceDSN = "SOURCE_DSN=""DRIVER=Microsoft Access Driver
'* (*.mdb);DBQ=\\machue1\Samples\Sales.MDB"";"
'*
'*
strSourceDSN = "SOURCE_DSN=FoodMart"
'*
'* We may have some other parameters that we want applied
'* at run time, but not stored in the cube file,
'* or returned in the output string.
'* Example:
'* strSourceDSNSuffix = "UID=;PWD="
'*
'*
'* Add CREATE CUBE. This defines the structure of the cube,
'* but not the data in it.
'* The BNF for this statement is in the
'* Microsoft SQL Server OLAP Services documentation.
'* Note: The names are quoted with square brackets.
'*
strCreateCube = "CREATECUBE=CREATE CUBE Mycube( "
strCreateCube = strCreateCube & "DIMENSION [Product],"
strCreateCube = strCreateCube & "LEVEL [All Products] TYPE ALL,"
strCreateCube = strCreateCube & "LEVEL [Product Family] ,"
strCreateCube = strCreateCube & "LEVEL [Product Department] ,"
strCreateCube = strCreateCube & "LEVEL [Product Category] ,"
strCreateCube = strCreateCube & "LEVEL [Product Subcategory] ,"
strCreateCube = strCreateCube & "LEVEL [Brand Name] ,"
strCreateCube = strCreateCube & "LEVEL [Product Name] ,"
strCreateCube = strCreateCube & "DIMENSION [Store],"
strCreateCube = strCreateCube & "LEVEL [All Stores] TYPE ALL,"
strCreateCube = strCreateCube & "LEVEL [Store Country] ,"
strCreateCube = strCreateCube & "LEVEL [Store State] ,"
strCreateCube = strCreateCube & "LEVEL [Store City] ,"
strCreateCube = strCreateCube & "LEVEL [Store Name] ,"
strCreateCube = strCreateCube & "DIMENSION [Store Type],"
strCreateCube = strCreateCube & "LEVEL [All Store Type] TYPE ALL,"
strCreateCube = strCreateCube & "LEVEL [Store Type] ,"
strCreateCube = strCreateCube & "DIMENSION [Time] TYPE TIME,"
strCreateCube = strCreateCube & "HIERARCHY [Column],"
strCreateCube = strCreateCube & "LEVEL [All Time] TYPE ALL,"
strCreateCube = strCreateCube & "LEVEL [Year] TYPE YEAR,"
strCreateCube = strCreateCube & "LEVEL [Quarter] TYPE QUARTER,"
strCreateCube = strCreateCube & "LEVEL [Month] TYPE MONTH,"
strCreateCube = strCreateCube & "LEVEL [Week] TYPE WEEK,"
strCreateCube = strCreateCube & "LEVEL [Day] TYPE DAY,"
strCreateCube = strCreateCube & "HIERARCHY [Formula],"
strCreateCube = strCreateCube & "LEVEL [All Formula Time] TYPE ALL,"
strCreateCube = strCreateCube & "LEVEL [Year] TYPE YEAR,"
strCreateCube = strCreateCube & "LEVEL [Quarter] TYPE QUARTER,"
strCreateCube = strCreateCube & "LEVEL [Month] TYPE MONTH OPTIONS" &_
"(SORTBYKEY) ,"
strCreateCube = strCreateCube & "DIMENSION [Warehouse],"
strCreateCube = strCreateCube & "LEVEL [All Warehouses] TYPE ALL,"
strCreateCube = strCreateCube & "LEVEL [Country] ,"
strCreateCube = strCreateCube & "LEVEL [State Province] ,"
strCreateCube = strCreateCube & "LEVEL [City] ,"
strCreateCube = strCreateCube & "LEVEL [Warehouse Name] ,"
strCreateCube = strCreateCube & "MEASURE [Store Invoice] "
strCreateCube = strCreateCube & "Function Sum "
strCreateCube = strCreateCube & "Format '#.#',"
strCreateCube = strCreateCube & "MEASURE [Supply Time] "
strCreateCube = strCreateCube & "Function Sum "
strCreateCube = strCreateCube & "Format '#.#',"
strCreateCube = strCreateCube & "MEASURE [Warehouse Cost] "
strCreateCube = strCreateCube & "Function Sum "
strCreateCube = strCreateCube & "Format '#.#',"
strCreateCube = strCreateCube & "MEASURE [Warehouse Sales] "
strCreateCube = strCreateCube & "Function Sum "
strCreateCube = strCreateCube & "Format '#.#',"
strCreateCube = strCreateCube & "MEASURE [Units Shipped] "
strCreateCube = strCreateCube & "Function Sum "
strCreateCube = strCreateCube & "Format '#.#',"
strCreateCube = strCreateCube & "MEASURE [Units Ordered] "
strCreateCube = strCreateCube & "Function Sum "
strCreateCube = strCreateCube & "Format '#.#')"
Figure 13 SyncMgr IDL
// ERDDSyncMgr.idl : IDL source for ERDDSyncMgr.dll
//
// This file will be processed by the MIDL tool to
// produce the type library (ERDDSyncMgr.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(51194C1B-116A-4EFF-A20C-7322B95ECB7E),
helpstring("IDDSyncMgr Interface"),
pointer_default(unique)
]
interface IDDSyncMgr : IUnknown
{
};
[
object,
uuid(2B9CFF60-41AF-4287-9FB1-574DEE547974),
helpstring("IDDSyncEnum Interface"),
pointer_default(unique)
]
interface IDDSyncEnum : IUnknown
{
};
[
uuid(96CB177C-122B-4C5D-8B34-0532C7E4F11A),
version(1.0),
helpstring("ERDDSyncMgr 1.0 Type Library")
]
library ERDDSYNCMGRLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(C7C5F46F-DA9F-4442-A8BE-6FA9A4E72B16),
helpstring("DDSyncMgr Class")
]
coclass DDSyncMgr
{
[default] interface IDDSyncMgr;
};
[
uuid(E64FFE15-15F4-4177-81FF-22AA9984D8C2),
helpstring("DDSyncEnum Class")
]
coclass DDSyncEnum
{
[default] interface IDDSyncEnum;
};
};
Figure 14 SyncMgr Header
// DDSyncMgr.h : Declaration of the CDDSyncMgr
#ifndef __DDSYNCMGR_H_
#define __DDSYNCMGR_H_
#include "resource.h" // main symbols
#include "DDSyncEnum.h" // Enumerator
#if FILEOUTPUT
#include <fstream.h> // File stream library
#endif
// Forward declaration
class CDDSyncMgr;
// List node defintion
typedef struct _Node
{
WCHAR src[MAX_PATH+1];
WCHAR dest[MAX_PATH+1];
SYNCMGRITEMID id;
int type;
BOOL bReadyToSync;
CDDSyncMgr * parent;
} NODE, *LPNODE;
typedef enum DDSyncMgrStatus { NONE=0, SYNC=1, EXIT=-1 };
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr
class ATL_NO_VTABLE CDDSyncMgr :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CDDSyncMgr, &CLSID_DDSyncMgr>,
public IDDSyncMgr,
public ISyncMgrSynchronize
{
friend class CDDSyncEnum;
public:
CDDSyncMgr();
~CDDSyncMgr();
DECLARE_REGISTRY_RESOURCEID(IDR_DDSYNCMGR)
DECLARE_NOT_AGGREGATABLE(CDDSyncMgr)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CDDSyncMgr)
COM_INTERFACE_ENTRY(IDDSyncMgr)
COM_INTERFACE_ENTRY(ISyncMgrSynchronize)
END_COM_MAP()
// IDDSyncMgr
public:
STDMETHOD(Initialize)(DWORD dwReserved, DWORD dwSyncMgrFlags, DWORD
cbCookie, const BYTE __RPC_FAR *lpCookie);
STDMETHOD(GetHandlerInfo)(LPSYNCMGRHANDLERINFO __RPC_FAR
*ppSyncMgrHandlerInfo);
STDMETHOD(EnumSyncMgrItems)(ISyncMgrEnumItems __RPC_FAR *__RPC_FAR
*ppSyncMgrEnumItems);
STDMETHOD(GetItemObject)(REFSYNCMGRITEMID ItemID, REFIID riid, void
__RPC_FAR *__RPC_FAR *ppv);
STDMETHOD(ShowProperties)(HWND hWndParent, REFSYNCMGRITEMID ItemID);
STDMETHOD(SetProgressCallback)(ISyncMgrSynchronizeCallback __RPC_FAR
*lpCallBack);
STDMETHOD(PrepareForSync)(ULONG cbNumItems, SYNCMGRITEMID __RPC_FAR
*pItemIDs, HWND hWndParent, DWORD dwReserved);
STDMETHOD(Synchronize)(HWND hWndParent);
STDMETHOD(SetItemStatus)(REFSYNCMGRITEMID pItemID, DWORD
dwSyncMgrStatus);
STDMETHOD(ShowError)(HWND hWndParent, REFSYNCMGRERRORID ErrorID);
private:
int m_cItems;
int m_maxItems;
LPNODE m_Items;
HANDLE m_hThread;
HANDLE m_hEvent;
DDSyncMgrStatus m_iStatus;
ISyncMgrSynchronizeCallback *m_pCallback;
STDMETHOD(AddItem)(LPWSTR sID, LPWSTR src, LPWSTR dest, int type);
STDMETHOD(SyncFiles)();
STDMETHOD(Progress)(REFSYNCMGRITEMID pItemID, UINT mask,
TCHAR *pStatusText, DWORD dwStatusType, int iProgValue,
int iMaxValue);
STDMETHOD(CheckFileDates)(LPWSTR src, LPWSTR dest);
#ifdef FILEOUTPUT
ofstream m_outDebug;
#endif
static DWORD WINAPI ThreadProc(LPVOID);
static DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER,
LARGE_INTEGER, LARGE_INTEGER, LARGE_INTEGER,
DWORD, DWORD, HANDLE, HANDLE, LPVOID);
};
#endif //__DDSYNCMGR_H_
Figure 15 SyncMgr Implementation
// DDSyncMgr.cpp : Implementation of CDDSyncMgr
#include "stdafx.h"
#include "ERDDSyncMgr.h"
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename ("EOF", "adoEOF")
#include "DDSyncMgr.h"
struct InitOle
{
InitOle() { ::CoInitialize(NULL); }
~InitOle() { ::CoUninitialize(); }
} _init_InitOle_;
//HANDLE CDDSyncMgr::m_hEvent = NULL;
//DDSyncMgrStatus CDDSyncMgr::m_iStatus = NONE;
///////////////////////////////////////////////////////////////////////////
// Constants
LPCWSTR szName = L"East Region Digital Dashboard";
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::CDDSyncMgr
///////////////////////////////////////////////////////////////////////////
CDDSyncMgr::CDDSyncMgr()
{
m_cItems = 0;
m_maxItems = 0;
m_Items = NULL;
m_hThread = NULL;
#ifdef FILEOUTPUT
m_outDebug.open("C:\\SyncMgrDebug.txt");
m_outDebug << "CDDSyncMgr::CDDSyncMgr\n";
#endif
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::~CDDSyncMgr
///////////////////////////////////////////////////////////////////////////
CDDSyncMgr::~CDDSyncMgr()
{
// Clean up the worker thread
if (NULL != m_hThread)
{
// Set the exit code for the thread and signal the worker thread
m_iStatus = EXIT;
SetEvent(m_hEvent);
if (WaitForSingleObject(m_hThread, 5000) != WAIT_OBJECT_0)
TerminateThread(m_hThread, 0);
// Close the handle to the thread
CloseHandle(m_hThread);
m_hThread = NULL;
}
if (NULL != m_hEvent)
{
CloseHandle(m_hEvent);
m_hEvent = NULL;
}
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::~CDDSyncMgr\n";
m_outDebug.close();
#endif
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::Initialize
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::Initialize(DWORD dwReserved,
DWORD dwSyncMgrFlags,
DWORD cbCookie,
const BYTE __RPC_FAR *lpCookie)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::Initialize\n";
#endif
HRESULT hr = S_OK;
_RecordsetPtr rs = NULL;
try
{
// Create the event and thread
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == m_hEvent)
return S_FALSE;
m_hThread = CreateThread(NULL, 0, ThreadProc, this, 0, NULL);
if (NULL == m_hThread)
return S_FALSE;
// open a connection to the local database
_bstr_t Connect(TEXT("Driver={SQL
Server};Network=dbnmpntw;Server=(local);Database=DigitalDashboard"));
_bstr_t Source(TEXT("SELECT * FROM Synchronization"));
// create a recordset and execute a query
rs.CreateInstance(__uuidof(Recordset));
hr = rs->Open(Source, Connect, adOpenForwardOnly, adLockReadOnly, -1);
// populate the list of files to synchronize
while(!rs->adoEOF)
{
_variant_t v;
_variant_t vOffset;
// Get the item ID
vOffset = (short) 0;
_variant_t vID = rs->Fields->GetItem(vOffset)->GetValue();
// Get the source
vOffset = (short) 1;
_variant_t vSrc = rs->Fields->GetItem(vOffset)->GetValue();
// get the destination
vOffset = (short) 2;
_variant_t vDest = rs->Fields->GetItem(vOffset)->GetValue();
// get the type
vOffset = (short) 3;
_variant_t vType = rs->Fields->GetItem(vOffset)->GetValue();
// Add the item to the list
AddItem(vID.bstrVal, vSrc.bstrVal, vDest.bstrVal,
vType.intVal);
// advance to the next item
rs->MoveNext();
}
// close the recordset
rs->Close();
rs = NULL;
}
catch(_com_error &e)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::Initialize Error: " << e.Description()
<< "\n";
#endif
hr = S_FALSE;
}
#ifdef FILEOUTPUT
if (S_FALSE == hr)
m_outDebug << "CDDSyncMgr::Initialize - returning: S_FALSE\n";
else
m_outDebug << "CDDSyncMgr::Initialize - returning: S_OK\n";
#endif
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::GetHandlerInfo
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::GetHandlerInfo(LPSYNCMGRHANDLERINFO __RPC_FAR
*ppSyncMgrHandlerInfo)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::GetHandlerInfo\n";
#endif
if (NULL == ppSyncMgrHandlerInfo)
return E_INVALIDARG;
HRESULT hr = S_OK;
DWORD dwSize = sizeof(SYNCMGRHANDLERINFO);
// Allocate the return structure
*ppSyncMgrHandlerInfo = (LPSYNCMGRHANDLERINFO)
HeapAlloc(GetProcessHeap(), 0, dwSize);
if (NULL == *ppSyncMgrHandlerInfo)
return E_OUTOFMEMORY;
(*ppSyncMgrHandlerInfo)->cbSize = sizeof(SYNCMGRHANDLERINFO);
(*ppSyncMgrHandlerInfo)->hIcon = LoadIcon(_Module.m_hInst,
_T("IDI_ICON"));
(*ppSyncMgrHandlerInfo)->SyncMgrHandlerFlags = 0;
lstrcpyn((*ppSyncMgrHandlerInfo)->wszHandlerName, szName,
MAX_SYNCMGRHANDLERNAME);
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::EnumSyncMgrItems
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::EnumSyncMgrItems(ISyncMgrEnumItems __RPC_FAR
*__RPC_FAR *ppSyncMgrEnumItems)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::EnumSyncMgrItems\n";
#endif
if (NULL == ppSyncMgrEnumItems)
return E_INVALIDARG;
HRESULT hr =
CComCoClass<CDDSyncEnum>::CreateInstance(ppSyncMgrEnumItems);
if (SUCCEEDED(hr))
((CDDSyncEnum *) *ppSyncMgrEnumItems)->SetSyncMgr(this);
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::GetItemObject
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::GetItemObject(REFSYNCMGRITEMID ItemID,
REFIID riid,
void __RPC_FAR *__RPC_FAR *ppv)
{
HRESULT hr = S_OK;
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::ShowProperties
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::ShowProperties(HWND hWndParent,
REFSYNCMGRITEMID ItemID)
{
HRESULT hr = S_OK;
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::SetProgressCallback
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::SetProgressCallback(ISyncMgrSynchronizeCallback
__RPC_FAR *lpCallBack)
{
m_pCallback = lpCallBack;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::PrepareForSync
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::PrepareForSync(ULONG cbNumItems,
SYNCMGRITEMID __RPC_FAR *pItemIDs,
HWND hWndParent,
DWORD dwReserved)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::PrepareForSync\n";
#endif
HRESULT hr = S_OK;
// For each of the items in the item list, mark as ready for
// synchronization
for(ULONG i=0; i<cbNumItems; i++)
{
for(int j=0; j<m_cItems; j++)
{
if (IsEqualGUID(pItemIDs[i], m_Items[j].id) == TRUE)
{
m_Items[j].bReadyToSync = TRUE;
break;
}
}
}
// We're done, notify SyncMgr
if (NULL != m_pCallback)
hr = m_pCallback->PrepareForSyncCompleted(hr);
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::Synchronize
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::Synchronize(HWND hWndParent)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::Synchronize\n";
#endif
HRESULT hr = S_OK;
m_iStatus = SYNC;
SetEvent(m_hEvent);
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::SetItemStatus
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::SetItemStatus(REFSYNCMGRITEMID pItemID,
DWORD dwSyncMgrStatus)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::SetItemStatus\n";
#endif
HRESULT hr = S_OK;
if (SYNCMGRSTATUS_SKIPPED != dwSyncMgrStatus)
return hr;
for(int i=0; i<m_cItems; i++)
{
if (IsEqualGUID(pItemID, m_Items[i].id) == TRUE)
{
m_Items[i].bReadyToSync = FALSE;
break;
}
}
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::ShowError
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::ShowError(HWND hWndParent,
REFSYNCMGRERRORID ErrorID)
{
HRESULT hr = S_OK;
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::AddItem
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::AddItem(LPWSTR sID, LPWSTR src, LPWSTR dest,
int type)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::AddItem\n";
#endif
// Are we full ?
if (m_cItems == m_maxItems)
{
m_maxItems = m_cItems + 10;
SIZE_T cbSize = m_maxItems * sizeof(NODE);
LPNODE t = (LPNODE) HeapAlloc(GetProcessHeap(),
HEAP_GENERATE_EXCEPTIONS |
HEAP_ZERO_MEMORY, cbSize);
if (NULL == t)
return E_OUTOFMEMORY;
// Copy the old items to the next item list
memcpy(t, m_Items, m_cItems * sizeof(NODE));
// Free the old list
HeapFree(GetProcessHeap(), 0, m_Items);
m_Items = t;
}
// Add the new item to the list
LPNODE pItem = &m_Items[m_cItems];
lstrcpyn(pItem->src, src, MAX_PATH);
lstrcpyn(pItem->dest, dest, MAX_PATH);
CLSIDFromString(sID, &pItem->id);
pItem->type = type;
pItem->bReadyToSync = FALSE;
pItem->parent = this;
m_cItems++;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::SyncFiles
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::SyncFiles()
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::SyncFiles\n";
#endif
HRESULT hr = S_OK;
BOOL bCancel = FALSE;
// Start copying the files
for(int i=0; i<m_cItems; i++)
{
LPNODE node = &m_Items[i];
if (TRUE == node->bReadyToSync && 3 == node->type)
{
// Set the progress for the user
Progress(node->id,
SYNCMGRPROGRESSITEM_STATUSTYPE |
SYNCMGRPROGRESSITEM_PROGVALUE |
SYNCMGRPROGRESSITEM_MAXVALUE,
NULL, SYNCMGRSTATUS_UPDATING, 0, 100);
// Check that the file is newer than the local file
if (CheckFileDates(node->src, node->dest) == S_FALSE)
{
Progress(node->id,
SYNCMGRPROGRESSITEM_STATUSTYPE |
SYNCMGRPROGRESSITEM_PROGVALUE |
SYNCMGRPROGRESSITEM_MAXVALUE |
SYNCMGRPROGRESSITEM_STATUSTEXT,
_T("The file does not need to be copied."),
SYNCMGRSTATUS_SUCCEEDED, 100, 100);
continue;
}
// Start the file copy
if (CopyFileEx(node->src, node->dest, CopyProgressRoutine,
node, &bCancel, COPY_FILE_RESTARTABLE) == TRUE)
{
node->bReadyToSync = FALSE;
Progress(node->id,
SYNCMGRPROGRESSITEM_STATUSTYPE |
SYNCMGRPROGRESSITEM_PROGVALUE |
SYNCMGRPROGRESSITEM_MAXVALUE, NULL,
SYNCMGRSTATUS_SUCCEEDED, 100, 100);
}
else
{
if (NULL != m_pCallback)
{
LPWSTR lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
(LPWSTR) &lpMsgBuf,
0,
NULL);
m_pCallback->LogError(SYNCMGRLOGLEVEL_ERROR, lpMsgBuf,
NULL);
LocalFree(lpMsgBuf);
}
}
}
}
// Call the callback to tell that we're done.
if (NULL != m_pCallback)
hr = m_pCallback->SynchronizeCompleted(hr);
return hr;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::CheckFileDates
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::CheckFileDates(LPWSTR src, LPWSTR dest)
{
WIN32_FILE_ATTRIBUTE_DATA fadSrc;
WIN32_FILE_ATTRIBUTE_DATA fadDest;
// Get the source file's attribute data
if (GetFileAttributesEx(src, GetFileExInfoStandard, &fadSrc) != FALSE)
{
if (GetFileAttributesEx(dest, GetFileExInfoStandard, &fadDest) !=
FALSE)
{
if (CompareFileTime(&(fadSrc.ftLastWriteTime),
&(fadDest.ftLastWriteTime)) <= 0)
return S_FALSE;
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::ThreadProc
///////////////////////////////////////////////////////////////////////////
DWORD WINAPI CDDSyncMgr::ThreadProc(LPVOID pParam)
{
DWORD dwReturn = 0;
CDDSyncMgr *t = (CDDSyncMgr *) pParam;
while(1)
{
// Wait for the main thread to signal
dwReturn = WaitForSingleObject(t->m_hEvent, INFINITE);
switch(t->m_iStatus)
{
case SYNC:
t->SyncFiles();
break;
case EXIT:
return 0;
case NONE:
default:
break;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::Progress
///////////////////////////////////////////////////////////////////////////
STDMETHODIMP CDDSyncMgr::Progress(REFSYNCMGRITEMID pItemID,
UINT mask,
TCHAR *pStatusText,
DWORD dwStatusType,
int iProgValue,
int iMaxValue)
{
#ifdef FILEOUTPUT
m_outDebug << "CDDSyncMgr::Progress\n";
#endif
SYNCMGRPROGRESSITEM syncProg;
if (NULL == m_pCallback)
return S_FALSE;
syncProg.cbSize = sizeof(SYNCMGRPROGRESSITEM);
syncProg.mask = mask;
if (SYNCMGRPROGRESSITEM_STATUSTEXT & mask)
{
#ifdef _UNICODE
syncProg.lpcStatusText = pStatusText;
#else
WCHAR wszStatusText[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, pStatusText,
-1, wszStatusText,MAX_PATH);
syncProg.lpcStatusText = wszStatusText;
#endif // _UNICODE
}
syncProg.dwStatusType = dwStatusType;
syncProg.iProgValue = iProgValue;
syncProg.iMaxValue = iMaxValue;
return m_pCallback->Progress(pItemID, &syncProg);
}
///////////////////////////////////////////////////////////////////////////
// CDDSyncMgr::CopyProgressRoutine
///////////////////////////////////////////////////////////////////////////
DWORD CALLBACK CDDSyncMgr::CopyProgressRoutine(
LARGE_INTEGER TotalFileSize, // file size
LARGE_INTEGER TotalBytesTransferred, // bytes transferred
LARGE_INTEGER StreamSize, // bytes in stream
LARGE_INTEGER StreamBytesTransferred, // bytes transferred for stream
DWORD dwStreamNumber, // current stream
DWORD dwCallbackReason, // callback reason
HANDLE hSourceFile, // handle to source file
HANDLE hDestinationFile, // handle to destination file
LPVOID lpData // from CopyFileEx
)
{
LPNODE pNode = (LPNODE) lpData;
if (NULL != pNode)
{
// Check if this item has been requested cancelled by the user
if (FALSE == pNode->bReadyToSync)
return PROGRESS_STOP;
CDDSyncMgr *pMgr = pNode->parent;
double dSize = double(TotalBytesTransferred.QuadPart) /
double(TotalFileSize.QuadPart);
pMgr->Progress(pNode->id,
SYNCMGRPROGRESSITEM_PROGVALUE |
SYNCMGRPROGRESSITEM_MAXVALUE,
NULL, 0, int(dSize * 100.0), 100);
}
else
return PROGRESS_CANCEL;
return PROGRESS_CONTINUE;
}