Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Formatowanie wiadomości
Konnekt | Forum > Developerzy > Tworzenie wtyczek
bulanh
Jak formatować tekst wychodzący wiem (<b></b> i te sprawy). Ale jak wygląda sprawa z formatowaniem tekstu przychodzącego? Gdzie mogę o tym coś wyczytać (jeśli jest w SDK to w którym miejscu)? Całość może (a nawet powinna) opierać się na kIEView. Tylko nie mogłem nigdzie znaleźć ani źródeł, ani żadnego opisu do tej wtyczki (prawdopodobnie nie mają dostępu do niej osoby trzecie smile.gif).

Z góry dzięki za odpowiedzi
Adam A.

PS. Jak się ładnie poprosi to jest możliwość dostania chociarz kawałka kodu wtyczki kIEView odpowiedzialnego za formatowanie tekstu?
gilek
wiadomości przychodzące możesz formatować za pomocą css'ów. chyba o to Ci chodziło.
bulanh
Niespecjalnie, chyba że można formatować słowa wybiórczo (np. co drugie)
hao
Nie wiem czy o to chodzi, ale w API Konnekta możesz przechwycić dowolną wiadomość, zmodyfikować ją i wstawić z powrotem do kolejki... Każda wiadomość może być formatowana przy użyciu HTML, zarówno przy- jak i wychodzące... Ważne jest tylko żeby wynikowy HTML był hiperpoprawny...
Olórin
QUOTE
Ważne jest tylko żeby wynikowy HTML był hiperpoprawny...

Dokładniej - aby przechodził bez problemu przez parser XML smile.gif
bulanh
hmmm.... W takiem razie jeszcze raz przeglądnę helpa smile.gif Dzięki za informację.
bulanh
Strasznie zagmatwane to API. Im dłużej czytam pomoc tym mnie wiem co z czym, kiedy i dlaczego. Dlatego też pozwolę sobie zadać kilka trywialnych pytań o podstawy (od razu zaznaczam, że pomoc czytałem).

1. Wykrycie momentu wysyłania wiadomości (do jakiejkolwiek sieci)
a ) Próbowałem poprzez IM_UIACTION (w IMessageProc) i IMIA_MSG_SEND (w mojej funkcji) - bez rezultatów
b ) Próbowałem także z IM_MSG_SEND - bez rezultatów
Dodam, że do testów używam sieci gg, w związku z tym poszukałem bardziej tam niż tu smile.gif. Jedyne jednak co zauważyłem związane zwysyłaniem wiadomości to potwierdzenie, co w żaden sposób nie jest mi potrzebne (tak mi się przynajmniej wydaje). A może da się to zrobić bardziej ogólnie, niezależnie od sieci?

2. Kolejki wiadomości
W helpie wyczytałem sobie, że do kolejki wiadomości dodaje się poprzez ICMessage, a później się je odbiera z tamtąd poprzez IM_MSG_RECV. Możecie mi wytłumaczyć czemu żeby odebrać wiadomość z sieci gg musiałem rejestrować sobie protokół gg i użyć IM_GG_EVENT? Czy wiadomości z tej sieci omijają kolejkę?

Już nic z tego nie wiem.

Z góry dzięki za pomoc
Adam.
Olórin
Do sposobu 2 w IM_PLUG_TYPE (czy cos takiego) musisz dodac wartość IMT_ALLMESSAGES.
hao
IM_UIACTION służy do obsługi "akcji" użytkownika, czyli różnych kontrolek i menusów w programie...

Do złapania wiadomości służy właśnie IM_MSG_RCV, tyle że jak napisał Olórin musisz dodać odpowiednią flagę w typie wtyczki...

Jeżeli chcesz tylko "podejrzeć" wysyłane wiadomości, obsługujesz je w IM_MSG_RCV (wysyłane wiadomości mają flagę MF_SEND) i zwracasz 0.

Jeżeli jednak chcesz je modyfikować operacja jest trochę bardziej skomplikowana...

