? wp/ap/win/abi.rgs
? wp/ap/win/app.rgs
? wp/ap/win/ap_Win32App.idl
? wp/ap/win/ap_Win32Com.rc
? wp/ap/win/resource.h
? wp/ap/xp/ap_ScriptMethods.cpp
? wp/ap/xp/ap_ScriptMethods.h
Index: af/util/xp/ut_string.cpp
===================================================================
RCS file: /cvsroot/abi/src/af/util/xp/ut_string.cpp,v
retrieving revision 1.66
diff -u -r1.66 ut_string.cpp
--- af/util/xp/ut_string.cpp	2001/08/10 18:32:38	1.66
+++ af/util/xp/ut_string.cpp	2001/08/15 17:34:28
@@ -1059,7 +1059,6 @@
   return string;
 };
 
-#ifdef BIDI_ENABLED
 /* copies exactly n-chars from src to dest; NB! does not check for 00 i src
 */
 UT_UCSChar * UT_UCS_strncpy(UT_UCSChar * dest, const UT_UCSChar * src, UT_uint32 n)
@@ -1077,6 +1076,7 @@
 	return dest;
 }
 
+#ifdef BIDI_ENABLED
 
 /* reverses str of len n; used by BiDi which always knows the len of string to process
    thus we can save ourselves searching for the 00 */
Index: af/util/xp/ut_string.h
===================================================================
RCS file: /cvsroot/abi/src/af/util/xp/ut_string.h,v
retrieving revision 1.53
diff -u -r1.53 ut_string.h
--- af/util/xp/ut_string.h	2001/08/10 18:32:38	1.53
+++ af/util/xp/ut_string.h	2001/08/15 17:34:28
@@ -85,8 +85,8 @@
 bool			UT_UCS_cloneString(UT_UCSChar ** dest, const UT_UCSChar * src);
 bool			UT_UCS_cloneString_char(UT_UCSChar ** dest, const char * src);
 
-#ifdef BIDI_ENABLED
 UT_UCSChar *    UT_UCS_strncpy(UT_UCSChar * dest, const UT_UCSChar * src, UT_uint32 n);
+#ifdef BIDI_ENABLED
 UT_UCSChar *    UT_UCS_strnrev(UT_UCSChar * dest, UT_uint32 n);
 #endif
 
===================================================================
RCS file: /cvsroot/abi/src/wp/ap/Makefile,v
retrieving revision 1.87
diff -u -r1.87 Makefile
--- wp/ap/Makefile	2001/04/30 03:19:02	1.87
+++ wp/ap/Makefile	2001/08/15 17:34:37
@@ -53,6 +53,9 @@
 		$(OBJDIR)/ap_$(ABI_FE)_TB_CFactory.$(OBJ_SUFFIX)	\
 		$(OBJDIR)/ap_$(ABI_FE)TopRuler.$(OBJ_SUFFIX)
 
+ifeq ($(ABI_FE), Win32)
+PLATFORM_OBJS += 	$(OBJDIR)/ap_$(ABI_FE)Com_i.$(OBJ_SUFFIX)
+endif
 
 ifeq ($(ABI_FE), Mac)
 PLATFORM_OBJS += $(OBJDIR)/ap_$(ABI_FE)Dlg_Replace.$(OBJ_SUFFIX)	\
@@ -152,6 +155,7 @@
 		$(OBJDIR)/ap_Preview_Paragraph.$(OBJ_SUFFIX)	\
 		$(OBJDIR)/ap_Preview_Abi.$(OBJ_SUFFIX)	        \
 		$(OBJDIR)/ap_Ruler.$(OBJ_SUFFIX)		\
+		$(OBJDIR)/ap_ScriptMethods.$(OBJ_SUFFIX)	\
 		$(OBJDIR)/ap_StatusBar.$(OBJ_SUFFIX)		\
 		$(OBJDIR)/ap_Strings.$(OBJ_SUFFIX)		\
 		$(OBJDIR)/ap_Toolbar_ActionSet.$(OBJ_SUFFIX)	\
