{"id":3163,"date":"2013-09-23T07:00:00","date_gmt":"2013-09-23T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/09\/23\/providing-a-custom-autocomplete-source-for-an-edit-control\/"},"modified":"2013-09-23T07:00:00","modified_gmt":"2013-09-23T07:00:00","slug":"providing-a-custom-autocomplete-source-for-an-edit-control","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130923-00\/?p=3163","title":{"rendered":"Providing a custom autocomplete source for an edit control"},"content":{"rendered":"<p>\nToday&#8217;s Little Program shows a custom source for autocomplete.\nIt&#8217;s nothing exciting, but at least&#8217;s it&#8217;s something\nyou can use as a starting point for your own customizations.\n<\/p>\n<p>\nWe start with a dialog template,\nwhose edit control will be the target of a custom autocomplete.\n<\/p>\n<pre>\n\/\/ scratch.rc\n#include &lt;windows.h&gt;\n1 DIALOGEX DISCARDABLE  32, 32, 200, 56\nSTYLE DS_MODALFRAME |  WS_POPUP |\n      WS_VISIBLE | WS_CAPTION | WS_SYSMENU\nCAPTION \"Sample\"\nFONT 8, \"MS Shell Dlg\"\nBEGIN\n LTEXT \"What is your favorite Seattle restaurant?\",-1,7,8,184,10\n EDITTEXT 100,7,18,184,14\n PUSHBUTTON \"OK\",IDOK,146,38,50,14\nEND\n<\/pre>\n<p>\nJust for fun,\nI wrote the program in ATL.\nInstead of complaining that my code is hard\nto understand because I didn&#8217;t use an application framework,\npeople can\nnow complain that my code is hard to understand\nbecause I used the <i>wrong<\/i> application framework.\n<\/p>\n<pre>\n\/\/ scratch.cpp\n#include &lt;windows.h&gt;\n#include &lt;ole2.h&gt;\n#include &lt;windowsx.h&gt;\n#include &lt;shlobj.h&gt;\n#include &lt;atlbase.h&gt;\n#include &lt;atlcom.h&gt;\nCComModule _Module;\n<\/pre>\n<p>\nTo save some typing, I define a shorthand name for\n&#8220;the predefined ATL object for enumerating strings via\n<code>IEnum&shy;String<\/code>.&#8221;\n<\/p>\n<pre>\ntypedef CComEnum&lt;IEnumString,\n                 &amp;IID_IEnumString,\n                 LPOLESTR,\n                 _Copy&lt;LPOLESTR&gt; &gt; CComEnumString;\n<\/pre>\n<p>\nTo initialize the dialog,\nwe do the following things:\n<\/p>\n<ul>\n<li>Create a predefined ATL object for implementing\n    <code>IEnum&shy;String<\/code>.<\/p>\n<li>Tell the predefined ATL object to enumerate a hard-coded\n    list of restaurant suggestions.<\/p>\n<li>Create an autocomplete object.\n<li>Connect the autocomplete object to the\n    edit control in the dialog and to\n    the <code>IEnum&shy;String<\/code>\n    object.<\/p>\n<li>Just for fun, change some of the default settings\n    for autocomplete.\n<\/ul>\n<pre>\nLPOLESTR c_rgpszSuggestions[] = {\n    L\"Brave Horse Tavern\",\n    L\"Cuoco\",\n    L\"Dahlia Bakery\",\n    L\"Dahlia Lounge\",\n    L\"Etta's\",\n    L\"Lola\",\n    L\"Palace Kitchen\",\n    L\"Seatown\",\n    L\"Serious Pie\",\n    L\"Ting Momo\",\n};\nvoid OnInitDialog(HWND hdlg)\n{\n  CComPtr&lt;IAutoComplete2&gt; spac;\n  CComObject&lt;CComEnumString&gt; *pes;\n  HRESULT hr = CComObject&lt;CComEnumString&gt;::CreateInstance(&amp;pes);\n  CComPtr&lt;IEnumString&gt; spes(pes);\n  if (SUCCEEDED(hr) &amp;&amp;\n      SUCCEEDED(pes-&gt;Init(&amp;c_rgpszSuggestions[0],\n                          &amp;c_rgpszSuggestions[ARRAYSIZE(c_rgpszSuggestions)],\n                          NULL)) &amp;&amp;\n      SUCCEEDED(spac.CoCreateInstance(CLSID_AutoComplete)) &amp;&amp;\n      SUCCEEDED(spac-&gt;Init(GetDlgItem(hdlg, 100), spes, NULL, NULL)) &amp;&amp;\n      SUCCEEDED(spac-&gt;SetOptions(ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST))) {\n  }\n}\n<\/pre>\n<p>\nThe rest is just boilerplate.\n<\/p>\n<pre>\nINT_PTR CALLBACK DlgProc(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n  switch (uMsg) {\n  case WM_INITDIALOG:\n    OnInitDialog(hdlg);\n    return TRUE;\n  case WM_COMMAND:\n    switch (GET_WM_COMMAND_ID(wParam, lParam)) {\n    case IDOK:\n      EndDialog(hdlg, 0);\n      break;\n    }\n  }\n  return FALSE;\n}\nint WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,\n                   LPSTR lpCmdLine, int nShowCmd)\n{\n  if (SUCCEEDED(CoInitialize(NULL))) {\n    DialogBox(hinst, MAKEINTRESOURCE(1), NULL, DlgProc);\n    CoUninitialize();\n  }\n  return 0;\n}\n<\/pre>\n<p>\nNow, one of the reasons for using a framework is that it hides\na lot of details from you.\nBut if you are trying to understand how to port code from one\nframework to another, those hidden details become an obstacle\nto progress rather than a convenience.\nYou may port the overall structure from one framework to another,\nbut if the two frameworks behave differently in the hidden parts,\nyour conversion was incorrect.\n<\/p>\n<p>\nFor example, one subtlety hidden in the above code\nis how the strings are returned by the\n<code>IEnum&shy;String::Next<\/code>\nmethod.\nRecall that\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms686638.aspx\">\nCOM interfaces use the task allocator<\/a>\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa366533.aspx\">\nto pass memory between objects<\/a>,\nso the string returned by\n<code>IEnum&shy;String::Next<\/code>\nis allocated by <code>Co&shy;Task&shy;Mem&shy;Alloc<\/code>,\nwith the expectation that the caller will call\n<code>Co&shy;Task&shy;Mem&shy;Free<\/code> to free it.\n<\/p>\n<p>\nUnless you happen to be familiar with this detail of ATL,\nyou would never have guessed it from the code above.\nYou might have thought that the enumerator handed out\nthe literal string pointers used to initialize it,\nand then you&#8217;ll start wondering why your program crashes\nat random times (because you introduced a heap corruption bug).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today&#8217;s Little Program shows a custom source for autocomplete. It&#8217;s nothing exciting, but at least&#8217;s it&#8217;s something you can use as a starting point for your own customizations. We start with a dialog template, whose edit control will be the target of a custom autocomplete. \/\/ scratch.rc #include &lt;windows.h&gt; 1 DIALOGEX DISCARDABLE 32, 32, 200, [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-3163","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Today&#8217;s Little Program shows a custom source for autocomplete. It&#8217;s nothing exciting, but at least&#8217;s it&#8217;s something you can use as a starting point for your own customizations. We start with a dialog template, whose edit control will be the target of a custom autocomplete. \/\/ scratch.rc #include &lt;windows.h&gt; 1 DIALOGEX DISCARDABLE 32, 32, 200, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3163","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=3163"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3163\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=3163"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=3163"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=3163"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}