1) Możesz po prostu podmienić tekst jeżeli nie jest dłuższy niż ten aktualnie znajdujący się w buforach...
2) Możesz podmienić bufory z tekstem... Są jednak dwa istotne problemy:
a) nowe bufory nie mogą zostać zwolnione dopóki procedura dodawania wiadomości do kolejki nie zostanie zakończona
cool.gif jeżeli któraś z wtyczek jest wrażliwa na zmianę buforów może to doprowadzić do krytyków (np. gdy alokuje pamięć dla tekstu wiadomości, dodaje ją do kolejki i używa wskaźnika ze struktury z wiadomością do zwolnienia tej pamięci)... O ile mi wiadomo moje wtyczki są na to odporne...
3) Możesz stworzyć nową wiadomość i dodać ją do kolejki (przez IMC_NEWMESSAGE). W IM_MSG_RCV trzeba zwrócić IM_MSG_delete żeby pierwotna wiadomość została usunięta z kolejki...
bulanh
Dzięki. Chyba rozwialiście moje wątpliwości, ale tak dla pewności:

CODE


int MessageEvent(cMessage *msg)
{
cMessage NewMsg;
// Tutaj przepisuje wszystkie parametry msg oprócz body
NewMsg.body = NowaTresc;
ICMessage(IMC_NEWMESSAGE, (int)&NewMsg);
return IM_MSG_delete;
}

__stdcall IMessageProc(sIMessage_base * msgBase) {
sIMessage_2params * msg = (msgBase->s_size>=sizeof(sIMessage_2params))?static_cast<sIMessage_2params*>(msgBase):0;
switch (msgBase->id)
{
[...]
case IM_MSG_RCV:   return MessageEvent((cMessage*)msg->p1);
}
[...]
}


Coś w tym stylu?

// DOPISANE

Stwierdzam, że ten pomysł jest zły (program się zapętla, w zasadzie nic dziwnego). W takim razie gdzie mam wstawic funkcję MessageEvent?
hao
Dodawaj do nowej wiadomości flagę lub parametr (poszukaj "ext" w SDK) i sprawdzaj przy wywolywaniu RCV... Ustrzeżesz się przed rekurencją...

Poza tym zakładając że RCV zawsze wywoływane są z głównego wątku wątku możesz zastosować coś takiego:

CODE

int MessageEvent(cMessage *msg)
{
 static bool occupied = false;
 if (occupied) return 0;
 occupied = true;
 cMessage NewMsg;
 // Tutaj przepisuje wszystkie parametry msg oprócz body
 NewMsg.body = NowaTresc;
 ICMessage(IMC_NEWMESSAGE, (int)&NewMsg);
 occupied = false;
 return IM_MSG_delete;
}
Olórin
A może modyfikować zawartość body?
skolima
CODE
NewMsg.body = NowaTresc;
;>
bulanh
W związku z tym, że pojawił się jak bug w kodzie (nie związany z Konnektem), postanowiłem przerwać pracę nad tamtą częścią i wrócić do pewnego problemu (związanego z Konnektem). Otóż przychodzą do mnie 2 wiadomości (zawsze) tj. ta która ktoś do mnie wyśle i ta którą ja wstawię do kolejki. Tak wygląda cała funkcja podpięta do IM_MSG_RCV:

CODE

int MessageEvent(cMessage* msg)
{
if(msg->type == MT_MESSAGE)
{
 static bool occupied = false;
 if (occupied) return 0;
 occupied = true;

 sMESSAGESELECT ms;                                                 //
 ms.id = ICMessage(IMC_MESSAGEQUEUE, (int)msg);     // <- z tym, czy bez tego
 int a = ICMessage(IMC_MESSAGEREMOVE, (int)&ms);    // i tak nie działa

 cMessage NewMsg;
 NewMsg.action = msg->action;
 NewMsg.ext = msg->ext;
 NewMsg.flag = msg->flag | MF_HTML;
 NewMsg.fromUid = msg->fromUid;
 NewMsg.net = msg->net;
 NewMsg.notify = msg->notify;
 NewMsg.s_size = msg->s_size;
 NewMsg.time = msg->time;
 NewMsg.toUid = msg->toUid;
 NewMsg.type = msg->type;
 NewMsg.body = Highlight(msg->body);
 sMESSAGESELECT nms;
 nms.id = ICMessage(IMC_NEWMESSAGE, (int)&NewMsg);
 if (nms.id != 0) ICMessage(IMC_MESSAGEQUEUE, (int)&nms);

 occupied = false;

 return IM_MSG_delete;
} else return 0;
}