Index: wp/ap/win/Makefile
===================================================================
RCS file: /cvsroot/abi/src/wp/ap/win/Makefile,v
retrieving revision 1.46
diff -u -r1.46 Makefile
--- wp/ap/win/Makefile	2001/05/03 18:53:30	1.46
+++ wp/ap/win/Makefile	2001/08/15 17:34:38
@@ -57,8 +57,11 @@
 			ap_$(ABI_FE)Dialog_Background.cpp	\
 			ap_$(ABI_FE)TopRuler.cpp
 
-TARGETS=		$(OBJS)
+CSRCS=		ap_$(ABI_FE)Com_i.c
+RCSRCS=		ap_$(ABI_FE)Com.rc
 
+TARGETS=		$(OBJS) reg ap_Win32Com.tlb
+
 include $(ABI_ROOT)/src/config/abi_rules.mk
 
 # Win32 must build libiconv as a peer, Unix should either
@@ -80,3 +83,23 @@
 INCLUDES+= -I$(ABI_XX_ROOT)/../wv -I$(ABI_XX_ROOT)/../wv/exporter -I$(ABI_XX_ROOT)/../zlib -I$(ABI_XX_ROOT)/../wv/libole2 -I$(ABI_XX_ROOT)/../libpng -I$(ABI_XX_ROOT)/../libiconv/include -I$(ABI_XX_ROOT)/../psiconv
 
 build:: $(TARGETS)
+
+# For building COM server
+
+MODULE=$(shell echo $(BINDIR) | $(TRANSFORM_TO_DOS_PATH))\\Abiword.exe
+
+.PHONY: reg unreg
+
+ap_Win32Com.tlb ap_Win32Com_i.c ap_Win32Com.h: ap_Win32App.idl
+	midl /h ap_Win32Com.h /iid ap_Win32Com_i.c /tlb ap_Win32Com.tlb \
+             ap_Win32App.idl
+
+reg:
+	regrgs /c app.rgs MODULE=$(MODULE)
+	regrgs /c abi.rgs
+	regtlb ap_Win32Com.tlb
+
+unreg:
+	regtlb -u ap_Win32Com.tlb
+	regrgs /c /u app.rgs MODULE=$(MODULE)
+	regrgs /c /u abi.rgs
Index: wp/ap/win/ap_Win32App.cpp
===================================================================
RCS file: /cvsroot/abi/src/wp/ap/win/ap_Win32App.cpp,v
retrieving revision 1.67
diff -u -r1.67 ap_Win32App.cpp
--- wp/ap/win/ap_Win32App.cpp	2001/07/03 22:55:36	1.67
+++ wp/ap/win/ap_Win32App.cpp	2001/08/15 17:34:38
@@ -24,6 +24,35 @@
 #define AW_WIN32_USE_NEW_SPELL_CHECKER
 
 #define WIN32_LEAN_AND_MEAN
+
+// ATL COM Support
+//
+// Note: This section must come before the rest of the includes.
+//       Otherwise the file will not compile in debug mode.
+#ifndef STRICT
+#define STRICT
+#endif
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400
+#endif
+#define _ATL_APARTMENT_THREADED
+#include <atlbase.h>
+class CExeModule : public CComModule
+{
+public:
+	LONG Unlock();
+	DWORD dwThreadID;
+	HANDLE hEventShutdown;
+	void MonitorShutdown();
+	bool StartMonitor();
+	bool bActivity;
+};
+extern CExeModule _Module;
+#include <atlcom.h>
+#include "ap_Win32Com.h"
+#include "resource.h"
+// END ATL COM Support
+
 #include <stdlib.h>
 #include <windows.h>
 #include <commctrl.h>   // includes the common control header
@@ -48,6 +77,7 @@
 #endif
 #include "ap_Strings.h"
 #include "ap_LoadBindings.h"
+#include "ev_EditMethod.h"
 #include "xap_EditMethods.h"
 #include "xap_Menu_ActionSet.h"
 #include "xap_Toolbar_ActionSet.h"
@@ -56,6 +86,7 @@
 #include "ap_Win32Resources.rc2"
 #include "ap_Clipboard.h"
 #include "ap_EditMethods.h"
+#include "ap_ScriptMethods.h"
 
 #include "fp_Run.h"
 #include "ut_Win32OS.h"
