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

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