Category Archives: Software

Cross-Thread invoke helper

Probabil cei care programeaza in .NET forms de ceva vreme se lovesc frecvent de problema invocarii unei metode a unui control, dintr-un thread altul decat cel care este owner-ul controlului. Nu intru in detaliile problemei, care coboara destul de jos la cozi de mesaje per thread, handle-uri windows si altele;

Solutia cel mai des intalnita este: se face un delegate cu semnatura metodei de invocat, se verifica daca este contextul threadului corect cu Control.IsInvokeRequired, si daca nu, atunci se apeleaza metoda prin Control.Invoke, cu delegate-ul definit anterior.

In timp devine “obositor” si mai ales la proiecte mari, definitia cate unui delegate pentru fiecare metoda posibila. O solutie la “oboseala” ar putea fi urmatoarea (mai putin cateva try – catch blocks 😉 :

class CrossThreadHelper
{
    private delegate Object CallMethodProxyDelegate(Control ctrl, String strMethod, object[] arguments);

    private static Object CallMethodProxy(Control ctrl, String strMethod, object[] arguments)
    {
        MethodInfo method;
        method = ctrl.GetType().GetMethod(strMethod);
        return method.Invoke(arguments);
    }

    public static Object CallMethod(Control ctrl, String strMethod, params object[] arguments)
    {
        if(ctrl.InvokeRequired)
        {
             Delegate = new CallMethodProxyDelegate(CallMethodProxy);
             Object[] newArgs = new Object[3];
             newArgs[0] = ctrl;
             newArgs[1] = strMethod;
             newArgs[2] = arguments;
             return ctrl.Invoke(del, newArgs);
         }

         return CallMethodProxy(ctrl, strMethod, arguments);
    }

}

Exemplu:

CrossThreadHelper.CallMethod(this.frmProgress, “Close”);

 

O metoda pentru a intercepta apelurile COM.

Cateodata e util (povestea lui “de ce” e prea lunga) sa se intercepteze apelurile care se fac intr-un server COM DLL  3rd party. Una dintre posibilele solutii la aceasta problema urmeaza:

(voi scurta detaliile,  presupunand ca oricum daca nu stiti cum sa ajungeti aici, nu v-ati pus problema interceptiei COM anyway ).

1. New project, ATL project.

2. Cu ajutorul object viewerului, inspectati DLL-ul care va intereseaza; veti avea in COM Object Viewer IDL-ul serverului vizat. Copiati-l in proiectul nou.

3. Adaugati un obiect COM (simple COM object), care va implementa interfata/interfetele care va intereseaza.

4. Nu uitati sa actualizati resursele registry (rgs) cu UUID-urile din IDL-ul “pastat”.

5. Metodele FinalConstruct si Final Release din obiectul COM adaugat la punctul 3, ar putea arata asa:

(IMyInterface este interfata care se intercepteaza):

HMODULE m_hOriginalModule; // handle la DLL-ul interceptat
CComPtr m_pOriginalInterface; // ptr la interfata originala

 HRESULT FinalConstruct()
 {

// incarca modulul de interceptat
  m_hOriginalModule = CoLoadLibrary(_T(““), FALSE);
  if(m_hOriginalModule != NULL)
  {

// obtine ptr la IClassFactory
   CComPtr pFactory;
   DllGetClassObjectFn fn = (DllGetClassObjectFn)GetProcAddress(m_hOriginalModule, “DllGetClassObject”);
   if(fn != NULL)
   {

// apel DllGetClassObject in modulul interceptat, pentru a obtine IClassFactory-ul 
    HRESULT hRes = fn(CLSID_MyInterfaceCoClass, IID_IClassFactory, (LPVOID *)&pFactory);  
    if(FAILED(hRes))
    {
     return hRes;
    }

 // apel CreateInstance pentru a obtine o interfata in implementarea originala
    hRes = pFactory->CreateInstance(NULL, IID_IMyInterface, (LPVOID *)&m_pOriginalInterface);
    if(FAILED(hRes))
    {
     return hRes;
    }
   }  
  }
  
  return S_OK;
 }

 void FinalRelease()
 {
  if(m_hOriginalModule != NULL)
  {

// release inainte de FreeLibrary
   m_pOriginalInterface.Release();
   CoFreeLibrary(m_hOriginalModule);
  }
 }

// se poate rescrie functia InternalQueryInterface pentru a loga ce apeluri QI se fac  

static HRESULT InternalQueryInterface(void *pThis, const ATL::_ATL_INTMAP_ENTRY *pEntries, const IID &iid, void **ppvObject)
 {
  // log the thing
  HRESULT hRes = CComObjectRootBase::InternalQueryInterface(pThis, pEntries, iid, ppvObject);
  CLog log;
  log.Write(“QI: {%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x} returned=%08x\r\n”,
   iid.Data1, iid.Data2, iid.Data3, iid.Data4[0], iid.Data4[1], iid.Data4[2], iid.Data4[3],
   iid.Data4[4], iid.Data4[5], iid.Data4[6], iid.Data4[7], hRes);
  return hRes;
 }
// se pot rescrie metodele din IMyInterface si loga parametrii

HRESULT MyMethod1(…. )
{
    // log params
    HRESULT hRes = m_pOriginalInterface->MyMethod1(…);
    // log hRes, out params
    return hRes;

}

… etc.