Exemple #1
0
//
//The implementation of VirtualAlloc routine,it just calls the appropriate
//helper routines according the dwAllocFlags.
//
static LPVOID kVirtualAlloc(__COMMON_OBJECT* lpThis,
						   LPVOID           lpDesiredAddr,
						   DWORD            dwSize,
						   DWORD            dwAllocFlags,
						   DWORD            dwAccessFlags,
						   UCHAR*           lpVaName,
						   LPVOID           lpReserved)
{
	switch(dwAllocFlags)
	{
	case VIRTUAL_AREA_ALLOCATE_IO:    //Call DoIoMap only.
		return DoIoMap(lpThis,
			lpDesiredAddr,
			dwSize,
			dwAllocFlags,
			dwAccessFlags,
			lpVaName,
			lpReserved);
	case VIRTUAL_AREA_ALLOCATE_RESERVE:
		return DoReserve(lpThis,
			lpDesiredAddr,
			dwSize,
			dwAllocFlags,
			dwAccessFlags,
			lpVaName,
			lpReserved);
	case VIRTUAL_AREA_ALLOCATE_ALL:
		return DoReserveAndCommit(lpThis,
			lpDesiredAddr,
			dwSize,
			dwAllocFlags,
			dwAccessFlags,
			lpVaName,
			lpReserved);
	case VIRTUAL_AREA_ALLOCATE_COMMIT:
		return DoCommit(lpThis,
			lpDesiredAddr,
			dwSize,
			dwAllocFlags,
			dwAccessFlags,
			lpVaName,
			lpReserved);
	case VIRTUAL_AREA_ALLOCATE_IOCOMMIT:
		return DoIoCommit(lpThis,
			lpDesiredAddr,
			dwSize,
			dwAllocFlags,
			dwAccessFlags,
			lpVaName,
			lpReserved);
	default:
		return NULL;
	}
	return NULL;
}
void AudioTimingControllerKaraoke::AnnounceChanges(int syl) {
	if (syl < 0) return;

	if (syl == cur_syl || syl == cur_syl + 1) {
		AnnounceUpdatedPrimaryRange();
		AnnounceUpdatedStyleRanges();
	}
	AnnounceMarkerMoved();
	AnnounceLabelChanged();

	if (auto_commit)
		DoCommit();
	else {
		pending_changes = true;
		commit_id = -1;
	}
}
Exemple #3
0
STDMETHODIMP CCUBRIDRowset::DeleteRows(HCHAPTER hReserved, DBCOUNTITEM cRows,
				const HROW rghRows[], DBROWSTATUS rgRowStatus[])
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::DeleteRows\n");

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	CHECK_UPDATABILITY(DBPROPVAL_UP_DELETE);

	if(cRows==0) return S_OK;
	if(rghRows==NULL && cRows>=1) return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	int hConn = GetSessionPtr()->GetConnection();
	UINT uCodepage = GetSessionPtr()->GetCodepage();
	BOOL bSuccess = false;
	BOOL bFailed = false;
	for(DBCOUNTITEM i=0;i<cRows;i++)
	{
		HROW hRow = rghRows[i];

		// Attempt to locate the row in our map
		CCUBRIDRowsetRow *pRow;
		{
			bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow);
			if(!bFound || pRow==NULL)
			{	// invalid handle
				bFailed = true;
				if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_INVALID;
				continue;
			}
		}

		if(pRow->m_status==DBPENDINGSTATUS_DELETED)
		{	// already deleted
			if(rgRowStatus) rgRowStatus[i] = DBROWSTATUS_E_DELETED;
			bFailed  = true;
			continue;
		}

		ATLASSERT( pRow->m_iRowset==(ULONG)-1 || pRow->m_iRowset<m_rgRowData.GetCount() );

		DBROWSTATUS rowStat = DBROWSTATUS_S_OK;

		// mark the row as deleted
		if(pRow->m_status==DBPENDINGSTATUS_INVALIDROW)
		{
			bFailed = true;
			// unsigned high bit signified neg. number
			if(pRow->m_dwRef & 0x80000000)		
				rowStat = DBROWSTATUS_E_INVALID;
			else
				rowStat = DBROWSTATUS_E_DELETED;
		}
		else if(pRow->m_iRowset==(ULONG)-1 && pRow->m_status!=DBPENDINGSTATUS_NEW)
		{	// 새로 삽입되었고 Storage로 전송됐다.
			bFailed = true;
			rowStat = DBROWSTATUS_E_NEWLYINSERTED;
		}
		else
		{
			bSuccess = true;
			rowStat = DBROWSTATUS_S_OK;
			if(pRow->m_status==DBPENDINGSTATUS_NEW)
				MakeRowInvalid(this, pRow);
			else
				pRow->m_status = DBPENDINGSTATUS_DELETED;
		}

		if(!bDeferred && pRow->m_status==DBPENDINGSTATUS_DELETED)
		{	// 변화를 지금 적용
			// CCUBRIDRowsetRow의 delete는 ReleaseRows에서 이루어진다.
			HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);
			if(FAILED(hr)) return hr;

			MakeRowInvalid(this, pRow);
		}

		if(rgRowStatus) rgRowStatus[i] = rowStat;
	}

	if(!bDeferred)
		DoCommit(this); // commit

	if(bFailed)
	{
		if(bSuccess)
			return DB_S_ERRORSOCCURRED;
		else
			return RaiseError(DB_E_ERRORSOCCURRED, 0, __uuidof(IRowsetChange));
	}
	else
		return S_OK;
}
Exemple #4
0
STDMETHODIMP CCUBRIDRowset::Update(HCHAPTER hReserved, DBCOUNTITEM cRows, const HROW rghRows[],
				DBCOUNTITEM *pcRows, HROW **prgRows, DBROWSTATUS **prgRowStatus)
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::Update\n");

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetUpdate), L"This object is in a zombie state");
	CHECK_RESTART(__uuidof(IRowsetUpdate));

	DBCOUNTITEM ulRows = 0; // update할 row 수
	bool bNotIgnore = true; // prgRows, prgRowStatus를 무시할지 여부를 나타냄

	// the following lines are used to fix the two _alloca calls below.  Those calls are risky 
	// because we may be allocating huge amounts of data.  So instead I'll allocate that data on heap.
	// But if you use _alloca you don't have to worry about cleaning this memory.  So we will use these
	// temporary variables to allocate memory on heap.  As soon as we exit the function, the memory will
	// be cleaned up, just as if we were using alloca. So now, instead of calling alloca, I'll alloc
	// memory on heap using the two smnart pointers below, and then assing it to the actual pointers.
	CHeapPtr<HROW> spTempRows;
	CHeapPtr<DBROWSTATUS> spTempRowStatus;

	if(cRows || pcRows)
	{
		if(prgRows) *prgRows = NULL;
		if(prgRowStatus) *prgRowStatus = NULL;		
	}
	else
	{
		bNotIgnore = false;		// Don't do status or row arrays
	}

	// Check to see how many changes we'll undo 
	if(pcRows)
	{
		*pcRows = NULL;
		if(prgRows==NULL) return E_INVALIDARG;
	}

	if(cRows)
	{
		if(rghRows==NULL) return E_INVALIDARG;
		ulRows = cRows;
	}
	else
		ulRows = (DBCOUNTITEM)m_rgRowHandles.GetCount();

	int hConn = GetSessionPtr()->GetConnection();
	UINT uCodepage = GetSessionPtr()->GetCodepage();
	// NULL out pointers
	{
		if(prgRows && ulRows && bNotIgnore)
		{
			// Make a temporary buffer as we may not fill up everything
			// in the case where cRows == 0
			if(cRows)
				*prgRows = (HROW*)CoTaskMemAlloc(ulRows * sizeof(HROW));
			else
			{
				spTempRows.Allocate(ulRows);
				*prgRows = spTempRows;
			}
			if (*prgRows==NULL) return E_OUTOFMEMORY;
		}

		if(prgRowStatus && ulRows && bNotIgnore)
		{
			if(cRows)
				*prgRowStatus = (DBROWSTATUS*)CoTaskMemAlloc(ulRows * sizeof(DBROWSTATUS));
			else
			{
				spTempRowStatus.Allocate(ulRows);
				*prgRowStatus = spTempRowStatus;
			}
			if(*prgRowStatus==NULL)
			{
				if(cRows) CoTaskMemFree(*prgRows);
				*prgRows = NULL;
				return E_OUTOFMEMORY;
			}
		}
	}

	bool bSucceeded = false;
	bool bFailed = false;
	ULONG ulCount = 0; // update된 row 수
	POSITION pos = m_rgRowHandles.GetStartPosition();
	for (ULONG ulRow = 0; ulRow < ulRows; ulRow++)
	{
		ULONG ulCurrentRow = ulCount;
		bool bDupRow = false; // 중복된 row
		ULONG ulAlreadyProcessed = 0; // 중복된 row의 handle의 위치

		HROW hRowUpdate = NULL; // 현재 update할 row의 handle
		{
			if(cRows)
			{	// row handle이 주어졌음
				hRowUpdate = rghRows[ulRow];
				for (ULONG ulCheckDup = 0; ulCheckDup < ulRow; ulCheckDup++)
				{
					if (hRowUpdate==rghRows[ulCheckDup] ||
						IsSameRow(hRowUpdate, rghRows[ulCheckDup]) == S_OK)
					{
						ulAlreadyProcessed = ulCheckDup;
						bDupRow = true;
						break;
					}
				}
			}
			else
			{	// 모든 row에 대해 update
				//ATLASSERT(ulRow < (ULONG)m_rgRowHandles.GetCount()); // delete된 row가 있으면 성립하지 않는다.
				ATLASSERT( pos != NULL );
				MapClass::CPair* pPair = m_rgRowHandles.GetNext(pos);
				ATLASSERT( pPair != NULL );
				hRowUpdate = pPair->m_key;
			}
		}

		if(prgRows && bNotIgnore)
			(*prgRows)[ulCurrentRow] = hRowUpdate;

		if(bDupRow)
		{
			// We've already set the row before, just copy status and
			// continue processing
			if(prgRowStatus && bNotIgnore)
				(*prgRowStatus)[ulCurrentRow] = (*prgRowStatus)[ulAlreadyProcessed];
			ulCount++;
			continue;
		}

		// Fetch the RowClass and determine if it is valid
		CCUBRIDRowsetRow *pRow;
		{
			bool bFound = m_rgRowHandles.Lookup((ULONG)hRowUpdate, pRow);
			if (!bFound || pRow == NULL)
			{
				if (prgRowStatus && bNotIgnore)
					(*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_INVALID;
				bFailed = true;
				ulCount++;
				continue;
			}
		}

		// If cRows is zero we'll go through all rows fetched.  We
		// shouldn't increment the attempted count for rows that are
		// not changed
		if (cRows != 0 || (pRow != NULL &&
			pRow->m_status != 0 && pRow->m_status != DBPENDINGSTATUS_UNCHANGED
			&& pRow->m_status != DBPENDINGSTATUS_INVALIDROW))
			ulCount++;
		else
			continue;

		if(cRows==0)
			pRow->AddRefRow();

		switch (pRow->m_status)
		{
		case DBPENDINGSTATUS_INVALIDROW:	// Row is bad or deleted
			{
				if(prgRowStatus && bNotIgnore)
					(*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_E_DELETED;
				bFailed = true;
			}
			break;
		case DBPENDINGSTATUS_UNCHANGED:
		case 0:
			{
				// If the row's status is not changed, then just put S_OK
				// and continue.  The spec says we should not transmit the
				// request to the data source (as nothing would change).
				if(prgRowStatus && bNotIgnore)
					(*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK;
				bSucceeded = true;
			}
			break;
		default:
			{
				DBORDINAL cCols;
				ATLCOLUMNINFO *pColInfo = GetColumnInfo(this, &cCols);
				HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);
				if(FAILED(hr))
				{
					DBROWSTATUS stat = DBROWSTATUS_E_FAIL;
					if(hr==DB_E_INTEGRITYVIOLATION) stat = DBROWSTATUS_E_INTEGRITYVIOLATION;
					if(prgRowStatus && bNotIgnore)
						(*prgRowStatus)[ulCurrentRow] = stat;
					bFailed = true;
				}
				else
				{
					//// m_iRowset을 적당히 조정한다.
					//if(pRow->m_status==DBPENDINGSTATUS_NEW)
					//{
					//	// NEW인 row는 항상 rowset의 뒤에 몰려있다.
					//	// 그 row 중 가장 작은 m_iRowset이 update 된 row의 m_iRowset이 되면 된다.
					//	CCUBRIDRowsetRow::KeyType key = pRow->m_iRowset;
					//	POSITION pos = m_rgRowHandles.GetStartPosition();
					//	while(pos)
					//	{
					//		CCUBRIDRowset::MapClass::CPair *pPair = m_rgRowHandles.GetNext(pos);
					//		ATLASSERT(pPair);
					//		CCUBRIDRowsetRow *pCheckRow = pPair->m_value;
					//		if( pCheckRow && pCheckRow->m_iRowset < key )
					//		{
					//			if(pCheckRow->m_iRowset<pRow->m_iRowset)
					//				pRow->m_iRowset = pCheckRow->m_iRowset;
					//			pCheckRow->m_iRowset++;
					//		}
					//	}

					//	// TODO: 북마크 업데이트가 필요한데 어떻게 해야 할지 모르겠다.

					//	// 새로 추가된 Row의 OID를 읽어들인다.
					//	pRow->ReadData(GetRequestHandle(), true);
					//}

					if(pRow->m_status==DBPENDINGSTATUS_DELETED)
						MakeRowInvalid(this, pRow);
					else
						pRow->m_status = DBPENDINGSTATUS_UNCHANGED;

					if(prgRowStatus && bNotIgnore)
						(*prgRowStatus)[ulCurrentRow] = DBROWSTATUS_S_OK;
					bSucceeded = true;

					// Check if we need to release the row because it's ref was 0
					// See the IRowset::ReleaseRows section in the spec for more
					// information
					if (pRow->m_dwRef == 0)
					{
						pRow->AddRefRow();	// Artifically bump this to remove it
						if( FAILED( RefRows(1, &hRowUpdate, NULL, NULL, false) ) )
							return E_FAIL;
					}
				}
			}
			break;
		}
	}

	// Set the output for rows undone.
	if(pcRows) *pcRows = ulCount;

	if(ulCount==0)
	{
		if(prgRows)
		{
			CoTaskMemFree(*prgRows);
			*prgRows = NULL;
		}

		if(prgRowStatus)
		{
			CoTaskMemFree(*prgRowStatus);
			*prgRowStatus = NULL;
		}
	}
	else if(cRows==0)
	{
		// In the case where cRows == 0, we need to allocate the final
		// array of data.
		if(prgRows && bNotIgnore)
		{
			HROW *prgRowsTemp = (HROW *)CoTaskMemAlloc(ulCount*sizeof(HROW));
			if(prgRowsTemp==NULL) return E_OUTOFMEMORY;
			memcpy(prgRowsTemp, *prgRows, ulCount*sizeof(HROW));
			*prgRows = prgRowsTemp;
		}

		if(prgRowStatus && bNotIgnore)
		{
			DBROWSTATUS *prgRowStatusTemp = (DBROWSTATUS *)CoTaskMemAlloc(ulCount*sizeof(DBROWSTATUS));
			if(prgRowStatusTemp==NULL)
			{
				CoTaskMemFree(*prgRows);
				*prgRows = NULL;
				return E_OUTOFMEMORY;
			}
			memcpy(prgRowStatusTemp, *prgRowStatus, ulCount*sizeof(DBROWSTATUS));
			*prgRowStatus = prgRowStatusTemp;
		}
	}

	DoCommit(this); // commit

	// Send the return value
	if(!bFailed)
		return S_OK;
	else
	{
		return bSucceeded ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED;
	}
}
Exemple #5
0
STDMETHODIMP CCUBRIDRowset::InsertRow(HCHAPTER hReserved, HACCESSOR hAccessor, void *pData, HROW *phRow)
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::InsertRow\n");

	if(phRow) *phRow = NULL;

	if(phRow)
		CHECK_CANHOLDROWS(__uuidof(IRowsetChange));

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	CHECK_UPDATABILITY(DBPROPVAL_UP_INSERT);

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	// 바인딩 정보를 구함
	ATLBINDINGS *pBinding;
	{
		bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding);
		if(!bFound || pBinding==NULL)
			return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange));
		if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA))
			return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다.
		if(pData==NULL && pBinding->cBindings!=0)
			return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));
	}

	CCUBRIDRowsetRow *pRow;
	CCUBRIDRowsetRow::KeyType key;
	{	// 새 row를 위한 Row class를 생성한다.
		DBORDINAL cCols;
		ATLCOLUMNINFO *pColInfo = GetColumnInfo(this, &cCols);
		ATLTRY(pRow = new CCUBRIDRowsetRow(m_uCodepage, -1, cCols, pColInfo, m_spConvert, m_Columns.m_defaultVal));
		if(pRow==NULL) return RaiseError(E_OUTOFMEMORY, 0, __uuidof(IRowsetChange));

		// row handle에 추가
		key = (CCUBRIDRowsetRow::KeyType)m_rgRowData.GetCount();
		if (key == 0) key++;
		
		while(m_rgRowHandles.Lookup(key)) key++;
		m_rgRowHandles.SetAt(key, pRow);

		// rowset에 데이터가 하나 늘었다.
//		m_rgRowData.SetCount(m_rgRowData.GetCount()+1);
	}

	HRESULT hrRead = pRow->ReadData(pBinding, pData, m_uCodepage);
	if(FAILED(hrRead))
	{
//		m_rgRowData.SetCount(m_rgRowData.GetCount()-1);
		m_rgRowHandles.RemoveKey(key);
		delete pRow;
		return hrRead;
	}
	pRow->m_status = DBPENDINGSTATUS_NEW;

	if(phRow)
	{	// handle을 반환할 때는 참조 카운트를 하나 증가시킨다.
		pRow->AddRefRow();
		*phRow = (HROW)key;
	}