@@ -793,6 +824,8 @@
 
 	if (bShowApp)
 	{
+	    bool b = pMyWin32App->initComServer(hInstance);
+		UT_ASSERT(b);
 		while (GetMessage(&msg, NULL, 0, 0))
 		{
 			// Note: we do not call TranslateMessage() because
@@ -804,6 +837,7 @@
 
 			DispatchMessage(&msg);
 		}
+		pMyWin32App->shutdownComServer();
 	}
 
 	// destroy the App.  It should take care of deleting all frames.
@@ -1005,3 +1039,632 @@
 
 	return false;
 }
+
+// COM Server Implementation follows
+
+// Here are the declarations of the classes that implement the
+// COM interfaces. 
+
+// coclass CApp
+class ATL_NO_VTABLE CApp : 
+	public CComObjectRootEx<CComSingleThreadModel>,
+	public CComCoClass<CApp, &CLSID_App>,
+	public ISupportErrorInfo,
+	public IDispatchImpl<IApp, &IID_IApp, &LIBID_ABILib>
+{
+public:
+	CApp()
+	{
+	}
+
+DECLARE_REGISTRY_RESOURCEID(IDR_APP)
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CApp)
+	COM_INTERFACE_ENTRY(IApp)
+	COM_INTERFACE_ENTRY(IDispatch)
+	COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+	STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
+public:
+	STDMETHOD(GetNumber)(int * pval);
+        STDMETHOD(Quit)();
+        STDMETHOD(get_Documents)(IDocuments ** ppDocs);
+};
+
+// coclass CDocuments
+class ATL_NO_VTABLE CDocuments : 
+	public CComObjectRootEx<CComSingleThreadModel>,
+	public ISupportErrorInfoImpl<&IID_IDocuments>,
+	public IDispatchImpl<IDocuments, &IID_IDocuments, &LIBID_ABILib>
+{
+public:
+	CDocuments()
+	{
+	}
+
+DECLARE_NO_REGISTRY()
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CDocuments)
+	COM_INTERFACE_ENTRY(IDocuments)
+	COM_INTERFACE_ENTRY(IDispatch)
+	COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+
+BEGIN_CATEGORY_MAP(CDocuments)
+END_CATEGORY_MAP()
+
+public:
+	STDMETHOD(get_Count)(int * pval);
+        STDMETHOD(Item)(VARIANT index, IDocument ** ppDoc);
+        STDMETHOD(Open)(BSTR ucsFilename, IDocument ** ppDoc);
+};
+
+// coclass CDocument
+class ATL_NO_VTABLE CDocument : 
+    public CComObjectRootEx<CComSingleThreadModel>,
+    public ISupportErrorInfoImpl<&IID_IDocument>,
+    public IDispatchImpl<IDocument, &IID_IDocument, &LIBID_ABILib>
+{
+    AD_Document * m_pDoc;
+    FL_DocLayout * m_pDocLayout;
+    
+public:
+    CDocument() : m_pDoc(NULL), m_pDocLayout(NULL) {}
+
+    // This must be called with a non-null ptr before the 
+    // object is exposed to a client.
+    void init(AD_Document * pDoc, FL_DocLayout * pDocLayout) {
+	m_pDoc = pDoc;
+	m_pDoc->ref();
+	m_pDocLayout = pDocLayout;
+    }
+
+    void FinalRelease() {
+	if (m_pDoc) m_pDoc->unref();
+    }
+
+DECLARE_NO_REGISTRY()
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CDocument)
+    COM_INTERFACE_ENTRY(IDocument)
+    COM_INTERFACE_ENTRY(IDispatch)
+    COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+
+BEGIN_CATEGORY_MAP(CDocument)
+END_CATEGORY_MAP()
+public:
+    STDMETHOD(get_Filename)(BSTR * pval);
+    STDMETHOD(Range)(int k1, int k2, IRange ** ppRange);
+    STDMETHOD(get_Sections)(ISections ** ppSections);
+    STDMETHOD(Save)();
+};
+
+// coclass CSections
+class ATL_NO_VTABLE CSections : 
+    public CComObjectRootEx<CComSingleThreadModel>,
+    public ISupportErrorInfoImpl<&IID_ISections>,
+    public IDispatchImpl<ISections, &IID_ISections, &LIBID_ABILib>
+{
+    FL_DocLayout * m_pDocLayout;
+    
+public:
+    CSections() : m_pDocLayout(NULL) {}
+
+    // This must be called with a non-null ptr before the 
+    // object is exposed to a client.
+    void init(FL_DocLayout * pDocLayout) {
+	m_pDocLayout = pDocLayout;
+    }
+
+DECLARE_NO_REGISTRY()
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CSections)
+    COM_INTERFACE_ENTRY(ISections)
+    COM_INTERFACE_ENTRY(IDispatch)
+    COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+
+BEGIN_CATEGORY_MAP(CSections)
+END_CATEGORY_MAP()
+public:
+    STDMETHOD(get_Count)(int * pn);
+    STDMETHOD(Item)(VARIANT varIdx, ISection ** ppSection);
+};
+
+
+// coclass CSection
+class ATL_NO_VTABLE CSection : 
+    public CComObjectRootEx<CComSingleThreadModel>,
+    public ISupportErrorInfoImpl<&IID_ISection>,
+    public IDispatchImpl<ISection, &IID_ISection, &LIBID_ABILib>
+{
+    fl_SectionLayout * m_pSection;
+    
+public:
+    CSection() : m_pSection(NULL) {}
+
+    // This must be called with a non-null ptr before the 
+    // object is exposed to a client.
+    void init(fl_SectionLayout * pSection) {
+	m_pSection = pSection;
+    }
+
+DECLARE_NO_REGISTRY()
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CSection)
+    COM_INTERFACE_ENTRY(ISection)
+    COM_INTERFACE_ENTRY(IDispatch)
+    COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+
+BEGIN_CATEGORY_MAP(CSection)
+END_CATEGORY_MAP()
+public:
+    STDMETHOD(get_Paragraphs)(IParagraphs ** ppParas);
+};
+
+// coclass CParagraphs
+class ATL_NO_VTABLE CParagraphs : 
+    public CComObjectRootEx<CComSingleThreadModel>,
+    public ISupportErrorInfoImpl<&IID_IParagraphs>,
+    public IDispatchImpl<IParagraphs, &IID_IParagraphs, &LIBID_ABILib>
+{
+    fl_SectionLayout * m_pSection;
+    
+public:
+    CParagraphs() : m_pSection(NULL) {}
+
+    // This must be called with a non-null ptr before the 
+    // object is exposed to a client.
+    void init(fl_SectionLayout * pSection) {
+	m_pSection = pSection;
+    }
+
+DECLARE_NO_REGISTRY()
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CParagraphs)
+    COM_INTERFACE_ENTRY(IParagraphs)
+    COM_INTERFACE_ENTRY(IDispatch)
+    COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+
+BEGIN_CATEGORY_MAP(CParagraphs)
+END_CATEGORY_MAP()
+public:
+    STDMETHOD(get_Count)(int * pn);
+    STDMETHOD(Item)(VARIANT varIdx, IParagraph ** ppParagraph);
+};
+
+
+// coclass CParagraph
+class ATL_NO_VTABLE CParagraph : 
+    public CComObjectRootEx<CComSingleThreadModel>,
+    public ISupportErrorInfoImpl<&IID_IParagraph>,
+    public IDispatchImpl<IParagraph, &IID_IParagraph, &LIBID_ABILib>
+{
+    fl_BlockLayout * m_pBlock;
+    
+public:
+    CParagraph() : m_pBlock(NULL) {}
+
+    // This must be called with a non-null ptr before the 
+    // object is exposed to a client.
+    void init(fl_BlockLayout * pBlock) {
+	m_pBlock = pBlock;
+    }
+
+DECLARE_NO_REGISTRY()
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CParagraph)
+    COM_INTERFACE_ENTRY(IParagraph)
+    COM_INTERFACE_ENTRY(IDispatch)
+    COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+
+BEGIN_CATEGORY_MAP(CParagraph)
+END_CATEGORY_MAP()
+public:
+    STDMETHOD(Range)(int k1, int k2, IRange ** ppRange);
+};
+
+// coclass CRange
+class ATL_NO_VTABLE CRange : 
+	public CComObjectRootEx<CComSingleThreadModel>,
+	public ISupportErrorInfoImpl<&IID_IRange>,
+	public IDispatchImpl<IRange, &IID_IRange, &LIBID_ABILib>
+{
+    fl_BlockLayout * m_pBlock;
+    int m_pos1, m_pos2;
+public:
+    CRange() {}
+
+    // This must be called with a non-null ptr before the 
+    // object is exposed to a client.
+    void init(fl_BlockLayout * pBlock, int k1, int k2) {
+	m_pBlock = pBlock;
+	m_pos1 = k1;
+	m_pos2 = k2;
+    }
+    
+DECLARE_NO_REGISTRY()
+
+DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+BEGIN_COM_MAP(CRange)
+    COM_INTERFACE_ENTRY(IRange)
+    COM_INTERFACE_ENTRY(IDispatch)
+    COM_INTERFACE_ENTRY(ISupportErrorInfo)
+END_COM_MAP()
+
+BEGIN_CATEGORY_MAP(CRange)
+END_CATEGORY_MAP()
+public:
+    STDMETHOD(get_Start)(int * pval);
+    STDMETHOD(get_Length)(int * pval);
+    STDMETHOD(get_Text)(BSTR * pszText);
+    STDMETHOD(Replace)(BSTR pszText);
+};
+
+// ATL Object Map
+//
+// ATL uses this to register the class factories on startup. Any
+// externally createable coclass should be declared here using
+// OBJECT_ENTRY. Any class not coclass should be declared using
+// OBJECT_ENTRY_NON_CREATEABLE.
+BEGIN_OBJECT_MAP(ObjectMap)
+  OBJECT_ENTRY(CLSID_App, CApp)
+  OBJECT_ENTRY_NON_CREATEABLE(CDocuments)
+  OBJECT_ENTRY_NON_CREATEABLE(CDocument)
+  OBJECT_ENTRY_NON_CREATEABLE(CRange)
+END_OBJECT_MAP()
+
+// Startup and shutdown methods for the COM server.
+bool AP_Win32App::initComServer(HINSTANCE hInstance)
+{
+    HRESULT hRes = CoInitialize(NULL);
+    if (!SUCCEEDED(hRes)) return false;
+    _Module.Init(ObjectMap, hInstance, &LIBID_ABILib);
+    _Module.dwThreadID = GetCurrentThreadId();
+    _Module.StartMonitor();
+    hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, 
+					REGCLS_MULTIPLEUSE);
+    if (!SUCCEEDED(hRes)) return false;
+    return true;
+}
+
+bool AP_Win32App::shutdownComServer()
+{
+    _Module.RevokeClassObjects();
+    _Module.Term();
+    CoUninitialize();
+    return true;
+}
+
+// Implementations of the coclasses.
+
+STDMETHODIMP CApp::InterfaceSupportsErrorInfo(REFIID riid)
+{
+    static const IID* arr[] = { &IID_IApp };
+    for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++) {
+	if (InlineIsEqualGUID(*arr[i],riid))
+	    return S_OK;
+    }
+    return S_FALSE;
+}
+
+STDMETHODIMP CApp::GetNumber(int *pval)
+{
+    *pval = 666;
+    return S_OK;
+}
+
+STDMETHODIMP CApp::Quit()
+{
+    scriptQuit();
+    return S_OK;
+}
+
+STDMETHODIMP CApp::get_Documents(IDocuments ** ppDocs)
+{
+    *ppDocs = NULL;
+    return CComCreator<CComObject<CDocuments> >::CreateInstance(
+    		NULL, IID_IDocuments, reinterpret_cast<void **>(ppDocs));
+}
+
+STDMETHODIMP CDocuments::get_Count(int *pval)
+{
+    *pval = scriptDocCount();
+    return S_OK;
+}
+
+STDMETHODIMP CDocuments::Item(VARIANT varIdx, IDocument ** ppDoc)
+{
+    CComVariant _varIdx(varIdx);
+    HRESULT hr = _varIdx.ChangeType(VT_I4);
+    if (FAILED(hr)) return hr;
+    int nIdx = _varIdx.lVal;
+    int nDocs = scriptDocCount();
+    if (nIdx < 0 || nIdx >= nDocs) return E_INVALIDARG;
+
+    *ppDoc = NULL;
+    hr = CComCreator<CComObject<CDocument> >::CreateInstance(
+    		NULL, IID_IDocument, reinterpret_cast<void **>(ppDoc));
+    if (FAILED(hr)) return hr;
+    
+    PD_Document * pDoc;
+    FL_DocLayout * pDocLayout;
+    scriptGetDoc(scriptGetDocFrame(nIdx), &pDoc, &pDocLayout);
+    static_cast<CDocument *>(*ppDoc)->init(pDoc, pDocLayout);
+    return S_OK;
+}
+
+// TODO: eh, move to script fns, remove doc obj create dup with Item.
+STDMETHODIMP CDocuments::Open(BSTR ucsFilename, IDocument ** ppDoc)
+{
+    int nLen = SysStringLen(ucsFilename);
+
+    char * szFilename = (char *) malloc(nLen+1);
+    WideCharToMultiByte(CP_ACP, 0, ucsFilename, nLen+1, 
+			szFilename, nLen+1, 0, 0);
+#if 0
+    UT_uint32 nRead, nWritten;
+    char * szFilename = UT_convert(reinterpret_cast<const char *>(ucsFilename),
+		   nLen, "US-ASCII", "UCS-2", &nRead, &nWritten);
+#endif
+    UT_DEBUGMSG(("[Script] Opening file '%s'\n", szFilename));
+    XAP_App * pApp = XAP_App::getApp();
+    UT_ASSERT(pApp);
+    XAP_Frame * pFrame = pApp->newFrame();
+    UT_ASSERT(pFrame);
+    UT_Error err = pFrame->loadDocument(szFilename, 0);
+    UT_ASSERT(err == UT_OK);
+    pFrame->show();
+    free(szFilename);
+
+    *ppDoc = NULL;
+    HRESULT hr = CComCreator<CComObject<CDocument> >::CreateInstance(
+	NULL, IID_IDocument, reinterpret_cast<void **>(ppDoc));
+    if (FAILED(hr)) return hr;
+
+    PD_Document * pDoc;
+    FL_DocLayout * pDocLayout;
+    scriptGetDoc(pFrame, &pDoc, &pDocLayout);
+    static_cast<CDocument *>(*ppDoc)->init(pDoc, pDocLayout);
+
+    return S_OK;
+}
+
+STDMETHODIMP CDocument::get_Filename(BSTR * pval)
+{
+    const char * szFilename = m_pDoc->getFilename();
+    if (szFilename == NULL) {
+	*pval = NULL;
+    } else {
+	int nLen = MultiByteToWideChar(CP_ACP, 0, szFilename, -1, 0, 0);
+	WCHAR * ucsFilename = (WCHAR *) malloc(sizeof(WCHAR) * nLen);
+	MultiByteToWideChar(CP_ACP, 0, szFilename, -1, ucsFilename, nLen);
+	*pval = SysAllocString(ucsFilename);
+	free(ucsFilename);
+    }
+    return S_OK;
+}
+
+// TODO: eh
+STDMETHODIMP CDocument::Range(int k1, int k2, IRange ** ppRange)
+{
+    return E_NOTIMPL;
+#if 0
+    UT_DEBUGMSG(("[Doc::Range] Entering\n"));
+    if (k2 < k1) return E_INVALIDARG;
+    UT_DEBUGMSG(("[Doc::Range] Args OK\n"));
+    *ppRange = NULL;
+    HRESULT hr = CComCreator<CComObject<CRange> >::CreateInstance(
+	NULL, IID_IRange, reinterpret_cast<void **>(ppRange));
+    UT_DEBUGMSG(("[Doc::Range] CI -> %d\n", hr));
+    if (FAILED(hr)) return hr;
+    UT_DEBUGMSG(("[Doc::Range] Object Created OK\n"));
+    static_cast<CRange *>(*ppRange)->init(static_cast<PD_Document *>(m_pDoc),
+					  k1, k2, m_pDocLayout);
+    UT_DEBUGMSG(("[Doc::Range] Exiting\n"));
+    return S_OK;
+#endif
+}
+
+STDMETHODIMP CDocument::get_Sections(ISections ** ppSections)
+{
+    *ppSections = NULL;
+    HRESULT hr = CComCreator<CComObject<CSections> >::CreateInstance(
+	NULL, IID_ISections, reinterpret_cast<void **>(ppSections));
+    if (FAILED(hr)) return hr;
+    static_cast<CSections *>(*ppSections)->init(m_pDocLayout);
+    return S_OK;
+}
+
+STDMETHODIMP CDocument::Save()
+{
+    m_pDoc->save();
+    return S_OK;
+}
+
+STDMETHODIMP CSections::get_Count(int * pn)
+{
+    *pn = scriptDocSectionCount(m_pDocLayout);
+    return S_OK;
+}
+
+// TODO: remove variant handling dup with other Item
+STDMETHODIMP CSections::Item(VARIANT varIdx, ISection ** ppSection)
+{
+    CComVariant _varIdx(varIdx);
+    HRESULT hr = _varIdx.ChangeType(VT_I4);
+    if (FAILED(hr)) return hr;
+    int nIdx = _varIdx.lVal;
+    int nSections = scriptDocSectionCount(m_pDocLayout);
+    if (nIdx < 0 || nIdx >= nSections) return E_INVALIDARG;
+
+    *ppSection = NULL;
+    hr = CComCreator<CComObject<CSection> >::CreateInstance(
+	NULL, IID_ISection, reinterpret_cast<void **>(ppSection));
+    if (FAILED(hr)) return hr;
+    static_cast<CSection *>(*ppSection)->init(scriptDocSection(m_pDocLayout, 
+							       nIdx));
+    return S_OK;
+}
+
+STDMETHODIMP CSection::get_Paragraphs(IParagraphs ** ppParas)
+{
+    *ppParas = NULL;
+    HRESULT hr = CComCreator<CComObject<CParagraphs> >::CreateInstance(
+	NULL, IID_IParagraphs, reinterpret_cast<void **>(ppParas));
+    if (FAILED(hr)) return hr;
+    static_cast<CParagraphs *>(*ppParas)->init(m_pSection);
+    return S_OK;
+}
+
+STDMETHODIMP CParagraphs::get_Count(int * pn)
+{
+    *pn = scriptBlockCount(m_pSection);
+    return S_OK;
+}
+
+// TODO: remove variant handling dup with other Item
+STDMETHODIMP CParagraphs::Item(VARIANT varIdx, IParagraph ** ppPara)
+{
+    CComVariant _varIdx(varIdx);
+    HRESULT hr = _varIdx.ChangeType(VT_I4);
+    if (FAILED(hr)) return hr;
+    int nIdx = _varIdx.lVal;
+    int nBlocks = scriptBlockCount(m_pSection);
+    if (nIdx < 0 || nIdx >= nBlocks) return E_INVALIDARG;
+
+    *ppPara = NULL;
+    hr = CComCreator<CComObject<CParagraph> >::CreateInstance(
+	NULL, IID_IParagraph, reinterpret_cast<void **>(ppPara));
+    if (FAILED(hr)) return hr;
+    static_cast<CParagraph *>(*ppPara)->init(scriptBlock(m_pSection, nIdx));
+    return S_OK;
+}
+
+STDMETHODIMP CParagraph::Range(int k1, int k2, IRange ** ppRange)
+{
+    if (k2 == -1) k2 = scriptBlockLength(m_pBlock);
+    if (k2 < k1) return E_INVALIDARG;
+    *ppRange = NULL;
+    HRESULT hr = CComCreator<CComObject<CRange> >::CreateInstance(
+	NULL, IID_IRange, reinterpret_cast<void **>(ppRange));
+    if (FAILED(hr)) return hr;
+    static_cast<CRange *>(*ppRange)->init(m_pBlock, k1, k2);
+    return S_OK;
+}
+
+
+STDMETHODIMP CRange::get_Start(int * pVal)
+{
+    *pVal = m_pos1;
+    return S_OK;
+}
+
+STDMETHODIMP CRange::get_Length(int * pVal)
+{
+    *pVal = m_pos2 - m_pos1;
+    return S_OK;
+}
+
+STDMETHODIMP CRange::get_Text(BSTR * pszText)
+{
+    UT_UCSChar * ucs = scriptGetRangeText(m_pBlock, m_pos1, m_pos2-m_pos1);
+    *pszText = SysAllocString(ucs);
+    free(ucs);
+    return S_OK;
+}
+
+STDMETHODIMP CRange::Replace(BSTR pszText)
+{
+    scriptReplaceRangeText(m_pBlock, m_pos1, m_pos2-m_pos1, pszText);
+    m_pos2 = m_pos1 + UT_UCS_strlen(pszText);
+    return S_OK;
+}
+
+// Implementation of CExeModule. This is the COM server. It registers
+// class objects and checks for shutdown conditions.
+
+// TODO: Explain this.
+const DWORD dwTimeOut = 5000;
+
+// Shim to run MonitorShutdown in a thread.
+static DWORD WINAPI MonitorProc(void* pv)
+{
+    CExeModule* p = (CExeModule*)pv;
+    p->MonitorShutdown();
+    return 0;
+}
+
+// Decrease the lock count on the module. If it reaches zero, wake
+// up MonitorShutdown.
+LONG CExeModule::Unlock()
+{
+    LONG l = CComModule::Unlock();
+    if (l == 0)
+    {
+        bActivity = true;
+        SetEvent(hEventShutdown); // tell monitor that we transitioned to zero
+    }
+    return l;
+}
+
+// Control shutdown. Shut down if the COM Server is no longer in use.
+void CExeModule::MonitorShutdown()
+{
+    UT_DEBUGMSG(("[COMServerMon] Started thread. Monitoring for shutdown conditions\n"));
+    while (1)
+    {
+        UT_DEBUGMSG(("[COMServerMon] Waiting for signal\n"));
+        WaitForSingleObject(hEventShutdown, INFINITE);
+        UT_DEBUGMSG(("[COMServerMon] Signal received\n"));
+        DWORD dwWait=0;
+        do
+        {
+            UT_DEBUGMSG(("[COMServerMon] Waiting %d ms for signal\n", dwTimeOut));
+            bActivity = false;
+            dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
+            UT_DEBUGMSG(("[COMServerMon] Wait ended\n"));
+        } while (dwWait == WAIT_OBJECT_0);
+        UT_DEBUGMSG(("[COMServerMon] Signal received, bActivity = %d, m_nLockCnt = \n",
+		     bActivity, m_nLockCnt));
+        // timed out
+        if (!bActivity && m_nLockCnt == 0) // if no activity let's really bail
+        {
+	    break;
+        }
+    }
+    CloseHandle(hEventShutdown);
+    // TODO: Shutdown more gracefully
+    PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
+}
+
+bool CExeModule::StartMonitor()
+{
+    hEventShutdown = CreateEvent(NULL, false, false, NULL);
+    if (hEventShutdown == NULL)
+        return false;
+    DWORD dwThreadID;
+    HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
+    return (h != NULL);
+}
+
+CExeModule _Module;
Index: wp/ap/win/ap_Win32App.h
===================================================================
RCS file: /cvsroot/abi/src/wp/ap/win/ap_Win32App.h,v
retrieving revision 1.20
diff -u -r1.20 ap_Win32App.h
--- wp/ap/win/ap_Win32App.h	2001/06/18 15:11:42	1.20
+++ wp/ap/win/ap_Win32App.h	2001/08/15 17:34:39
@@ -66,6 +66,10 @@
 	bool handleModelessDialogMessage( MSG * msg );
 
 protected:
+    // Initialize or shut down the COM server. Return true if successful.
+	bool                    initComServer(HINSTANCE hInstance);
+    bool                    shutdownComServer();
+
 	bool					_pasteFormatFromClipboard(PD_DocumentRange * pDocRange, const char * szFormat,
 													 const char * szType, bool bWide);
 	XAP_StringSet *			m_pStringSet;
Index: wp/ap/xp/Makefile
===================================================================
RCS file: /cvsroot/abi/src/wp/ap/xp/Makefile,v
retrieving revision 1.64
diff -u -r1.64 Makefile
--- wp/ap/xp/Makefile	2001/04/28 22:06:07	1.64
+++ wp/ap/xp/Makefile	2001/08/15 17:34:39
@@ -77,6 +77,7 @@
 		ap_Preview_Paragraph.cpp	\
 		ap_Preview_Abi.cpp		\
 		ap_Ruler.cpp			\
+		ap_ScriptMethods.cpp            \
 		ap_StatusBar.cpp		\
 		ap_Strings.cpp			\
 		ap_Toolbar_ActionSet.cpp	\
