656 lines
14 KiB
C++
656 lines
14 KiB
C++
// ==========================================================================
|
|
// Class Specification : COXAutoComplete
|
|
// ==========================================================================
|
|
// Header file : OXAutoComplete.cpp
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
//
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "OXAutoComplete.h"
|
|
#include "OXRegistryValFile.h"
|
|
#include "UTB64Bit.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
#pragma warning(disable : 4355)
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// COXAutoComplete
|
|
//////////////////////////////////////////////////////////////////////
|
|
COXAutoComplete* COXAutoComplete::m_pThis=NULL;
|
|
|
|
COXAutoComplete::COXAutoComplete(HWND hParentWnd) :
|
|
m_lstBox(this), m_hParent(hParentWnd)
|
|
{
|
|
m_pThis=this;
|
|
m_hkMsg=::SetWindowsHookEx(WH_CALLWNDPROC,CallWndProc,NULL,::GetCurrentThreadId());
|
|
ASSERT(m_hkMsg);
|
|
m_hkKbrd=::SetWindowsHookEx(WH_KEYBOARD,KeyboardProc,NULL,::GetCurrentThreadId());
|
|
ASSERT(m_hkKbrd);
|
|
m_hAttached=NULL;
|
|
m_bUpdate=FALSE;
|
|
|
|
|
|
}
|
|
|
|
COXAutoComplete::~COXAutoComplete()
|
|
{
|
|
Detach();
|
|
::UnhookWindowsHookEx(m_hkMsg);
|
|
::UnhookWindowsHookEx(m_hkKbrd);
|
|
if (::IsWindow(m_lstBox.GetSafeHwnd()))
|
|
m_lstBox.DestroyWindow();
|
|
}
|
|
|
|
BOOL COXAutoComplete::Attach(CWnd *pWnd, LPCTSTR lpszStorageName, DWORD dwOptions)
|
|
{
|
|
return Attach(pWnd->GetSafeHwnd(),lpszStorageName, dwOptions);
|
|
}
|
|
|
|
BOOL COXAutoComplete::Attach(HWND hWnd, LPCTSTR lpszStorageName, DWORD dwOptions)
|
|
{
|
|
ASSERT(hWnd);
|
|
|
|
if (!m_hkMsg || !m_hkKbrd)
|
|
return FALSE;
|
|
|
|
if (::IsWindow(hWnd))
|
|
{
|
|
if (!m_hParent)
|
|
m_hParent=::GetParent(hWnd);
|
|
COXAutoStorage* pStorage;
|
|
if (m_mpStorage.Lookup(hWnd,pStorage))
|
|
Detach(hWnd);
|
|
|
|
pStorage=NULL;
|
|
|
|
//try to find COXAutoStorage
|
|
POSITION pos=m_mpStorage.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
HWND hwnd;
|
|
COXAutoStorage* pMappedStorage=NULL;
|
|
m_mpStorage.GetNextAssoc(pos, hwnd, pMappedStorage);
|
|
if (pMappedStorage && pMappedStorage->GetName()==lpszStorageName)
|
|
{
|
|
pStorage=pMappedStorage;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pStorage)
|
|
{
|
|
m_mpStorage.SetAt(hWnd,pStorage);
|
|
m_mpOptions.SetAt(hWnd,dwOptions);
|
|
return TRUE;
|
|
}
|
|
pStorage=new COXAutoStorage(lpszStorageName);
|
|
m_mpStorage.SetAt(hWnd,pStorage);
|
|
m_mpOptions.SetAt(hWnd,dwOptions);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
LRESULT CALLBACK COXAutoComplete::CallWndProc(int nCode,
|
|
WPARAM wParam,
|
|
LPARAM lParam )
|
|
{
|
|
#if defined (_WINDLL)
|
|
#if defined (_AFXDLL)
|
|
AFX_MANAGE_STATE(AfxGetAppModuleState());
|
|
#else
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#endif
|
|
#endif
|
|
|
|
if (nCode<0)
|
|
{
|
|
return ::CallNextHookEx(m_pThis->m_hkMsg,nCode,wParam,lParam);
|
|
}
|
|
|
|
CWPSTRUCT* pSt=(CWPSTRUCT*) lParam;
|
|
COXAutoStorage* pStorage=NULL;
|
|
|
|
ASSERT(m_pThis);
|
|
|
|
if (!m_pThis->m_mpStorage.Lookup(pSt->hwnd,pStorage))
|
|
{
|
|
return ::CallNextHookEx(m_pThis->m_hkMsg,nCode,wParam,lParam);
|
|
}
|
|
|
|
|
|
switch (pSt->message)
|
|
{
|
|
case WM_SETTEXT:
|
|
case WM_PASTE:
|
|
case WM_CUT:
|
|
{
|
|
if (!m_pThis->m_bUpdate)
|
|
{
|
|
CString sText;
|
|
CWnd* pWnd=CWnd::FromHandle(pSt->hwnd);
|
|
pWnd->GetWindowText(sText);
|
|
m_pThis->OnContentsChange(pWnd->m_hWnd,sText);
|
|
}
|
|
}
|
|
break;
|
|
case WM_KILLFOCUS:
|
|
m_pThis->Hide();
|
|
}
|
|
return ::CallNextHookEx(m_pThis->m_hkMsg,nCode,wParam,lParam);
|
|
}
|
|
|
|
void COXAutoComplete::Detach(CWnd *pWnd)
|
|
{
|
|
Detach(pWnd->GetSafeHwnd());
|
|
}
|
|
|
|
void COXAutoComplete::Detach(HWND hWnd)
|
|
{
|
|
if (hWnd)
|
|
{
|
|
COXAutoStorage* pStorage;
|
|
if (m_mpStorage.Lookup(hWnd,pStorage))
|
|
{
|
|
m_mpStorage.RemoveKey(hWnd);
|
|
m_mpOptions.RemoveKey(hWnd);
|
|
}
|
|
else
|
|
return;
|
|
//try to find out who else is using this storage,
|
|
//if no one is using, delete it
|
|
COXAutoStorage* pTest=NULL;
|
|
POSITION pos=m_mpStorage.GetStartPosition();
|
|
|
|
while (pos)
|
|
{
|
|
HWND hwnd;
|
|
m_mpStorage.GetNextAssoc(pos,hwnd,pTest);
|
|
if (pTest==pStorage)
|
|
return;
|
|
}
|
|
delete pStorage;
|
|
return;
|
|
}
|
|
|
|
//detach all storages
|
|
POSITION pos=m_mpStorage.GetStartPosition();
|
|
|
|
//cannot delete directly because the same storage can be mapped
|
|
//to different windows
|
|
CMap<COXAutoStorage*,COXAutoStorage*,DWORD,DWORD> mpToDelete;
|
|
|
|
while (pos)
|
|
{
|
|
HWND hwnd;
|
|
COXAutoStorage* pStorage=NULL;
|
|
m_mpStorage.GetNextAssoc(pos,hwnd,pStorage);
|
|
mpToDelete.SetAt(pStorage,NULL);
|
|
}
|
|
|
|
//delete all objects
|
|
pos=mpToDelete.GetStartPosition();
|
|
while (pos)
|
|
{
|
|
COXAutoStorage* pStorage;
|
|
DWORD dwNULL;
|
|
mpToDelete.GetNextAssoc(pos,pStorage,dwNULL);
|
|
delete pStorage;
|
|
|
|
}
|
|
|
|
mpToDelete.RemoveAll();
|
|
m_mpStorage.RemoveAll();
|
|
m_mpOptions.RemoveAll();
|
|
}
|
|
|
|
|
|
LRESULT COXAutoComplete::KeyboardProc(int code,
|
|
WPARAM wParam, LPARAM lParam)
|
|
{
|
|
ASSERT(m_pThis);
|
|
|
|
if (code<0)
|
|
return ::CallNextHookEx(m_pThis->m_hkKbrd,code,wParam,lParam);
|
|
else
|
|
{
|
|
CString sText;
|
|
CWnd* pWnd=CWnd::GetFocus();
|
|
COXAutoStorage* pStorage;
|
|
_AFX_THREAD_STATE* pThreadState=AfxGetThreadState();
|
|
if(pThreadState->m_hTrackingWindow==NULL && pWnd!=NULL &&
|
|
m_pThis->m_mpStorage.Lookup(pWnd->m_hWnd,pStorage))
|
|
{
|
|
if (lParam<0)//key is pressed
|
|
{
|
|
switch (wParam)
|
|
{
|
|
case VK_NEXT:
|
|
case VK_PRIOR:
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
m_pThis->ChangeSel(PtrToInt(wParam));
|
|
return TRUE;
|
|
break;
|
|
default:
|
|
if (wParam>VK_HELP)
|
|
{
|
|
pWnd->GetWindowText(sText);
|
|
m_pThis->OnContentsChange(pWnd->m_hWnd,sText);
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (wParam)
|
|
{
|
|
case VK_NEXT:
|
|
case VK_PRIOR:
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ::CallNextHookEx(m_pThis->m_hkKbrd,code,wParam,lParam);
|
|
}
|
|
|
|
|
|
BOOL COXAutoComplete::OnContentsChange(HWND hwnd, CString sNewText)
|
|
{
|
|
COXAutoStorage* pStorage;
|
|
if (!m_mpStorage.Lookup(hwnd,pStorage))
|
|
return FALSE;
|
|
|
|
DWORD dwOptions;
|
|
VERIFY(m_mpOptions.Lookup(hwnd,dwOptions));
|
|
|
|
if (!dwOptions)
|
|
return FALSE;
|
|
|
|
CStringArray arsStrings;
|
|
ASSERT(pStorage);
|
|
UINT nCount=pStorage->GetMatchedStrings(sNewText, arsStrings);
|
|
|
|
if (nCount)
|
|
{
|
|
CWnd* pWnd=CWnd::FromHandle(hwnd);
|
|
if (dwOptions & OX_AUTOCOMPLETE_APPEND)
|
|
{
|
|
CString sText=arsStrings.GetAt(0);
|
|
int nLength=pWnd->GetWindowTextLength();
|
|
if (nLength<=sText.GetLength())
|
|
{
|
|
m_bUpdate=TRUE;
|
|
pWnd->SetWindowText(sText);
|
|
pWnd->SendMessage(EM_SETSEL,nLength,-1);
|
|
m_bUpdate=FALSE;
|
|
}
|
|
|
|
}
|
|
if (dwOptions & OX_AUTOCOMPLETE_LIST)
|
|
{
|
|
m_lstBox.m_bDraw=FALSE;
|
|
if (hwnd!=m_hAttached && m_lstBox.GetSafeHwnd())
|
|
m_lstBox.DestroyWindow();
|
|
|
|
|
|
//calculate height of the listbox
|
|
CDC* pDC=pWnd->GetDC();
|
|
SIZE sz;
|
|
sz.cx=sz.cy=0;
|
|
int nHeight=0;
|
|
int n=0;
|
|
for (n=0;n<arsStrings.GetSize();n++)
|
|
{
|
|
CString sText=arsStrings.GetAt(n);
|
|
VERIFY(::GetTextExtentPoint32(pDC->m_hDC,
|
|
(LPCTSTR) sText, sText.GetLength(),&sz));
|
|
if ((sz.cy+nHeight)<(OX_AUTOCOMPLETE_HEIGHTDEFAULTMAX-1))
|
|
nHeight+=sz.cy;
|
|
else
|
|
break;
|
|
}
|
|
nHeight+=2;
|
|
CRect rctWnd, rctWArea;
|
|
pWnd->GetWindowRect(&rctWnd);
|
|
|
|
//calculate vertical position of the listbox
|
|
VERIFY(::SystemParametersInfo(SPI_GETWORKAREA,NULL,&rctWArea,NULL));
|
|
if (rctWArea.bottom-rctWnd.bottom<nHeight)
|
|
{
|
|
//on the top of the window
|
|
rctWnd.bottom=rctWnd.top;
|
|
rctWnd.top-=nHeight;
|
|
}
|
|
else
|
|
{
|
|
rctWnd.top=rctWnd.bottom;
|
|
rctWnd.bottom+=nHeight;
|
|
}
|
|
|
|
m_lstBox.m_nHeight=sz.cy;
|
|
m_lstBox.m_nWidth=rctWnd.Width();
|
|
|
|
CWnd* pParent=CWnd::FromHandle(m_hParent);
|
|
pParent->ScreenToClient(rctWnd);
|
|
if (!::IsWindow(m_lstBox.GetSafeHwnd()))
|
|
{
|
|
VERIFY(m_lstBox.Create(WS_CHILD | WS_BORDER
|
|
| LBS_OWNERDRAWFIXED | WS_VSCROLL | LBS_HASSTRINGS,
|
|
rctWnd,pParent,
|
|
OX_AUTOCOMPLETE_IDC_LIST));
|
|
m_lstBox.ModifyStyleEx(0, WS_EX_TOPMOST | WS_EX_TOOLWINDOW);
|
|
m_lstBox.SetFont(pWnd->GetFont());
|
|
m_hAttached=hwnd;
|
|
}
|
|
else
|
|
{
|
|
CRect rctAct;
|
|
m_lstBox.GetWindowRect(&rctAct);
|
|
if (rctAct!=rctWnd)
|
|
m_lstBox.MoveWindow(&rctWnd);
|
|
m_lstBox.ResetContent();
|
|
}
|
|
|
|
for (n=0;n<arsStrings.GetSize();n++)
|
|
{
|
|
m_lstBox.AddString(arsStrings.GetAt(n));
|
|
}
|
|
if (!m_lstBox.IsWindowVisible())
|
|
m_lstBox.ShowWindow(SW_SHOW);
|
|
m_lstBox.m_bDraw=TRUE;
|
|
m_lstBox.SetWindowPos(&CWnd::wndTopMost,0,0,0,0,SWP_NOMOVE);
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
if (::IsWindow(m_lstBox.GetSafeHwnd()))
|
|
m_lstBox.ShowWindow(SW_HIDE);
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void COXAutoComplete::Complete(HWND hWnd)
|
|
{
|
|
COXAutoStorage* pStorage;
|
|
if (!m_mpStorage.Lookup(hWnd,pStorage))
|
|
return;
|
|
|
|
ASSERT(pStorage);
|
|
|
|
CWnd* pWnd=CWnd::FromHandlePermanent(hWnd);
|
|
CString sText;
|
|
pWnd->GetWindowText(sText);
|
|
if (!sText.IsEmpty())
|
|
{
|
|
pStorage->AddString(sText);
|
|
}
|
|
::SendMessage(m_hAttached,EM_SETSEL,(WPARAM)-1,(LPARAM)-1);
|
|
}
|
|
|
|
void COXAutoComplete::Hide()
|
|
{
|
|
|
|
if (::IsWindow(m_lstBox.GetSafeHwnd()))
|
|
m_lstBox.ShowWindow(SW_HIDE);
|
|
|
|
::SendMessage(m_hAttached,EM_SETSEL,(WPARAM)-1,(LPARAM)-1);
|
|
}
|
|
|
|
void COXAutoComplete::ChangeSel(int nKey)
|
|
{
|
|
if (::IsWindow(m_lstBox.GetSafeHwnd()))
|
|
{
|
|
int nSel=m_lstBox.GetCurSel();
|
|
if (nSel==-1)
|
|
{
|
|
m_lstBox.SetCurSel(0);
|
|
}
|
|
else
|
|
{
|
|
|
|
CRect rct;
|
|
m_lstBox.GetClientRect(rct);
|
|
int nCount=rct.Height()/m_lstBox.GetItemHeight(nSel);
|
|
switch (nKey)
|
|
{
|
|
case VK_UP:
|
|
if (nSel>0)
|
|
m_lstBox.SetCurSel(nSel-1);
|
|
break;
|
|
case VK_DOWN:
|
|
if (nSel<(m_lstBox.GetCount()-1))
|
|
m_lstBox.SetCurSel(nSel+1);
|
|
break;
|
|
case VK_NEXT:
|
|
if ((nSel+nCount)<m_lstBox.GetCount())
|
|
m_lstBox.SetCurSel(nSel+nCount-1);
|
|
else
|
|
m_lstBox.SetCurSel(m_lstBox.GetCount()-1);
|
|
break;
|
|
case VK_PRIOR:
|
|
if ((nSel-nCount+1)>0)
|
|
m_lstBox.SetCurSel(nSel-nCount+1);
|
|
else
|
|
m_lstBox.SetCurSel(0);
|
|
|
|
}
|
|
}
|
|
int nNewSel=m_lstBox.GetCurSel();
|
|
if (nNewSel!=nSel)
|
|
{
|
|
int nStartSel;
|
|
::SendMessage(m_hAttached,EM_GETSEL, (WPARAM) &nStartSel,NULL);
|
|
CString sText;
|
|
m_lstBox.GetText(nNewSel,sText);
|
|
m_bUpdate=TRUE;
|
|
::SendMessage(m_hAttached,WM_SETTEXT,NULL, (LPARAM) (LPCTSTR) sText);
|
|
m_bUpdate=FALSE;
|
|
::SendMessage(m_hAttached,EM_SETSEL, nStartSel, -1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void COXAutoComplete::SetDepth(UINT nDepth, HWND hWnd)
|
|
{
|
|
COXAutoStorage* pStorage=NULL;
|
|
if (m_mpStorage.Lookup(hWnd,pStorage))
|
|
{
|
|
ASSERT(pStorage);
|
|
pStorage->SetDepth(nDepth);
|
|
}
|
|
}
|
|
|
|
int COXAutoComplete::GetDepth(HWND hWnd)
|
|
{
|
|
int nRet=-1;
|
|
|
|
COXAutoStorage* pStorage=NULL;
|
|
if (m_mpStorage.Lookup(hWnd,pStorage))
|
|
{
|
|
ASSERT(pStorage);
|
|
nRet=pStorage->GetDepth();
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
COXAutoStorage* COXAutoComplete::GetStorage(HWND hWnd)
|
|
{
|
|
COXAutoStorage* pStorage=NULL;
|
|
if (m_mpStorage.Lookup(hWnd,pStorage))
|
|
return pStorage;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// COXAutoStorage
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
COXAutoStorage::COXAutoStorage(LPCTSTR lpszName,UINT nDepth) :
|
|
m_nDepth(nDepth)
|
|
{
|
|
if (lpszName && *lpszName)
|
|
m_sName=lpszName;
|
|
else
|
|
m_sName=OX_AUTOCOMPLETE_NAMEDEFAULT;
|
|
VERIFY(Load());
|
|
}
|
|
|
|
COXAutoStorage::~COXAutoStorage()
|
|
{
|
|
Save();
|
|
}
|
|
|
|
UINT COXAutoStorage::GetMatchedStrings(CString sText, CStringArray& arsStrings)
|
|
{
|
|
UINT nRslt=0;
|
|
for (int n=0; n<m_arsContents.GetSize();n++)
|
|
{
|
|
if (m_arsContents.GetAt(n).Find(sText)==0)
|
|
{
|
|
nRslt++;
|
|
arsStrings.Add(m_arsContents.GetAt(n));
|
|
}
|
|
}
|
|
return nRslt;
|
|
}
|
|
|
|
BOOL COXAutoStorage::AddString(CString sText)
|
|
{
|
|
if (sText.IsEmpty())
|
|
return FALSE;
|
|
ASSERT((UINT) m_arsContents.GetSize()<=m_nDepth);
|
|
|
|
//try to find the same string in the storage
|
|
for (int n=0;n<m_arsContents.GetSize();n++)
|
|
{
|
|
if (sText==m_arsContents.GetAt(n))
|
|
{
|
|
|
|
m_arsContents.RemoveAt(n);
|
|
m_arsContents.InsertAt(0,sText);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
m_arsContents.InsertAt(0,sText);
|
|
if ((UINT) m_arsContents.GetSize()>=m_nDepth)
|
|
m_arsContents.RemoveAt(m_nDepth);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXAutoStorage::Load()
|
|
{
|
|
CString sApp=AfxGetAppName();
|
|
sApp+=_T("\\Autocomplete");
|
|
COXRegistryValFile reg;
|
|
|
|
long lErr;
|
|
|
|
if (!reg.Open(HKEY_CURRENT_USER,sApp,m_sName,lErr))
|
|
return FALSE;
|
|
|
|
DWORD dwLength=(DWORD)reg.GetLength();
|
|
if (!dwLength)
|
|
return TRUE;
|
|
|
|
BYTE* pBuffer=new BYTE[dwLength+2];
|
|
::ZeroMemory(pBuffer,dwLength+2);
|
|
|
|
if (reg.Read(pBuffer,dwLength)!=dwLength)
|
|
{
|
|
delete []pBuffer;
|
|
reg.Close();
|
|
return FALSE;
|
|
}
|
|
|
|
reg.Close();
|
|
|
|
DWORD dwVersion=*((DWORD*) pBuffer);
|
|
if (dwVersion!=OX_AUTOCOMPLETE_VERSION)
|
|
{
|
|
delete []pBuffer;
|
|
return FALSE;
|
|
}
|
|
TCHAR* pChar=(TCHAR*) (pBuffer+4);
|
|
|
|
CString sText=pChar;
|
|
delete []pBuffer;
|
|
|
|
int nFind=sText.Find(_T("\r\n"));
|
|
while (nFind!=-1)
|
|
{
|
|
CString sString=sText.Left(nFind);
|
|
m_arsContents.Add(sString);
|
|
sText=sText.Right(sText.GetLength()-nFind-2);
|
|
nFind=sText.Find(_T("\r\n"));
|
|
}
|
|
while((UINT) m_arsContents.GetSize()>m_nDepth)
|
|
m_arsContents.RemoveAt(m_arsContents.GetSize()-1);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXAutoStorage::Save()
|
|
{
|
|
CString sApp=AfxGetAppName();
|
|
sApp+=_T("\\Autocomplete");
|
|
COXRegistryValFile reg;
|
|
|
|
long lErr;
|
|
|
|
if (!reg.Open(HKEY_CURRENT_USER,sApp,m_sName,lErr))
|
|
return FALSE;
|
|
|
|
reg.SetLength(0);
|
|
DWORD dwVersion=OX_AUTOCOMPLETE_VERSION;
|
|
reg.Write(&dwVersion, 4);
|
|
for (int i=0; i<m_arsContents.GetSize(); i++)
|
|
{
|
|
CString sString=m_arsContents.GetAt(i)+_T("\r\n");
|
|
reg.Write(sString, sString.GetLength());
|
|
}
|
|
reg.Close();
|
|
return TRUE;
|
|
}
|
|
|
|
void COXAutoStorage::SetDepth(UINT nDepth)
|
|
{
|
|
m_nDepth=nDepth;
|
|
}
|
|
|
|
UINT COXAutoStorage::GetDepth()
|
|
{
|
|
return m_nDepth;
|
|
}
|
|
|
|
void COXAutoComplete::SetParent(HWND hParentWnd)
|
|
{
|
|
m_hParent=hParentWnd;
|
|
}
|