Dodam, że ms.id zawsze dostaje id = 0, tak samo zmienna pomocnicza a. Dla mnie to wygląda tak, że tych wiadomości nie ma w kolejce. W oknie rozmowy najpierw wyświetla się wiadomość, którą wstawię do kolejki, a zaraz pod nią ta którą napisał ktoś do mnie. Tego problemu nie ma z wiadomościami wychodzącymi. Jak to naprawić?
bulanh
Wydaję mi się, że wiem w czym leży problem. Uważam, że wtyczka kIEview wcześniej dobiera się do wiadomości niż moja. Próbowałem to zmienić zwracając IM_PLUG_PRIORITY 224 (czyli PLUGP_HIGHEST). Nic to nie dało. Co prawda jak sobie zobaczę w info moja wtyczka jest nad kIEview, jednak (wydaję mi się, że) dostaje później wiadomość.

Sprawdziłem to w ten sposób:
- na początku mojej nowej, programowo wygenerowanej wiadomości wstawiłem '^',
- dodałem gdzieś <font color="#FF0000">coś</font> (tak dla przykładu),
- nie ustawiłem flagi MF_HTML (kIEview powinien to zrobić, ze względu na '^')

I oto co się stało.

Jeśli ja wysyłam wiadomość to:
- u mnie w okienku pokazała się ta wiadomość, która była w polu do wpisywania tekstu,
- u klienta pokazał się przerobiony tekst z daszkiem (bez kolorków).

Jeśli ja odbieram wiadomość to:
- pokazuje się najpierw przerobiony tekst z daszkiem (bez kolorków)
- zaraz pod spodem pokazuje się oryginalna wiadomość (nie przerobiona i bez daszka)

Proszę powiedzcie mi co robie źlę, bo już nie mam pomysłów.

Pozdrowienia
Adam.
hao
QUOTE
Sprawdziłem to w ten sposób:
- na początku mojej nowej, programowo wygenerowanej wiadomości wstawiłem '^',
- dodałem gdzieś <font color="#FF0000">coś</font> (tak dla przykładu),
- nie ustawiłem flagi MF_HTML (kIEview powinien to zrobić, ze względu na '^')

"Daszki" rozpoznaje interfejs zanim w ogóle wstawi wiadomość do kolejki... kIEview nie ma z nimi nic wspólnego...
Dopóki nie podmienisz wskaźników tekstu bezpośrednio w strukturze cMessage w oknie rozmowy zawsze pojawi się to co wpisałeś do kontrolki wpisywania...

QUOTE
Jeśli ja odbieram wiadomość to:
- pokazuje się najpierw przerobiony tekst z daszkiem (bez kolorków)
- zaraz pod spodem pokazuje się oryginalna wiadomość (nie przerobiona i bez daszka)


Jeżeli używasz kodu który wcześniej zapostowałeś to
CODE
ms.id = ICMessage(IMC_MESSAGEQUEUE, (int)msg);

w ogóle nie ma prawa działać... IMC_MESSAGEQUEUE przyjmuje jako parametr wyłącznie sMESSAGESELECT* i służy do rozsyłania wiadomości czekających w kolejce.

Do tego jako że obsługujesz wiadomość w RCV - wiadomość jeszcze na dobre nie znajduje się w kolejce, więc IMC_MESSAGEREMOVE też nie zadziała jak możnaby się po nim spodziewać...