//	m_rgBookmarks.Add(pRow->m_iRowset+1);

	if(!bDeferred)
	{	// 변화를 지금 적용
		int hConn = GetSessionPtr()->GetConnection();
		UINT uCodepage = GetSessionPtr()->GetCodepage();
		HRESULT hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);
		if(FAILED(hr))
		{
			pRow->ReleaseRow();
			if (phRow != NULL)
				*phRow = NULL;
			return hr;
		}

		pRow->m_status = 0; // or UNCHANGED?
		if(pRow->m_dwRef==0)
		{
			m_rgRowHandles.RemoveKey(key);
			delete pRow;
		}

		DoCommit(this); // commit

		//// deferred update 모드였다가 immediate update 모드로 바뀌지는 않으므로
		//// 다른 NEW 상태의 row는 없다. 즉 m_iRowset을 변경해야 할 row는 없다.

		//// 새로 추가된 Row의 OID를 읽어들인다.
		//pRow->ReadData(GetRequestHandle(), true);
	}

	return hrRead;
}
Exemple #6
0
STDMETHODIMP CCUBRIDRowset::SetData(HROW hRow, HACCESSOR hAccessor, void *pData)
{
	ATLTRACE(atlTraceDBProvider, 2, "CCUBRIDRowset::SetData\n");

	ClearError();
	if(m_nStatus==1) return RaiseError(E_UNEXPECTED, 1, __uuidof(IRowsetChange), L"This object is in a zombie state");

	// cci_cursor_update를 이용하면 질의를 재실행할 때까지 SetData를 실행할 수 없다.
	// SQL and cci_execute를 이용하면 가능하다.
	CHECK_RESTART(__uuidof(IRowsetChange));

	CHECK_UPDATABILITY(DBPROPVAL_UP_CHANGE);

	// Determine if we're in immediate or deferred mode
	bool bDeferred = IsDeferred(this);

	// Attempt to locate the row in our map
	CCUBRIDRowsetRow *pRow;
	{
		bool bFound = m_rgRowHandles.Lookup((ULONG)hRow, pRow);
		if(!bFound || pRow==NULL)
			return RaiseError(DB_E_BADROWHANDLE, 0, __uuidof(IRowsetChange));
	}

	ATLASSERT( pRow->m_iRowset==(ULONG)-1 || pRow->m_iRowset<m_rgRowData.GetCount() );

	// 이미 지워진 row
	if(pRow->m_status==DBPENDINGSTATUS_DELETED || pRow->m_status==DBPENDINGSTATUS_INVALIDROW)
		return RaiseError(DB_E_DELETEDROW, 0, __uuidof(IRowsetChange));

	// 새로 삽입되었고 Storage로 전송됐다.
	if(pRow->m_iRowset==(ULONG)-1 && pRow->m_status!=DBPENDINGSTATUS_NEW)
		return DB_E_NEWLYINSERTED;

	// 바인딩 정보를 구함
	ATLBINDINGS *pBinding;
	{
		bool bFound = m_rgBindings.Lookup((ULONG)hAccessor, pBinding);
		if(!bFound || pBinding==NULL)
			return RaiseError(DB_E_BADACCESSORHANDLE, 0, __uuidof(IRowsetChange));
		if(!(pBinding->dwAccessorFlags & DBACCESSOR_ROWDATA))
			return RaiseError(DB_E_BADACCESSORTYPE, 0, __uuidof(IRowsetChange)); // row accessor 가 아니다.
		if(pData==NULL && pBinding->cBindings!=0)
			return RaiseError(E_INVALIDARG, 0, __uuidof(IRowsetChange));
	}

	HRESULT hr = pRow->ReadData(pBinding, pData, m_uCodepage);
	if(FAILED(hr)) return hr;
	// 새로 삽입된 row는 변경이 있어도 그냥 새로 삽입된 것으로 표시
	if(pRow->m_status!=DBPENDINGSTATUS_NEW)
		pRow->m_status = DBPENDINGSTATUS_CHANGED;

	if(!bDeferred)
	{	// 변화를 지금 적용
		int hConn = GetSessionPtr()->GetConnection();
		UINT uCodepage = GetSessionPtr()->GetCodepage();
		hr = pRow->WriteData(hConn, uCodepage, GetRequestHandle(), m_strTableName);

		if (hr == DB_E_INTEGRITYVIOLATION)
			return RaiseError(DB_E_INTEGRITYVIOLATION, 0, __uuidof(IRowsetChange));

		if(FAILED(hr)) return RaiseError(DB_E_ERRORSOCCURRED, 0, __uuidof(IRowsetChange));
		
		pRow->m_status = 0; // or UNCHANGED?
		DoCommit(this); // commit
	}

	return hr; // S_OK or DB_S_ERRORSOCCURRED
}
Exemple #7
0
MsgResult CBaseBrushNameDlg::Message(Msg* pMessage)
{
	// A message from the dialog or its gadgets?
	if (IS_OUR_DIALOG_MSG(pMessage))
	{
		DialogMsg* pMsg = (DialogMsg*) pMessage;
		switch (pMsg->DlgMsg)
		{
		case DIM_CREATE:
			InitGadgetText();
			break;

		case DIM_TEXT_CHANGED:
			// Disable the OK/Apply button if there's no document or entered text.
			EnableGadget(_R(IDOK), !GetStringGadgetValue(_R(IDC_EDITBRUSHNAME), 0).IsEmpty()
							&& Document::GetSelected() != 0);
			break;

		case DIM_LFT_BN_CLICKED:	// enter messages when the edit box has the focus get cast to this
			if (pMsg->GadgetID == _R(ID_CC_HELP_BUTTON))
				break;
		case DIM_COMMIT:
			{
				// Check name for validity.
				String_256 strEnter = GetStringGadgetValue(_R(IDC_EDITBRUSHNAME), 0);
				UINT32 nErrID = IsValid(strEnter);
				
				if (nErrID != 0)
				{
					// Invalid, reinitialise.
					InformError(nErrID);
					if (nErrID == _R(IDS_BRUSHNAME_INVALID))
					{
						String_32 s(strEnter);
						InitGadgetText(&s, FALSE);
					}
					else
						InitGadgetText(NULL);
					break;
				}
				else
				{
					// Entry is valid, try committing it.
					String_32 FinalString(strEnter);
					if (DoCommit(strEnter))
					{
						// Don't close, reinitialise (dialog is modeless).
						InitGadgetText();
						pMsg->DlgMsg = DIM_NONE; // stop base class closing it
						break;
					}
					else
					{
						// Close();
						// End(); - base class will close
						break;
					}
				}
						
			}
			break;
		case DIM_CANCEL:
			HandleCancel(); // base class will close
			break;
		default:
			break;
		}
	}
	

	// Has the document been switched or closed?
	else if (MESSAGE_IS_A(pMessage, DocChangingMsg))
	{
		DocChangingMsg* pMsg = (DocChangingMsg*) pMessage;
		if (pMsg->State == DocChangingMsg::SELCHANGED)
			EnableGadget(_R(IDOK), pMsg->pNewDoc != 0);
	}

	// Pass everything on to the base class . . .
	return DialogOp::Message(pMessage);
}  
void AudioTimingControllerKaraoke::Commit() {
	if (!auto_commit && pending_changes)
		DoCommit();
}
void CMWrongQuestion::Commit()
{
    DoCommit();
}