Тема: Вопрос по acedSSGetFirst

Привет всем!!! У меня такой избитый вопрос по acedSSGetFirst и все-таки :)
Есть вот такая вот функция взятая с этого форума:) :

void GetFirst(void)
{
  AcGeMatrix3d matTr;
  AcGePoint3d ptDisp;
if (acedSSGetFirst(NULL,&pset) == RTNORM && pset && pset->restype == RTPICKS)
   {
     ads_name ss;
    ads_name_set(pset->resval.rlname,ss);
    long nset = 0;
    acedSSLength(ss,&nset);
    ads_name ent;
    AcDbObjectId id = AcDbObjectId::kNull;
    ptDisp.set(0.0,200.0,0.0);
    matTr.setToIdentity();
    matTr.setToTranslation(ptDisp.asVector());
    for (long i = 0; i < nset; i++)
     {
          if (acedSSName(ss,i,ent) != RTNORM) continue;
        if (acdbGetObjectId(id,ent) != Acad::eOk) continue;
        AcDbEntity* pEnt = NULL;
        if (acdbOpenAcDbEntity(pEnt,id,AcDb::kForWrite) != Acad::eOk) continue;
                  pEnt->setColorIndex(1);
        pEnt->transformBy(matTr);
        pEnt->close();
    }
    acutPrintf(_T("\nБыло предварительно выбрано примитивов: <%d>"),nset);
  }
 else
 {
   acutPrintf(_T("\nНе было предварительного выбора или его нельзя получить!"));
 }
}

Так вот суть проблемы в том, что при ее вызове из initApp()
все работает OK!, а вот при повторном вызове из любой другой функции не делает ни каких действий. Пишет что ничего не выбрано хотя елементы выбраны. Подскажите пожалуйста в чем может быть дело?

Re: Вопрос по acedSSGetFirst

> Constantine
Видимо в невнимательном чтении документации. :(

Note The addCommand() optional flags ACRX_CMD_USEPICKSET and ACRX_CMD_REDRAW must be used in order for acedSSGetFirst() to work.

Re: Вопрос по acedSSGetFirst

Александр Ривилис (2007-08-20 23:47:13)
Большое спасибо!.
С этим вроде понятно. Только вот почему не получается вызвать вышеприведенную функцию из другой функции. Например при использовании acedRegisterWatchWinMsg() и после нажатия определенной клавиши вызвать мою функцию где используется acedSSGetFirst() или это возможно только через addCommand()???

Re: Вопрос по acedSSGetFirst

> Constantine
Попробуй в этом контексте: acedSSGet(_T("_I"),NULL,NULL,NULL,ss);

Re: Вопрос по acedSSGetFirst

Уже пробывал результат такой-же возвращает
RTERROR. Что может быть еще?

Re: Вопрос по acedSSGetFirst

> Constantine
Запускай из обработчика зарегистрированную команду, в которой и выполняй то что тебе нужно.

Re: Вопрос по acedSSGetFirst

Я уже так попробывал, но комманда не передается.
Делаю так:
1)Регистрирую hook с помощью acedRegisterFilterWinMsg(filterLC)
2)Проверяю клавишу:

void filterLC(MSG *pMsg)
{
if (pMsg->message == WM_KEYDOWN
&& pMsg->wParam  == VK_DELETE)
 {
  acedCommand(RTSTR, _T("my_cmd_1"),  RTSTR, _T(""), RTNONE);
 }
}

И результата НЕТ! комманда не вызывается.
И еще один подвопросик как сделать так чтобы реакция на клавишу происходила только в окне
MODEL SPACE и никаких других? Если можно то с небольшим примером кода пожалуйста.

Re: Вопрос по acedSSGetFirst

По поводу первого вопроса:
1) acedCommand в этом контексте использовать нельзя. Можно или acedPostCommand или curDoc()->sendStringToExecute()
2) В твоем коде ты не блокируешь действие клавиши DELETE, что приводит к тому что AutoCAD должен удалить выбранные тобой примитивы. Функция acedRegisterFilterWinMsg требует callback-функции, которая возвращает TRUE или FALSE. Причем если она возвращает TRUE, то этот MSG не передается дальше для обработки в AutoCAD.
Вот пример работающей функции, которая запускает команду _ERASE если нажата клавиша DELETE:

