source: trunk/Utilities/MaxMindGeoLite/Location.h @ 49

Last change on this file since 49 was 49, checked in by roman, 10 years ago

singletons, lazy initialization singleton, free threaded marhsaler, x64

  • Property svn:keywords set to Id
File size: 24.9 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2012
3// Created by Roman Ryltsov roman@alax.info
4//
5// $Id: Location.h 49 2012-02-11 22:47:53Z roman $
6
7#pragma once
8
9#include <atlenc.h>
10#include "rosockets.h"
11#include "MaxMindGeoLite_i.h"
12
13////////////////////////////////////////////////////////////
14// GeoLiteCity
15
16namespace GeoLiteCity
17{
18        ////////////////////////////////////////////////////////////
19        // CLocation
20
21        class CLocation
22        {
23        public:
24                INT m_nIdentifier;
25                CStringA m_sCountryCode;
26                CStringA m_sRegion;
27                CStringA m_sCity;
28                CStringA m_sPostalCode;
29                DOUBLE m_fLatitude;
30                DOUBLE m_fLongitude;
31                CStringA m_sMetroCode;
32                CStringA m_sAreaCode;
33
34        public:
35        // CLocation
36                CLocation() throw()
37                {
38                }
39                CLocation(LPCSTR pszString)
40                {
41                        Initialize(pszString);
42                }
43                VOID Initialize(LPCSTR pszString)
44                {
45                        CRoArrayT<CStringA> Array;
46                        __D(_StringHelper::GetCommaSeparatedItems(pszString, Array) >= 7, E_UNNAMED);
47                        __D(AtlStringToInteger(Array[0], m_nIdentifier), E_UNNAMED);
48                        m_sCountryCode = Array[1];
49                        m_sRegion = Array[2];
50                        m_sCity = Array[3];
51                        m_sPostalCode = Array[4];
52                        __D(AtlStringToDouble(Array[5], m_fLatitude), E_UNNAMED);
53                        __D(AtlStringToDouble(Array[6], m_fLongitude), E_UNNAMED);
54                        if(Array.GetCount() >= 8)
55                                m_sMetroCode = Array[7];
56                        if(Array.GetCount() >= 9)
57                                m_sAreaCode = Array[8];
58                }
59        };
60
61        ////////////////////////////////////////////////////////////
62        // CLocationArray
63
64        class CLocationArray :
65                protected CRoArrayT<CLocation>
66        {
67        public:
68        // CLocationArray
69                CLocationArray() throw()
70                {
71                }
72                CLocationArray(const CPath& sPath)
73                {
74                        Initialize(sPath);
75                }
76                VOID Initialize(const CPath& sPath)
77                {
78                        CAtlFile File;
79                        __C(File.Create(sPath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
80                        ULONGLONG nSize;
81                        __C(File.GetSize(nSize));
82                        CHeapPtr<CHAR> pszData;
83                        __D(pszData.Allocate((SIZE_T) nSize + 1), E_OUTOFMEMORY);
84                        __C(File.Read(pszData, (DWORD) nSize));
85                        pszData[nSize] = 0;
86                        LPCSTR pszDataPointer = pszData;
87                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Copyright line
88                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Header line
89                        for(; *pszDataPointer; )
90                        {
91                                LPCSTR pszSeparator = strchr(pszDataPointer, '\n');
92                                if(!pszSeparator)
93                                        break;
94                                const SIZE_T nLength = pszSeparator - pszDataPointer;
95                                CTempBufferT<CHAR> pszLine(nLength + 1);
96                                strncpy_s(pszLine, nLength + 1, pszDataPointer, _TRUNCATE);
97                                const SIZE_T nIndex = Add();
98                                CLocation& Location = GetAt(nIndex);
99                                Location.Initialize(pszLine);
100                                __D(Location.m_nIdentifier == nIndex + 1, E_UNNAMED);
101                                pszDataPointer = pszSeparator + 1;
102                        }
103                }
104                BOOL Lookup(INT nIdentifier, const CLocation** ppLocation = NULL) const throw()
105                {
106                        if(nIdentifier < 1 || nIdentifier - 1 >= (INT) GetCount())
107                                return FALSE;
108                        const CLocation& Location = GetAt(nIdentifier - 1);
109                        _A(Location.m_nIdentifier == nIdentifier);
110                        if(ppLocation)
111                                *ppLocation = &Location;
112                        return TRUE;
113                }
114        };
115
116        ////////////////////////////////////////////////////////////
117        // CBlock
118
119        class CBlock
120        {
121        public:
122                ULONG m_nStartAddress;
123                ULONG m_nEndAddress;
124                INT m_nLocationIdentifier;
125
126        public:
127        // CBlock
128                CBlock() throw()
129                {
130                }
131                CBlock(LPCSTR pszString)
132                {
133                        Initialize(pszString);
134                }
135                VOID Initialize(LPCSTR pszString)
136                {
137                        CRoArrayT<CStringA> Array;
138                        __D(_StringHelper::GetCommaSeparatedItems(pszString, Array) >= 3, E_UNNAMED);
139                        LONGLONG nStartAddress, nEndAddress;
140                        __D(AtlStringToInteger(Array[0], nStartAddress), E_UNNAMED);
141                        __D(AtlStringToInteger(Array[1], nEndAddress), E_UNNAMED);
142                        m_nStartAddress = (ULONG) nStartAddress;
143                        m_nEndAddress = (ULONG) nEndAddress;
144                        __D(AtlStringToInteger(Array[2], m_nLocationIdentifier), E_UNNAMED);
145                }
146                BOOL Contains(ULONG nAddress) const throw()
147                {
148                        return nAddress >= m_nStartAddress && nAddress <= m_nEndAddress;
149                }
150        };
151
152        ////////////////////////////////////////////////////////////
153        // CBlockArray
154
155        class CBlockArray :
156                protected CRoArrayT<CBlock>
157        {
158        public:
159        // CBlockArray
160                CBlockArray() throw()
161                {
162                }
163                CBlockArray(const CPath& sPath)
164                {
165                        Initialize(sPath);
166                }
167                VOID Initialize(const CPath& sPath)
168                {
169                        CAtlFile File;
170                        __C(File.Create(sPath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
171                        ULONGLONG nSize;
172                        __C(File.GetSize(nSize));
173                        CHeapPtr<CHAR> pszData;
174                        __D(pszData.Allocate((SIZE_T) nSize + 1), E_OUTOFMEMORY);
175                        __C(File.Read(pszData, (DWORD) nSize));
176                        pszData[nSize] = 0;
177                        LPCSTR pszDataPointer = pszData;
178                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Copyright line
179                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Header line
180                        ULONG nPreviousEndAddress = 0;
181                        for(; *pszDataPointer; )
182                        {
183                                LPCSTR pszSeparator = strchr(pszDataPointer, '\n');
184                                if(!pszSeparator)
185                                        break;
186                                const SIZE_T nLength = pszSeparator - pszDataPointer;
187                                CTempBufferT<CHAR> pszLine(nLength + 1);
188                                strncpy_s(pszLine, nLength + 1, pszDataPointer, _TRUNCATE);
189                                const SIZE_T nIndex = Add();
190                                CBlock& Block = GetAt(nIndex);
191                                Block.Initialize(pszLine);
192                                __D(Block.m_nStartAddress && Block.m_nStartAddress > nPreviousEndAddress, E_UNNAMED);
193                                nPreviousEndAddress = Block.m_nEndAddress;
194                                pszDataPointer = pszSeparator + 1;
195                        }
196                }
197                BOOL Lookup(ULONG nAddress, const CBlock** ppBlock = NULL) const throw()
198                {
199                        SIZE_T nLeftIndex = 0, nRightIndex = GetCount();
200                        if(!nRightIndex)
201                                return FALSE;
202                        if(nAddress < GetAt(0).m_nStartAddress || nAddress > GetAt(GetCount() - 1).m_nEndAddress)
203                                return FALSE;
204                        for(; nLeftIndex + 1 < nRightIndex; )
205                        {
206                                SIZE_T nIndex = (nLeftIndex + nRightIndex) / 2;
207                                const CBlock& Block = GetAt(nIndex);
208                                if(nAddress < Block.m_nStartAddress)
209                                {
210                                        nRightIndex = nIndex;
211                                } else
212                                if(nAddress > Block.m_nEndAddress)
213                                {
214                                        nLeftIndex = nIndex + 1;
215                                } else
216                                {
217                                        nLeftIndex = nIndex;
218                                        break;
219                                }
220                        }
221                        const CBlock& Block = GetAt(nLeftIndex);
222                        if(!Block.Contains(nAddress))
223                                return FALSE;
224                        if(ppBlock)
225                                *ppBlock = &Block;
226                        return TRUE;
227                }
228        };
229}
230
231////////////////////////////////////////////////////////////
232// CFreeThreadedMarshaler
233
234class CFreeThreadedMarshaler
235{
236private:
237        CComPtr<IUnknown> m_pMarshalerUnknown;
238        CComPtr<IMarshal> m_pMarshalerMarshal;
239
240public:
241// CFreeThreadedMarshaler
242        const CComPtr<IMarshal>& operator -> () const throw()
243        {
244                return GetMarshal();
245        }
246        VOID Initialize()
247        {
248                _A(!m_pMarshalerUnknown && !m_pMarshalerMarshal);
249                __C(CoCreateFreeThreadedMarshaler(NULL, &m_pMarshalerUnknown));
250                m_pMarshalerMarshal = m_pMarshalerUnknown;
251                __D(m_pMarshalerMarshal, E_NOINTERFACE);
252        }
253        VOID Terminate() throw()
254        {
255                m_pMarshalerMarshal = NULL;
256                m_pMarshalerUnknown = NULL;
257        }
258        const CComPtr<IMarshal>& GetMarshal() const throw()
259        {
260                return m_pMarshalerMarshal;
261        }
262};
263
264////////////////////////////////////////////////////
265// CDispatchExT
266//
267// TODO: IDispatch methods should take care of IID argument
268
269template <typename T>
270class ATL_NO_VTABLE CDispatchExT :
271        public IDispatchEx
272{
273public:
274
275        ////////////////////////////////////////////////////////
276        // CDispatchData
277
278        class CDispatchData
279        {
280        public:
281                IID m_InterfaceIdentifier;
282                IDispatch* m_pDispatch;
283
284        public:
285        // CDispatchData
286                CDispatchData() throw() :
287                        m_InterfaceIdentifier(IID_NULL),
288                        m_pDispatch(NULL)
289                {
290                }
291                CDispatchData(IDispatchEx* pDispatchEx, const IID& InterfaceIdentifier)
292                {
293                        CComPtr<IDispatch> pDispatch;
294                        __C(pDispatchEx->QueryInterface(InterfaceIdentifier, (VOID**) &pDispatch));
295                        m_InterfaceIdentifier = InterfaceIdentifier;
296                        m_pDispatch = pDispatch;
297                }
298        };
299
300private:
301        CRoArrayT<CDispatchData> m_DispatchDataArray;
302
303public:
304// CDispatchExT
305        VOID ResetDispatchInterfaceIdentifiers() throw()
306        {
307                m_DispatchDataArray.RemoveAll();
308        }
309        VOID SetDispatchInterfaceIdentifiers(const IID* pInterfaceIdentifiers, SIZE_T nInterfaceIdentifierCount)
310        {
311                _A(m_DispatchDataArray.IsEmpty());
312                for(SIZE_T nIndex = 0; nIndex < nInterfaceIdentifierCount; nIndex++)
313                        _W(m_DispatchDataArray.Add(CDispatchData(this, pInterfaceIdentifiers[nIndex])) >= 0);
314        }
315        VOID SetDispatchInterfaceIdentifiers(const IID& InterfaceIdentifier)
316        {
317                SetDispatchInterfaceIdentifiers(&InterfaceIdentifier, 1);
318        }
319        VOID SetDispatchInterfaceIdentifiers(SIZE_T nInterfaceIdentifierCount, ...)
320        {
321                _A(nInterfaceIdentifierCount);
322                va_list Arguments;
323                va_start(Arguments, nInterfaceIdentifierCount);
324                CTempBufferT<IID> pInterfaceIdentifiers(nInterfaceIdentifierCount);
325                for(SIZE_T nIndex = 0; nIndex < nInterfaceIdentifierCount; nIndex++)
326                        pInterfaceIdentifiers[nIndex] = *va_arg(Arguments, IID*);
327                va_end(Arguments);
328                SetDispatchInterfaceIdentifiers(pInterfaceIdentifiers, nInterfaceIdentifierCount);
329        }
330        IDispatch* GetDispatch(DISPID nDispIdentifier) const throw()
331        {
332                const SIZE_T nDispatchIndex = (UINT) (nDispIdentifier >> 12);
333                _A(nDispatchIndex < m_DispatchDataArray.GetCount());
334                return m_DispatchDataArray[nDispatchIndex].m_pDispatch;
335        }
336
337// IDispatchEx
338        STDMETHOD(GetDispID)(BSTR sName, DWORD nFlags, DISPID* pid) throw()
339        {
340                _Z4(atlTraceCOM, 4, _T("this 0x%p, sName \"%s\", nFlags 0x%x\n"), static_cast<T*>(this), CString(sName), nFlags);
341                _ATLTRY
342                {
343                        __D(pid, E_POINTER);
344                        nFlags;
345                        OLECHAR* ppszNames[] = { const_cast<OLECHAR*>(sName), };
346                        const LCID nLocaleIdentifier = GetThreadLocale();
347                        *pid = -1;
348                        HRESULT nResult = DISP_E_UNKNOWNNAME;
349                        for(SIZE_T nIndex = 0; nIndex < m_DispatchDataArray.GetCount(); nIndex++)
350                        {
351                                DISPID nDispatchDispIdentifier;
352                                const HRESULT nDispatchResult = m_DispatchDataArray[nIndex].m_pDispatch->GetIDsOfNames(IID_NULL, ppszNames, DIM(ppszNames), nLocaleIdentifier, &nDispatchDispIdentifier);
353                                if(SUCCEEDED(nDispatchResult))
354                                {
355                                        _A(!(nDispatchDispIdentifier & ~0x0FFF));
356                                        *pid = (DISPID) (nIndex << 12) + nDispatchDispIdentifier;
357                                        nResult = nDispatchResult;
358                                        break;
359                                }
360                        }
361                        _Z4(atlTraceGeneral, 4, _T("nResult 0x%08x, *pid %d\n"), nResult, *pid);
362                        return nResult;
363                }
364                _ATLCATCH(Exception)
365                {
366                        _C(Exception);
367                }
368                return E_NOTIMPL;
369        }
370        STDMETHOD(InvokeEx)(DISPID id, LCID nLocaleIdentifier, WORD nFlags, DISPPARAMS* pdp, VARIANT* pvarRes, EXCEPINFO* pei, IServiceProvider* pServiceProvider) throw()
371        {
372                _Z4(atlTraceCOM, 4, _T("this 0x%p, id %d, nLocaleIdentifier %d, nFlags 0x%x\n"), static_cast<T*>(this), id, nLocaleIdentifier, nFlags);
373                _ATLTRY
374                {
375                        pServiceProvider;
376                        UINT nErroneousArgument;
377                        _A((id & ~0xFFFF) == 0);
378                        const HRESULT nResult = GetDispatch(id)->Invoke(id & 0x0FFF, IID_NULL, nLocaleIdentifier, nFlags, pdp, pvarRes, pei, &nErroneousArgument);
379                        _Z4(atlTraceGeneral, 4, _T("nResult 0x%08x\n"), nResult);
380                        return nResult;
381                }
382                _ATLCATCH(Exception)
383                {
384                        _C(Exception);
385                }
386                return E_NOTIMPL;
387        }
388        STDMETHOD(DeleteMemberByName)(BSTR sName, DWORD nFlags) throw()
389        {
390                _Z4(atlTraceCOM, 4, _T("this 0x%p, sName \"%s\", nFlags 0x%x\n"), static_cast<T*>(this), CString(sName), nFlags);
391                return E_NOTIMPL;
392        }
393        STDMETHOD(DeleteMemberByDispID)(DISPID id) throw()
394        {
395                _Z4(atlTraceCOM, 4, _T("this 0x%p, id %d\n"), static_cast<T*>(this), id);
396                return E_NOTIMPL;
397        }
398        STDMETHOD(GetMemberProperties)(DISPID id, DWORD nFlagMask, DWORD* pnFlags) throw()
399        {
400                _Z4(atlTraceCOM, 4, _T("this 0x%p, id %d, nFlagMask 0x%x\n"), static_cast<T*>(this), id, nFlagMask);
401                return E_NOTIMPL;
402        }
403        STDMETHOD(GetMemberName)(DISPID id, BSTR* psName) throw()
404        {
405                _Z4(atlTraceCOM, 4, _T("this 0x%p, id %d\n"), static_cast<T*>(this), id);
406                return E_NOTIMPL;
407        }
408        STDMETHOD(GetNextDispID)(DWORD nFlags, DISPID id, DISPID* pid) throw()
409        {
410                _Z4(atlTraceCOM, 4, _T("this 0x%p, nFlags 0x%x, id %d\n"), static_cast<T*>(this), nFlags, id);
411                return E_NOTIMPL;
412        }
413        STDMETHOD(GetNameSpaceParent)(IUnknown** ppunk) throw()
414        {
415                _Z4(atlTraceCOM, 4, _T("this 0x%p\n"), static_cast<T*>(this));
416                return E_NOTIMPL;
417        }
418
419// IDispatch
420        STDMETHOD(GetTypeInfoCount)(UINT* pnCount) throw()
421        {
422                _Z4(atlTraceCOM, 4, _T("this 0x%p\n"), static_cast<T*>(this));
423                _ATLTRY
424                {
425                        const HRESULT nResult = GetDispatch(0)->GetTypeInfoCount(pnCount);
426                        _Z4(atlTraceGeneral, 4, _T("nResult 0x%08x\n"), nResult);
427                        return nResult;
428                }
429                _ATLCATCH(Exception)
430                {
431                        _C(Exception);
432                }
433                return E_NOTIMPL;
434        }
435        STDMETHOD(GetTypeInfo)(UINT nIndex, LCID nLocaleIdentifier, ITypeInfo** ppTypeInfo) throw()
436        {
437                _Z4(atlTraceCOM, 4, _T("this 0x%p, nIndex %d, nLocaleIdentifier %d\n"), static_cast<T*>(this), nIndex, nLocaleIdentifier);
438                _ATLTRY
439                {
440                        const HRESULT nResult = GetDispatch(0)->GetTypeInfo(nIndex, nLocaleIdentifier, ppTypeInfo);
441                        _Z4(atlTraceGeneral, 4, _T("nResult 0x%08x\n"), nResult);
442                        return nResult;
443                }
444                _ATLCATCH(Exception)
445                {
446                        _C(Exception);
447                }
448                return E_NOTIMPL;
449        }
450        STDMETHOD(GetIDsOfNames)(REFIID InterfaceIdentifier, LPOLESTR* ppszNames, UINT nNameCount, LCID nLocaleIdentifier, DISPID* rgDispId) throw()
451        {
452                _Z4(atlTraceCOM, 4, _T("this 0x%p, nNameCount %d, nLocaleIdentifier %d\n"), static_cast<T*>(this), nNameCount, nLocaleIdentifier);
453                _ATLTRY
454                {
455                        const HRESULT nResult = GetDispatch(0)->GetIDsOfNames(InterfaceIdentifier, ppszNames, nNameCount, nLocaleIdentifier, rgDispId);
456                        _Z4(atlTraceGeneral, 4, _T("nResult 0x%08x\n"), nResult);
457                        return nResult;
458                }
459                _ATLCATCH(Exception)
460                {
461                        _C(Exception);
462                }
463                return E_NOTIMPL;
464        }
465        STDMETHOD(Invoke)(DISPID dispIdMember, REFIID InterfaceIdentifier, LCID nLocaleIdentifier, WORD nFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) throw()
466        {
467                _Z4(atlTraceCOM, 4, _T("this 0x%p, dispIdMember %d, nLocaleIdentifier %d, nFlags 0x%x\n"), static_cast<T*>(this), dispIdMember, nLocaleIdentifier, nFlags);
468                _ATLTRY
469                {
470                        const HRESULT nResult = GetDispatch(0)->Invoke(dispIdMember, InterfaceIdentifier, nLocaleIdentifier, nFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
471                        _Z4(atlTraceGeneral, 4, _T("nResult 0x%08x\n"), nResult);
472                        return nResult;
473                }
474                _ATLCATCH(Exception)
475                {
476                        _C(Exception);
477                }
478                return E_NOTIMPL;
479        }
480};
481
482////////////////////////////////////////////////////////////
483// CLocations
484
485class ATL_NO_VTABLE CLocations : 
486        public CComObjectRootEx<CComMultiThreadModelNoCS>,
487        public CComCoClass<CLocations, &__uuidof(Locations)>,
488        public IDispatchImpl<ILocations>
489{
490public:
491        enum { IDR = IDR_LOCATIONS };
492
493//DECLARE_REGISTRY_RESOURCEID(IDR)
494
495DECLARE_CLASSFACTORY_SINGLETON(CLocations)
496
497DECLARE_PROTECT_FINAL_CONSTRUCT()
498
499BEGIN_COM_MAP(CLocations)
500        COM_INTERFACE_ENTRY(ILocations)
501        COM_INTERFACE_ENTRY(IDispatch)
502        COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(IMarshal), m_FreeThreadedMarshaler)
503END_COM_MAP()
504
505public:
506
507        ////////////////////////////////////////////////////////
508        // CLocation
509
510        class ATL_NO_VTABLE CLocation : 
511                public CComObjectRootEx<CComMultiThreadModelNoCS>,
512                public CComCoClass<CLocation, &__uuidof(Location)>,
513                public IDispatchImpl<ILocation>
514        {
515        public:
516
517        DECLARE_NO_REGISTRY()
518
519        //DECLARE_PROTECT_FINAL_CONSTRUCT()
520
521        BEGIN_COM_MAP(CLocation)
522                COM_INTERFACE_ENTRY(ILocation)
523                COM_INTERFACE_ENTRY(IDispatch)
524        END_COM_MAP()
525
526        private:
527                GeoLiteCity::CLocation m_Location;
528
529        public:
530        // CLocation
531                CLocation() throw()
532                {
533                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
534                }
535                ~CLocation() throw()
536                {
537                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
538                }
539                VOID Initialize(const GeoLiteCity::CLocation& Location)
540                {
541                        m_Location = Location;
542                }
543
544        // ILocation
545                STDMETHOD(get_Country)(BSTR* psCountry) throw()
546                {
547                        _Z4(atlTraceCOM, 4, _T("...\n"));
548                        _ATLTRY
549                        {
550                                __D(psCountry, E_POINTER);
551                                ObjectLock Lock(this);
552                                *psCountry = CComBSTR(m_Location.m_sCountryCode).Detach();
553                        }
554                        _ATLCATCH(Exception)
555                        {
556                                _C(Exception);
557                        }
558                        return S_OK;
559                }
560                STDMETHOD(get_Region)(BSTR* psRegion) throw()
561                {
562                        _Z4(atlTraceCOM, 4, _T("...\n"));
563                        _ATLTRY
564                        {
565                                __D(psRegion, E_POINTER);
566                                ObjectLock Lock(this);
567                                *psRegion = CComBSTR(m_Location.m_sRegion).Detach();
568                        }
569                        _ATLCATCH(Exception)
570                        {
571                                _C(Exception);
572                        }
573                        return S_OK;
574                }
575                STDMETHOD(get_City)(BSTR* psCity) throw()
576                {
577                        _Z4(atlTraceCOM, 4, _T("...\n"));
578                        _ATLTRY
579                        {
580                                __D(psCity, E_POINTER);
581                                ObjectLock Lock(this);
582                                *psCity = CComBSTR(m_Location.m_sCity).Detach();
583                        }
584                        _ATLCATCH(Exception)
585                        {
586                                _C(Exception);
587                        }
588                        return S_OK;
589                }
590                STDMETHOD(get_PostalCode)(BSTR* psPostalCode) throw()
591                {
592                        _Z4(atlTraceCOM, 4, _T("...\n"));
593                        _ATLTRY
594                        {
595                                __D(psPostalCode, E_POINTER);
596                                ObjectLock Lock(this);
597                                *psPostalCode = CComBSTR(m_Location.m_sPostalCode).Detach();
598                        }
599                        _ATLCATCH(Exception)
600                        {
601                                _C(Exception);
602                        }
603                        return S_OK;
604                }
605                STDMETHOD(get_Latitude)(DOUBLE* pfLatitude) throw()
606                {
607                        _Z4(atlTraceCOM, 4, _T("...\n"));
608                        _ATLTRY
609                        {
610                                __D(pfLatitude, E_POINTER);
611                                ObjectLock Lock(this);
612                                *pfLatitude = m_Location.m_fLatitude;
613                        }
614                        _ATLCATCH(Exception)
615                        {
616                                _C(Exception);
617                        }
618                        return S_OK;
619                }
620                STDMETHOD(get_Longitude)(DOUBLE* pfLongitude) throw()
621                {
622                        _Z4(atlTraceCOM, 4, _T("...\n"));
623                        _ATLTRY
624                        {
625                                __D(pfLongitude, E_POINTER);
626                                ObjectLock Lock(this);
627                                *pfLongitude = m_Location.m_fLongitude;
628                        }
629                        _ATLCATCH(Exception)
630                        {
631                                _C(Exception);
632                        }
633                        return S_OK;
634                }
635                STDMETHOD(get_MetroCode)(BSTR* psMetroCode) throw()
636                {
637                        _Z4(atlTraceCOM, 4, _T("...\n"));
638                        _ATLTRY
639                        {
640                                __D(psMetroCode, E_POINTER);
641                                ObjectLock Lock(this);
642                                *psMetroCode = CComBSTR(m_Location.m_sMetroCode).Detach();
643                        }
644                        _ATLCATCH(Exception)
645                        {
646                                _C(Exception);
647                        }
648                        return S_OK;
649                }
650                STDMETHOD(get_AreaCode)(BSTR* psAreaCode) throw()
651                {
652                        _Z4(atlTraceCOM, 4, _T("...\n"));
653                        _ATLTRY
654                        {
655                                __D(psAreaCode, E_POINTER);
656                                ObjectLock Lock(this);
657                                *psAreaCode = CComBSTR(m_Location.m_sAreaCode).Detach();
658                        }
659                        _ATLCATCH(Exception)
660                        {
661                                _C(Exception);
662                        }
663                        return S_OK;
664                }
665        };
666
667private:
668        CWindowsSockets2 m_Sockets;
669        CFreeThreadedMarshaler m_FreeThreadedMarshaler;
670        //mutable CRoCriticalSection m_DataCriticalSection;
671        GeoLiteCity::CLocationArray m_LocationArray;
672        GeoLiteCity::CBlockArray m_BlockArray;
673
674public:
675// CLocations
676        static CString GetObjectFriendlyName()
677        {
678                return _StringHelper::GetLine(IDR, 2);
679        }
680        static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()
681        {
682                _Z2(atlTraceRegistrar, 2, _T("bRegister %d\n"), bRegister);
683                _ATLTRY
684                {
685                        UpdateRegistryFromResource<CLocations>(bRegister);
686                }
687                _ATLCATCH(Exception)
688                {
689                        _C(Exception);
690                }
691                return S_OK;
692        }
693        CLocations() throw()
694        {
695                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
696        }
697        ~CLocations() throw()
698        {
699                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
700        }
701        HRESULT FinalConstruct() throw()
702        {
703                _ATLTRY
704                {
705                        __C(m_Sockets.GetStartupResult());
706                        m_FreeThreadedMarshaler.Initialize();
707                        Initialize();
708                }
709                _ATLCATCH(Exception)
710                {
711                        _C(Exception);
712                }
713                return S_OK;
714        }
715        VOID FinalRelease() throw()
716        {
717                m_FreeThreadedMarshaler.Terminate();
718        }
719        VOID Initialize()
720        {
721                TCHAR pszDirectory[MAX_PATH] = { 0 };
722                _W(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), pszDirectory, DIM(pszDirectory)));
723                _W(RemoveFileSpec(pszDirectory));
724                CPath sLocationPath, sBlockPath;
725                sLocationPath.Combine(pszDirectory, _T("GeoLiteCity-Location.csv"));
726                sBlockPath.Combine(pszDirectory, _T("GeoLiteCity-Blocks.csv"));
727                //CRoCriticalSectionLock DataLock(m_DataCriticalSection);
728                m_LocationArray.Initialize(sLocationPath);
729                m_BlockArray.Initialize(sBlockPath);
730        }
731
732// ILocations
733        STDMETHOD(get_Item)(VARIANT vIndex, ILocation** ppLocation) throw()
734        {
735                _Z4(atlTraceCOM, 4, _T("vIndex.vt 0x%x\n"), vIndex.vt);
736                _ATLTRY
737                {
738                        __D(ppLocation, E_POINTER);
739                        __D(vIndex.vt == VT_BSTR, E_INVALIDARG);
740                        ULONG nAddress;
741                        nAddress = ntohl(inet_addr(CW2A(vIndex.bstrVal)));
742                        if(nAddress == INADDR_NONE)
743                        {
744                                SOCKADDR_IN Address;
745                                __E(CSocket::AddressFromHost(CW2CT(vIndex.bstrVal), 0, Address));
746                                nAddress = ntohl(Address.sin_addr.S_un.S_addr);
747                        }
748                        //ObjectLock Lock(this);
749                        //CRoCriticalSectionLock DataLock(m_DataCriticalSection);
750                        CObjectPtr<CLocation> pLocation;
751                        const GeoLiteCity::CBlock* pBlock;
752                        if(m_BlockArray.Lookup(nAddress, &pBlock))
753                        {
754                                const GeoLiteCity::CLocation* pInternalLocation;
755                                if(m_LocationArray.Lookup(pBlock->m_nLocationIdentifier, &pInternalLocation))
756                                        pLocation.Construct()->Initialize(*pInternalLocation);
757                                else
758                                        _A(FALSE);
759                        }
760                        *ppLocation = pLocation.Detach();
761                }
762                _ATLCATCH(Exception)
763                {
764                        _C(Exception);
765                }
766                return S_OK;
767        }
768};
769
770OBJECT_ENTRY_AUTO(__uuidof(Locations), CLocations)
771
772////////////////////////////////////////////////////////////
773// CLazyLocations
774
775class ATL_NO_VTABLE CLazyLocations : 
776        public CComObjectRootEx<CComMultiThreadModelNoCS>,
777        public CComCoClass<CLazyLocations, &__uuidof(LazyLocations)>,
778        public IDispatchImpl<ILazyLocations>,
779        public IDispatchImpl<ILocations>,
780        public CDispatchExT<CLazyLocations>
781{
782        typedef CThreadT<CLazyLocations> CThread;
783
784public:
785        enum { IDR = IDR_LAZYLOCATIONS };
786
787//DECLARE_REGISTRY_RESOURCEID(IDR)
788
789DECLARE_CLASSFACTORY_SINGLETON(CLazyLocations)
790
791DECLARE_PROTECT_FINAL_CONSTRUCT()
792
793BEGIN_COM_MAP(CLazyLocations)
794        COM_INTERFACE_ENTRY(ILazyLocations)
795        COM_INTERFACE_ENTRY(ILocations)
796        COM_INTERFACE_ENTRY_IID(__uuidof(IDispatch), ILocations)
797        COM_INTERFACE_ENTRY(IDispatchEx)
798        COM_INTERFACE_ENTRY_AGGREGATE(__uuidof(IMarshal), m_FreeThreadedMarshaler)
799END_COM_MAP()
800
801private:
802        CFreeThreadedMarshaler m_FreeThreadedMarshaler;
803        mutable CRoCriticalSection m_ThreadCriticalSection;
804        CObjectPtr<CThread> m_pThread;
805        mutable CRoCriticalSection m_DataCriticalSection;
806        CObjectPtr<CLocations> m_pLocations;
807
808        DWORD ThreadProc(CThread* pThread, CEvent& InitializationEvent, CEvent& TerminationEvent)
809        {
810                CMultiThreadedApartment MultiThreadedApartment;
811                _W(InitializationEvent.Set());
812                CComPtr<ILocations> pLocations;
813                __C(pLocations.CoCreateInstance(__uuidof(Locations)));
814                const CObjectPtr<CLocations> pNativeLocations = static_cast<CLocations*>((ILocations*) pLocations);
815                _A(pNativeLocations);
816                {
817                        CRoCriticalSectionLock DataLock(m_DataCriticalSection);
818                        _A(!m_pLocations);
819                        m_pLocations = pNativeLocations;
820                }
821                TerminationEvent;
822                CRoCriticalSectionLock ThreadLock(m_ThreadCriticalSection);
823                _A(m_pThread == pThread || !m_pThread && WaitForSingleObject(TerminationEvent, 0) == WAIT_OBJECT_0);
824                m_pThread.Release();
825                return 0;
826        }
827
828public:
829// CLazyLocations
830        static CString GetObjectFriendlyName()
831        {
832                return _StringHelper::GetLine(IDR, 2);
833        }
834        static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()
835        {
836                _Z2(atlTraceRegistrar, 2, _T("bRegister %d\n"), bRegister);
837                _ATLTRY
838                {
839                        UpdateRegistryFromResource<CLazyLocations>(bRegister);
840                }
841                _ATLCATCH(Exception)
842                {
843                        _C(Exception);
844                }
845                return S_OK;
846        }
847        CLazyLocations() throw()
848        {
849                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
850        }
851        ~CLazyLocations() throw()
852        {
853                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
854        }
855        HRESULT FinalConstruct() throw()
856        {
857                _ATLTRY
858                {
859                        SetDispatchInterfaceIdentifiers(2, &__uuidof(ILazyLocations), &__uuidof(ILocations));
860                        CRoCriticalSectionLock ThreadLock(m_ThreadCriticalSection);
861                        CObjectPtr<CThread> pThread;
862                        __E(pThread.Construct()->Initialize(this, &CLazyLocations::ThreadProc));
863                        m_pThread = pThread;
864                }
865                _ATLCATCH(Exception)
866                {
867                        _C(Exception);
868                }
869                return S_OK;
870        }
871        VOID FinalRelease() throw()
872        {
873                CObjectPtr<CThread> pThread;
874                {
875                        CRoCriticalSectionLock ThreadLock(m_ThreadCriticalSection);
876                        m_pThread.Swap(pThread);
877                }
878        }
879        CObjectPtr<CLocations> GetLocations() const throw()
880        {
881                CRoCriticalSectionLock DataLock(m_DataCriticalSection);
882                return m_pLocations;
883        }
884
885// ILazyLocations
886        STDMETHOD(get_Initialized)(VARIANT_BOOL* pbInitialized) throw()
887        {
888                _Z4(atlTraceCOM, 4, _T("...\n"));
889                _ATLTRY
890                {
891                        __D(pbInitialized, E_POINTER);
892                        //ObjectLock Lock(this);
893                        //CRoCriticalSectionLock DataLock(m_DataCriticalSection);
894                        *pbInitialized = GetLocations() ? ATL_VARIANT_TRUE : ATL_VARIANT_FALSE;
895                }
896                _ATLCATCH(Exception)
897                {
898                        _C(Exception);
899                }
900                return S_OK;
901        }
902
903// ILocations
904        STDMETHOD(get_Item)(VARIANT vIndex, ILocation** ppLocation) throw()
905        {
906                _Z4(atlTraceCOM, 4, _T("vIndex.vt 0x%x\n"), vIndex.vt);
907                _ATLTRY
908                {
909                        __D(ppLocation, E_POINTER);
910                        __D(vIndex.vt == VT_BSTR, E_INVALIDARG);
911                        //ObjectLock Lock(this);
912                        //CRoCriticalSectionLock DataLock(m_DataCriticalSection);
913                        CComPtr<ILocation> pLocation;
914                        const CObjectPtr<CLocations> pLocations = GetLocations();
915                        if(pLocations)
916                                __C(pLocations->get_Item(vIndex, &pLocation));
917                        *ppLocation = pLocation.Detach();
918                }
919                _ATLCATCH(Exception)
920                {
921                        _C(Exception);
922                }
923                return S_OK;
924        }
925};
926
927OBJECT_ENTRY_AUTO(__uuidof(LazyLocations), CLazyLocations)
Note: See TracBrowser for help on using the repository browser.