hl.txt 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. libkchl - C++ API for shorter code doing MAPI
  2. == What is encompassed by KCHL ==
  3. * <kopano/ECRestriction.h>: ECRestriction, ECAndRestriction,
  4. ECPropertyRestriction, etc.: classes for construct restrictions, and to later
  5. export to a bare MAPI SRestriction.
  6. * <kopano/memory.hpp>: memory_ptr<T>: smart pointer class like unique_ptr describing ownership of an
  7. object whose lifetime is bound by MAPIAllocateBuffer/MAPIFreeBuffer.
  8. * <kopano/memory.hpp>: object_ptr<T>: smart pointer class like unique_ptr(!)
  9. holding an object (like shared_ptr(!)) whose lifetime is bound by
  10. IUnknown::AddRef/Release.
  11. * <kopano/tie.hpp>: unique_tie: glue function to bind a std::unique_ptr<T> to a
  12. function taking T*.
  13. * <kopano/automapi.hpp>: AutoMAPI: Wrapepr class to invoke
  14. MAPIUninitialize at destruction time.
  15. * <kopano/hl.hpp>: K* classes: Exception-based wrapper classes for MAPI
  16. object pointers.
  17. == ECRestriction ==
  18. Classic MAPI approach:
  19. SRestriction r, tmp[2];
  20. r.rt = RES_OR;
  21. r.res.resOr.cRes = 2;
  22. r.res.resOr.lpRes = tmp;
  23. tmp[0].rt = RES_EXIST;
  24. tmp[0].res.resExist.ulPropTag = PR_EC_IMAP_ID;
  25. tmp[1].rt = RES_PROPERTY;
  26. tmp[1].res.resProperty.relop = RELOP_EQ;
  27. tmp[1].res.resProperty.ulPropTag = PR_EC_IMAP_ID;
  28. tmp[1].res.resProperty.lpProp = &pv;
  29. With ECRestriction classes:
  30. ECOrRestriction r(
  31. ECExistRestriction(PR_EC_IMAP_ID) +
  32. ECRestrictionProperty(RELOP_EQ, PR_EC_IMAP_ID, &pv,
  33. ECRestriction::Shallow));
  34. KC < 8.3 allowed for the last argument to be optional; this has been abolished
  35. so that there is always a mindful mode selection by the developer (and review
  36. thereof).
  37. == memory_ptr ==
  38. KCHL::memory_ptr works much like a std::unique_ptr made to use MAPIFreeBuffer,
  39. but has a number of extensions for source-code compatibility such as implicit
  40. conversions. The use of unique_ptr/memory_ptr allows for shorter
  41. code.
  42. Traditional:
  43. foo *obj;
  44. MAPIAllocateBuffer(sizeof(*obj), &obj);
  45. memset(obj, 0, sizeof(obj));
  46. ...
  47. exit:
  48. MAPIFreeBuffer(obj);
  49. With unique_ptr:
  50. //struct mapideleter { void operator()(void *x) { MAPIFreeBuffer(x); }}
  51. std::unique_ptr<foo, mapideleter> obj;
  52. MAPIAllocateBuffer(sizeof(*obj), &unique_tie(obj));
  53. memset(obj.get(), 0, sizeof(foo));
  54. With memory_ptr:
  55. memory_ptr<foo> obj;
  56. MAPIAllocateBuffer(sizeof(*obj), &~obj);
  57. memset(obj, 0, sizeof(foo));
  58. Since one cannot know in advance whether such a function will write to obj or
  59. leave it untouched, the & operator had been defined to always free obj first to
  60. ensure there will be no leaks. As memory_ptr was used in more and more places,
  61. it turned out that in some instances, such freeing is undesired (e.g. near
  62. GetNameFromIDs). As a consequence, freeing has been made explicit using the
  63. ~ operator, not-freeing is expressed with the + operator, and not using either
  64. of ~ or + leads to a compile error, to catch unmindful uses of &.
  65. == object_ptr ==
  66. The class implicitly invokes the object's Release function when the
  67. object_ptr goes out of scope. This allows for shorter code.
  68. Classic MAPI approach:
  69. {
  70. IMessage *msg;
  71. int ret = store->CreateMessage(&msg);
  72. if (ret != hrSuccess)
  73. goto exit;
  74. ret = msg->foo();
  75. if (ret != hrSuccess)
  76. goto exit;
  77. exit:
  78. if (msg != nullptr)
  79. msg->Release();
  80. return ret;
  81. }
  82. Modern approach:
  83. {
  84. object_ptr<IMessage> msg;
  85. int ret = store->CreateMessage(&~msg);
  86. if (ret != hrSuccess)
  87. return hr;
  88. ret = msg->foo();
  89. if (ret != hrSuccess)
  90. return ret;
  91. }
  92. == unique_tie ==
  93. Instead of writing
  94. std::unique_ptr<Foo> g;
  95. Foo *f;
  96. somefunction(&f);
  97. g.reset(f);
  98. the unique_tie function makes it possible to do without the explicit temporary
  99. 'f':
  100. std::unique_ptr<Foo> g;
  101. somefunction(&unique_tie(g));
  102. == Exception-based wrappers ==
  103. A group of experimental classes which always return objects while
  104. error codes are signalled via exceptions (rather than return codes).
  105. This makes it possible to write code which is so terse that I am not
  106. convinced yet using these classes everywhere is a good idea (it makes
  107. it harder to identify which function exactly failed).
  108. Traditional:
  109. //IMsgStore *store;
  110. IMAPIFolder *rcv;
  111. IMessage *msg;
  112. IUnknown *entry;
  113. int ret = store->GetReceiveFolder(&rcv);
  114. if (ret != hrSuccess)
  115. goto exit;
  116. ret = store->OpenEntry(rcv, nullptr, MAPI_MODIFY, &entry);
  117. if (ret != hrSuccess)
  118. goto exit;
  119. ret = entry->CreateMessage(nullptr, 0, &msg);
  120. if (ret != hrSuccess)
  121. goto exit;
  122. msg->foo(); //...
  123. exit:
  124. if (ret != hrSuccess)
  125. fprintf(stderr, "%s\n", GetMAPIErrorDescription(ret));
  126. if (rcv != nullptr)
  127. rcv->Release();
  128. New:
  129. //KStore store;
  130. try {
  131. auto new_msg = store
  132. .open_entry(store.get_receive_folder(), nullptr, MAPI_MODIFY)
  133. .create_message(nullptr, 0)
  134. new_msg->foo(); //...
  135. } catch (KMAPIError &e) {
  136. fprintf(stderr, "%s\n", e.what());
  137. }
  138. This group of classes is the only one that require Makefile.am to be augmented
  139. with libkchl.la / -lkchl.