BOOL IsPickFirstEmpty()
{
  RB *gset = NULL, *pset = NULL;
  BOOL flag_empty = TRUE;
  if (acedSSGetFirst(&gset,&pset) == RTNORM) {
    if (pset) {
      if (pset->restype == RTPICKS) {
        long l = 0;
        acedSSLength(pset->resval.rlname,&l);
        acedSSFree(pset->resval.rlname);
        if (l > 0) flag_empty = FALSE;
      }
      acutRelRb(pset);
    }
    if (gset) {
      if (gset->restype == RTPICKS) acedSSFree(gset->resval.rlname);
      acutRelRb(gset);
    }
  }
  return flag_empty;
}
BOOL IsEmptyCmdLine()
{
  CString Colon = _T(":");
  CWnd *wTextCmdLine = acedGetAcadTextCmdLine();
  if (wTextCmdLine) {
    //---------------------------------------------------------------
    // Find First Child Window of AcadTextCmdLine window is command
    // line, which must have only text "Command:"
    // (or localized version of this text)
    //---------------------------------------------------------------
    CWnd *wCommandLine = wTextCmdLine->GetWindow(GW_CHILD);
    if (wCommandLine) {
      // Is command line empty?
      // Algorithm: Last nonblank symbol in command line must be ":" and
      // there is not other ":" in command line!
      CString sCommandLine;
      wCommandLine->GetWindowText(sCommandLine);
      // Delete all right blank symbols
      sCommandLine.TrimRight();
      // Is last nonblank symbol ":" ?
      if (sCommandLine.Right(1)    != Colon) return FALSE;
      // Is where any other ":" in command line ?
      if (sCommandLine.Find(Colon) != sCommandLine.GetLength()-1) return FALSE;
    }
  }
  return TRUE;
}
//
// This function gets the Window messages
// *BEFORE* AutoCAD processes them.
//
BOOL filterProc(MSG *pMsg)
{
  if (pMsg->message != WM_KEYDOWN)    return FALSE;       // Continue
  if (GetKeyState(VK_SHIFT) & 0x8000) return FALSE;       // Continue
  if (pMsg->wParam == VK_DELETE) {
    if (pMsg->hwnd == acedGetAcadDwgView()->GetSafeHwnd() ||
        (GetParent(pMsg->hwnd) == acedGetAcadTextCmdLine()->GetSafeHwnd() &&
        pMsg->hwnd != GetWindow(acedGetAcadTextCmdLine()->GetSafeHwnd(),GW_CHILD)) ||
        (GetParent(pMsg->hwnd) == acedGetAcadDockCmdLine()->GetSafeHwnd() &&
        pMsg->hwnd != GetWindow(acedGetAcadDockCmdLine()->GetSafeHwnd(),GW_CHILD))) {
      //
      // Step 1: Make sure that there is no active command
      //         and that there is nothing in the command line.
      RB var;
      if (acedGetVar(_T("CMDACTIVE"),&var) == RTNORM && var.resval.rint == 0)  {
        if (IsEmptyCmdLine() && !IsPickFirstEmpty()) {
          acedPostCommand(_T("_ERASE "));
          return TRUE;      // Remove message
        }
      }
    } // if
  } // if
  return FALSE;       // Continue
}

Это работающий код.
По поводу второго вопроса: AcDbDatabase::currentSpaceId() возвращает AcDbObjectId для активного пространства (ACDB_MODEL_SPACE или что-то другое) - сравниваешь и узнаешь (упрощенно без обработки ошибок):

static bool IsModelSpace(void)
{
  AcDbObjectId idCurrent = acdbCurDwg()->currentSpaceId();
  AcDbBlockTablePointer pBT(acdbCurDwg(),AcDb::kForRead);
  if (pBT.openStatus() == Acad::eOk) {
    AcDbObjectId idModel;
    if (pBT->getAt(ACDB_MODEL_SPACE,idModel) == Acad::eOk) {
      if (idModel == idCurrent) return true;
    }
  }
  return false;
}

Re: Вопрос по acedSSGetFirst

БОЛЬШОЕ ВАМ СПАСИБО!!! ВЫ подсказали как раз то, что мне нужно. Еще раз СПАСИБО!!!

Re: Вопрос по acedSSGetFirst

По ходу экспериментов выходит, что все-таки придется заблокировать клавишу. Подскажите пожалуйста как это реализовать?

Re: Вопрос по acedSSGetFirst

Ну вообще-то возвращать из filterProc значение TRUE. Но наверное придется не только для WM_KEYDOWN, но и для WM_KEYUP - я не проверял.

Re: Вопрос по acedSSGetFirst

СПАСИБО за помощь! Все отлично работает:)