Samo zwrócenie IM_MSG_delete powinno ją na dobre usunąć...

Ogólnie myślę że łatwiej będzie jednak podmieniać bufory bezpośrednio w wiadomościach, bez usuwania ich z kolejki.
bulanh
QUOTE(hao @ 19.06.2005 - 20:38)
Ogólnie myślę że łatwiej będzie jednak podmieniać bufory bezpośrednio w wiadomościach, bez usuwania ich z kolejki.


Tak, też zrobiłem i działa jak powinno. Całe szczęście - za niedługo koniec smile.gif
hao
Tylko tak dla pewności, pokaż kod którym podmieniasz te bufory :]
bulanh
Proszę bardzo:
CODE

int MessageEvent(cMessage* msg)
{
if(msg->type == MT_MESSAGE)
{
 NET_TYPE = msg->net;
 FROM_UID = msg->fromUid;

 if (msg->flag == MF_SEND)
 {
  msg->flag = msg->flag | MF_HTML;
  msg->body = Highlight(msg->body);
  return 0;
 } else
 {
  msg->body = Highlight(msg->body);
  msg->flag = msg->flag | MF_HTML;
  return IM_MSG_ok;
 }
} else return 0;
}

Funkcja Highlight zwraca char*
hao
A jak wygląda tworzenie i zwalnianie tego char* który ta funkcja zwraca? Głównie o to mi chodzi...
bulanh
Tak:
CODE

char* Highlight(char* msg)
{
 int start, end;
 std::string s_msg = msg;
 if (!FindTags(s_msg, start, end)) return msg;
 int w_start = start + strlen("[delphi]");
 std::string *formated = ColorSyntax(s_msg.substr(w_start, end-w_start), DELPHI);
 formated = ReplaceEnters(*formated);
 std::string complFormated = "<font style=\"font-weight: normal;\">";
 complFormated += *formated;
 complFormated += "</font>";
 delete formated;
 s_msg.replace(start, end+strlen("[/delphi]")-start, complFormated);
 char* ret_str = new char[s_msg.length()];
 strcpy(ret_str, s_msg.c_str());
 return ret_str;
}


Jak widać nie zwalniam tego chara*, żeby się nic nie posypało dalej
skolima
i siejesz w pamięci :/
hao
Skolima, bądź bardziej konsktruktywny smile.gif

Bulanh, musisz gdzieś zwalniać te bufory bo w przeciwnym razie tworzysz dość spore wycieki pamięci...
Najprostszą metodą, aczkolwiek dosyć ryzykowną, jest jeden statyczny bufor. Ryzykowną, bo jeżeli któraś z wtyczek (jak na przykład niedoszła Twoja) wstawi w RCV nową wiadomość do kolejki bufor, który jeszcze nie przestał być używany będzie ponownie nadpisany...

Dlatego proponuję prosty string pooling...

CODE

/*Gdzieś globalnie:*/
const unsigned int strPoolSize = 20;
std::string strPool [poolSize];
unsigned int strPoolPos = 0;

/*Zamiast:
char* ret_str = new char[s_msg.length()];
strcpy(ret_str, s_msg.c_str());
return ret_str;*/

const std::string& retStr = strPool[(strPoolPos++) % strPoolSize];
retStr = s_msg;
return (char*) retStr.c_str();


Nie jestem w tej chwili pewien jak MSVS zareaguje na taką tablicę std::string, jeżeli mu się nie spodoba to oczywiście można użyć chociażby std::vector i na samym początku ustawić mu na sztywno rozmiar...


Dobrze że zapytałem wink.gif
bulanh
Dlatego powinien być API dla Delphi smile.gif. Skoro działa i nie ma zagrożeń to wszystko od strony konnekta jest już zrobione. Dzięki za pomoc.
hao
Zakładając tylko że zmieniłeś sposób tworzenia nowych buforów to nie ma za co wink.gif
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2012 Invision Power Services, Inc.