Help me understand this C code - c

INT GetTree (HWND hWnd, HTREEITEM hItem, HKEY *pRoot, TCHAR *pszKey,
INT nMax) {
TV_ITEM tvi;
TCHAR szName[256];
HTREEITEM hParent;
HWND hwndTV = GetDlgItem (hWnd, ID_TREEV);
memset (&tvi, 0, sizeof (tvi));
hParent = TreeView_GetParent (hwndTV, hItem);
if (hParent) {
// Get the parent of the parent of the...
GetTree (hWnd, hParent, pRoot, pszKey, nMax);
// Get the name of the item.
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szName;
tvi.cchTextMax = dim(szName);
TreeView_GetItem (hwndTV, &tvi); //send the TVM_GETITEM message?
lstrcat (pszKey, TEXT ("\\"));
lstrcat (pszKey, szName);
} else {
*pszKey = TEXT ('\0');
szName[0] = TEXT ('\0');
// Get the name of the item.
tvi.mask = TVIF_TEXT | TVIF_PARAM;
tvi.hItem = hItem;
tvi.pszText = szName;
tvi.cchTextMax = dim(szName);
if (TreeView_GetItem (hwndTV, &tvi))
//*pRoot = (HTREEITEM)tvi.lParam; //original
hItem = (HTREEITEM)tvi.lParam;
else {
INT rc = GetLastError();
}
}
return 0;
}
The block of code that begins with the comment "Get the name of the item" does not make sense to me. If you are getting the listview item why does the code set the parameters of the item being retrieved? If you already had the values there would be no need to retrieve them.
Secondly near the comment "original" is the original line of code which will compile with a warning under embedded visual c++ 4.0, but if you copy the exact same code into visual studio 2008 it will not compile. Since I did not write any of this code, and am trying to learn, is it possible the original author made a mistake on this line? The *pRoot should point to HKEY type yet he is casting to an HTREEITEM type which should never work since the data types don't match?

The block of code that begins with the comment "Get the name of the item" does not make sense to me. If you are getting the listview item why does the code set the parameters of the item being retrieved, because if you already had the values there would be no need to retrieve them.
After that comment, the first line is to specify to TreeView_GetItem (which, by the way, is actually a SendMessage in disguise) that we want to retrieve the text of the item and the associated lParam. The next line specifies the handle to the item about which we want information.
The following line specifies where the retrieved text must be saved, i.e. in the szName buffer, which has been allocated at the beginning of the function; the last line before the function call specifies the size of such buffer, so to avoid buffer overflows.
I suggest you to have a look at the documentation of TreeView_GetItem and of TVITEM to understand better what's going on.
Secondly near the comment "original" is the original line of code which will compile with a varning under embedded visual c++, but if you copy the exact same code into visual studio 2008 it will not compile. Since I did not write any of this code and am trying to learn is it possible the original author made a mistake on this line, since the *pRoot should point to and HKEY type yet he is casting to an HTREEITEM type which should never work since the data types don't match?
It's not clear what the code is trying to do there; at first glance I'd say that in the lParam associated to each item in the root node of the treeview is stored a handle to a registry key, and the procedure retrieves it in that way. Still, if it was like that, the (HTREEITEM) cast wouldn't make sense at all; probably it was a mistake, forgiven by the compiler because it treated all handles as plain void *; if my hypothesis is correct you should keep the original line, just replacing (HTREEITEM) with (HKEY).

Many times, API calls take in information in a structure, and also return information in the same structure. If you look at the documentation for TreeView_GetItem, it will clearly show how it operates.
As for the second question, are you compiling as C++? What is the error?

The LPTVITEM parameter to the TreeView_GetItem macro is used bi-directionally.
TreeView_GetItem does indeed send the TVM_GETITEM message to the treeview. What's going on here is that the caller fills in a little bit of the struct to say "here's what I have and what I want" and then the treeview will fill in the requested bits.
From the TreeView_GetItem documentation
When the TVM_GETITEM message is sent, the hItem member of the TVITEM or TVITEMEX structure identifies the item to retrieve information about, and the mask member specifies the attributes to retrieve.
For the second part, I think it looks like it was a mistake, based on the names of the variables etc., but you should probably check how the function is used in the rest of the code to make sure.

The first question is pretty simple: you're filling in a few of the items in the structure to tell what data you want, then calling TreeView_GetItem to actually retrieve the specified data. In this case, you're specifying TVIF_TEXT, which says you want the text for the particular item. You also give it a buffer where it's going to put the text (szName), and tell it how long that buffer is (so it won't write past the end of the buffer). When you call TreeView_GetIem, it copies the text for that item into your buffer.
As to your second question: it looks like all that code (both old and new) is somewhat problematic. The general intent seems to be to retrieve the path to the item that was originally passed in, but it seems to do that rather poorly. It starts by recursively walking up the tree to the root. Then it retrieves the text for the root item, but only into the local variable szName -- which it then ignores (does not copy into szKey). It does store the handle to the root item into hItem (this is where it originally wrote to pRoot).
Then, as it returns (walking back "down" the tree), it retrieves the text for each item, and appends those names to szKey (separated by '\'), to form (most of) the path to the item originally passed in. Unfortunately, as it does this, it ignores the nMax that was passed in, so it can (apparently) write past the end of the szKey buffer.

Related

How to get text from a windows task manager task listview [duplicate]

I'm trying to capture data from a SysListView32 class (according to Spy++) from another application. Sending a LVM_GETITEMCOUNT message to this handle always returns the correct number of items. There is a child window which is SysHeader32 which presumably contains header titles.
When I try to send a LVM_GETITEMTEXT message to the target application, it crashes. The relevant code for this message is below:
LPTSTR lpText;
LVITEM* lvItem;
lvItem = new LVITEM;
lvItem->iSubItem = 0;
lvItem->cchTextMax = 255;
lvItem->pszText = lpText;
//SysListViewHandle is the HWND to the SysListView32 'content' window
SendMessage(SysListViewHandle, LVM_GETITEMTEXT, 1, (long)lvItem);
Each 'cell' in the list contains text no more than 50 characters, so the max text size should be fine.
The list structure which I wish to get the data from has 16 columns and a variable number of entries, more than 5, so the wParam should be fine. The styles this list use are WS_CHILDWINDOW, WS_VISIBLE, WS_TABSTOP, WS_HSCROLL, LVS_REPORT with extended styles of WS_EX_LEFT, WS_EX_LTRREADING, WS_EX_RIGHTSCROLLBAR, WS_EX_NOPARENTNOTIFY, WS_EX_CLIENTEDGE, LVS_GRIDLINES and LVS_FULLROWSELECT.
UISpy is able to probe this list and find the actual data within so I presumed it would be a walk in the park to get using messages, but this has proved not the case =/ any assistance would be greatly appreciated.
EDIT: Worth mentioning the error log on crashing is:
Unhandled exception at 0x77582b87 in applicationname.exe: 0xC0000005: Access violation writing location 0x01bc48b0.
Call stack location comctl32.dll
Disassembly:
77582B87 mov dword ptr [esi],1
Your problem is that since the list view exists in another process, the memory you allocate is not valid in that other process. I refer you to an article over at The Code Project which offers a solution.
What's more, you do not appear to have allocated any memory for lpText so it would fail in your own process.

customizing completion of GtkComboBoxText

How can I customize the completion of a GtkComboBoxText with both a "static" aspect and a "dynamic" one? The static aspect is because some entries are known and added to the combo-box-text at construction time with gtk_combo_box_text_append_text. The dynamic aspect is because I also need to complete thru some callback function(s), that is to complete dynamically -after creation of the GtkComboBoxText widget- once several characters has been typed.
My application uses Boehm's GC (except for GTK objects of course) like Guile or SCM or Bigloo are doing. It can be seen as an experimental persistent dynamic-typed programming language implementation with an integrated editor coded on and for Debian/Linux/x86-64 with the system GTK3.21 library, it is coded in C99 (some of which is generated) and is compiled with GCC6.
(I don't care about non-Linux systems, GTK3 libraries older than GTK3.20, GCC compiler older that GCC6)
question details
I'm entering (inputting into the GtkComboBoxText) either a name, or an object-id.
The name is C-identifier-like but starts with a letter and cannot end with an underscore. For example, comment, if, the_GUI, the_system, payload_json, or x1 are valid names (but _a0bcd or foobar_ are invalid names, because they start or end with an underscore). I currently have a big dozen of names, but I could have a few thousands of them. So it would be reasonable to offer a completion once only a single or perhaps two letters has been typed, and completion for names can happen statically because they are not many of them (so I feel reasonable to call gtk_combo_box_append_text for each name).
The object-id starts with an underscore followed by a digit and has exactly 18 alphanumeric (sort-of random) characters. For example, _5Hf0fFKvRVa71ZPM0, _8261sbF1f9ohzu2Iu, _0BV96V94PJIn9si1K are possible object-ids. Actually it is 96 almost random bits (probably only 294 are possible). The object-id plays the role of UUIDs (in the sense that it is assumed to be world-wide unique for distinct objects) but has a C friendly syntax. I currently have a few dozen of objects-ids, but I could have a few hundred of thousands (or maybe a million) of them. But given a prefix of four characters like _6S3 or _22z, I am assuming that only a reasonable number (probably at most a dozen, and surely no more than a thousand) object-ids exist in my application with that prefix. Of course it would be unreasonable to register (statically) a priori all the object ids (the completion has to happen after four characters have been typed, and should happen dynamically).
So I want a completion that works both on names (e.g. typing one letter perhaps followed by another alphanum character should be enough to propose a completion of at most a hundred choices), and on object-ids (typing four characters like _826 should be enough to trigger a completion of probably at most a few dozen choices, perhaps a thousand ones if unlucky).
Hence typing the three keys p a tab would offer completion with a few names like payload_json or payload_vectval etc... and typing the five keys _ 5 H f tab would offer completion with very few object-ids, notably _5Hf0fFKvRVa71ZPM0
sample incomplete code
So far I coded the following:
static GtkWidget *
mom_objectentry (void)
{
GtkWidget *obent = gtk_combo_box_text_new_with_entry ();
gtk_widget_set_size_request (obent, 30, 10);
mo_value_t namsetv = mo_named_objects_set ();
I have Boehm-garbage-collected values, and mo_value_t is a pointer to any of them. Values can be tagged integers, pointers to strings, objects, or tuples or sets of objects. So namesetv now contains the set of named objects (probably less than a few thousand of named objects).
int nbnam = mo_set_size (namsetv);
MOM_ASSERTPRINTF (nbnam > 0, "bad nbnam");
mo_value_t *namarr = mom_gc_alloc (nbnam * sizeof (mo_value_t));
int cntnam = 0;
for (int ix = 0; ix < nbnam; ix++)
{
mo_objref_t curobr = mo_set_nth (namsetv, ix);
mo_value_t curnamv = mo_objref_namev (curobr);
if (mo_dyncast_string (curnamv))
namarr[cntnam++] = curnamv;
}
qsort (namarr, cntnam, sizeof (mo_value_t), mom_obname_cmp);
for (int ix = 0; ix < cntnam; ix++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (obent),
mo_string_cstr (namarr[ix]));
at this point I have sorted all the (few thousands at most) names and added "statically" them using gtk_combo_box_text_append_text.
GtkWidget *combtextent = gtk_bin_get_child (GTK_BIN (obent));
MOM_ASSERTPRINTF (GTK_IS_ENTRY (combtextent), "bad combtextent");
MOM_ASSERTPRINTF (gtk_entry_get_completion (GTK_ENTRY (combtextent)) ==
NULL, "got completion in combtextent");
I noticed with a bit of surprise that gtk_entry_get_completion (GTK_ENTRY (combtextent)) is null.
But I am stuck here. I am thinking of:
Having some mom_set_complete_objectid(const char*prefix) which given a prefix like "_47n" of at least four characters would return a garbage collected mo_value_t representing the set of objects with that prefix. This is very easy to code for me, and is nearly done.
Make my own local GtkEntryCompletion* mycompl = ..., which would complete like I want. Then I would put it in the text entry combtextent of my gtk-combo-box-text using gtk_entry_set_completion(GTK_ENTRY(combtextent), mycompl);
Should it use the entries added with gtk_combo_box_text_append_text for the "static" name completion role? How should I dynamically complete using the dynamic set value returned from my mom_set_complete_objectid; given some object-pointer obr and some char bufid[20]; I am easily and quickly able to fill it with the object-id of that object obr with mo_cstring_from_hi_lo_ids(bufid, obr->mo_ob_hid, obr->mo_ob_loid)..
I don't know how to code the above. For reference, I am now just returning the combo-box-text:
// if the entered text starts with a letter, I want it to be
// completed with the appended text above if the entered text starts
// with an undersore, then a digit, then two alphanum (like _0BV or
// _6S3 for example), I want to call a completion function.
#warning objectentry: what should I code here?
return obent;
} /* end mom_objectentry */
Is my approach the right one?
The mom_objectentry function above is used to fill modal dialogs with short lifetime.
I am favoring simple code over efficiency. Actually, my code is temporary (I'm hoping to bootstrap my language, and generate all its C code!) and in practice I'll probably have only a few hundred names and at most a few dozen of thousands of object-ids. So performance is not very important, but simplicity of coding (some conceptually "throw away" code) is more important.
I don't want (if possible) to add my own GTK classes. I prefer using existing GTK classes and widgets, customizing them with GTK signals and callbacks.
context
My application is an experimental persistent programming language and implementation with a near Scheme or Python (or JavaScript, ignoring the prototype aspect, ...) semantics but with a widely different (not yet implemented in september 7th, 2016) syntax (to be shown & input in GTK widgets), using the Boehm garbage collector for values (including objects, sets, tuples, strings...)... Values (including objects) are generally persistent (except the GTK related data : the application starts with a nearly empty window). The entire language heap is persisted in JSON-like syntax in some Sqlite "database" (generated at application exit) dumped into _momstate.sql which is re-loaded at application startup. Object-ids are useful to show object references to the user in GTK widgets, for persistence, and to generate C code related to the objects (e.g. the object of id _76f7e2VcL8IJC1hq6 could be related to a mo_76f7e2VcL8IJC1hq6 identifier in some generated C code; this is partly why I have my object-id format instead of using UUIDs).
PS. My C code is GPLv3 free software and available on github. It is the MELT monitor, branch expjs, commit e2b3b99ef66394...
NB: The objects mentioned here are implicitly my language objects, not GTK objects. The all have a unique object-id, and some but not most of them are named.
I will not show exact code on how to do it because I never did GTK & C only GTK & Python, but it should be fine as the functions in C and Python functions can easily be translated.
OP's approach is actually the right one, so I will try to fill in the gaps. As the amount of static options is limited probably won't change to much it indeed makes sense to add them using gtk_combo_box_text_append which will add them to the internal model of the GtkComboBoxText.
Thats covers the static part, for the dynamic part it would be perfect if we could just store this static model and replace it with a temporay model using gtk_combo_box_set_model() when a _ was found at the start of the string. But we shouldn't do this as the documentation says:
You should not call gtk_combo_box_set_model() or attempt to pack more cells into this combo box via its GtkCellLayout interface.
So we need to work around this, one way of doing this is by adding a GtkEntryCompletion to the entry of the GtkComboBoxText. This will make the entry attempt to complete the current string based on its current model. As an added bonus it can also add all the character all options have in common like this:
As we don't want to load all the dynamic options before hand I think the best approach will be to connect a changed listener to the GtkEntry, this way we can load the dynamic options when we have a underscore and some characters.
As the GtkEntryCompletion uses a GtkListStore internally, we can reuse part of the code Nominal Animal provided in his answer. The main difference being: the connect is done on the GtkEntry and the replacing of GtkComboText with GtkEntryCompletion inside the populator. Then everything should be fine, I wish I would be able to write decent C then I would have provided you with code but this will have to do.
Edit: A small demo in Python with GTK3
import gi
gi.require_version('Gtk', '3.0')
import gi.repository.Gtk as Gtk
class CompletingComboBoxText(Gtk.ComboBoxText):
def __init__(self, static_options, populator, **kwargs):
# Set up the ComboBox with the Entry
Gtk.ComboBoxText.__init__(self, has_entry=True, **kwargs)
# Store the populator reference in the object
self.populator = populator
# Create the completion
completion = Gtk.EntryCompletion(inline_completion=True)
# Specify that we want to use the first col of the model for completion
completion.set_text_column(0)
completion.set_minimum_key_length(2)
# Set the completion model to the combobox model such that we can also autocomplete these options
self.static_options_model = self.get_model()
completion.set_model(self.static_options_model)
# The child of the combobox is the entry if 'has_entry' was set to True
entry = self.get_child()
entry.set_completion(completion)
# Set the active option of the combobox to 0 (which is an empty field)
self.set_active(0)
# Fill the model with the static options (could also be used for a history or something)
for option in static_options:
self.append_text(option)
# Connect a listener to adjust the model when the user types something
entry.connect("changed", self.update_completion, True)
def update_completion(self, entry, editable):
# Get the current content of the entry
text = entry.get_text()
# Get the completion which needs to be updated
completion = entry.get_completion()
if text.startswith("_") and len(text) >= completion.get_minimum_key_length():
# Fetch the options from the populator for a given text
completion_options = self.populator(text)
# Create a temporary model for the completion and fill it
dynamic_model = Gtk.ListStore.new([str])
for completion_option in completion_options:
dynamic_model.append([completion_option])
completion.set_model(dynamic_model)
else:
# Restore the default static options
completion.set_model(self.static_options_model)
def demo():
# Create the window
window = Gtk.Window()
# Add some static options
fake_static_options = [
"comment",
"if",
"the_GUI",
"the_system",
"payload_json",
"x1",
"payload_json",
"payload_vectval"
]
# Add the the Combobox
ccb = CompletingComboBoxText(fake_static_options, dynamic_option_populator)
window.add(ccb)
# Show it
window.show_all()
Gtk.main()
def dynamic_option_populator(text):
# Some fake returns for the populator
fake_dynamic_options = [
"_5Hf0fFKvRVa71ZPM0",
"_8261sbF1f9ohzu2Iu",
"_0BV96V94PJIn9si1K",
"_0BV1sbF1f9ohzu2Iu",
"_0BV0fFKvRVa71ZPM0",
"_0Hf0fF4PJIn9si1Ks",
"_6KvRVa71JIn9si1Kw",
"_5HKvRVa71Va71ZPM0",
"_8261sbF1KvRVa71ZP",
"_0BKvRVa71JIn9si1K",
"_0BV1KvRVa71ZPu2Iu",
"_0BV0fKvRVa71ZZPM0",
"_0Hf0fF4PJIbF1f9oh",
"_61sbFV0fFKn9si1Kw",
"_5Hf0fFKvRVa71ozu2",
]
# Only return those that start with the text
return [fake_dynamic_option for fake_dynamic_option in fake_dynamic_options if fake_dynamic_option.startswith(text)]
if __name__ == '__main__':
demo()
Gtk.main()
Here is my suggestion:
Use a GtkListStore to contain a list of GTK-managed strings (essentially, copies of your identifier string) that match the current prefix string.
(As documented for gtk_list_store_set(), a G_TYPE_STRING item is copied. I consider the overhead of the extra copy acceptable here; it should not affect real-world performance much anyway, I think, and in return, GTK+ will manage the reference counting for us.)
The above is implemented in a GTK+ callback function, which gets an extra pointer as payload (set at the time the GUI is created or activated; I suggest you use some structure to keep references you need to generate the matches). The callback is connected to the combobox popup signal, so that it gets called whenever the list is expanded.
Note that as B8vrede noted in a comment, a GtkComboBoxText should not be modified via its model; that is why one should/must use a GtkComboBox instead.
Practical example
For simplicity, let's assume all the data you need to find or generate all known identifiers matched against is held in a structure, say
struct generator {
/* Whatever data you need to generate prefix matches */
};
and the combo box populator helper function is then something like
static void combo_box_populator(GtkComboBox *combobox, gpointer genptr)
{
struct generator *const generator = genptr;
GtkListStore *combo_list = GTK_LIST_STORE(gtk_combo_box_get_model(combobox));
GtkWidget *entry = gtk_bin_get_child(GTK_BIN(combobox));
const char *prefix = gtk_entry_get_text(GTK_ENTRY(entry));
const size_t prefix_len = (prefix) ? strlen(prefix) : 0;
GtkTreeIter iterator;
/* Clear the current store */
gtk_list_store_clear(combo_list);
/* Initialize the list iterator */
gtk_tree_model_get_iter_first(GTK_TREE_MODEL(combo_list), &iterator);
/* Find all you want to have in the combo box;
for each const char *match, do:
*/
gtk_list_store_append(combo_list, &iterator);
gtk_list_store_set(combo_list, &iterator, 0, match, -1);
/* Note that the string pointed to by match is copied;
match is not referred to after the _set() returns.
*/
}
When the UI is built or activated, you need to ensure the GtkComboBox has an entry (so the user can write text into it), and a GtkListStore model:
struct generator *generator;
GtkWidget *combobox;
GtkListStore *combo_list;
combo_list = gtk_list_store_new(1, G_TYPE_STRING);
combobox = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(combo_list));
gtk_combo_box_set_id_column(GTK_COMBO_BOX(combobox), 0);
gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combobox), 0);
gtk_combo_box_set_button_sensitivity(GTK_COMBO_BOX(combobox), GTK_SENSITIVITY_ON);
g_signal_connect(combobox, "popup", G_CALLBACK(combo_box_populator), generator);
On my system, the default pop-up accelerator is Alt+Down, but I assume you've already changed that to Tab.
I have a crude working example here (a .tar.xz tarball, CC0): it reads lines from standard input, and lists the ones matching the user prefix in reverse order in the combo box list (when popped-up). If the entry is empty, the combobox will contain all input lines. I didn't change the default accelerators, so instead of Tab, try Alt+Down.
I also have the same example, but using GtkComboBoxText instead, here (also CC0). This does not use a GtkListStore model, but uses gtk_combo_box_text_remove_all() and gtk_combo_box_text_append_text() functions to manipulate the list contents directly. (There is just a few different lines in the two examples.) Unfortunately, the documentation is not explicit whether this interface references or copies the strings. Although copying is the only option that makes sense, and this can be verified from the current Gtk+ sources, the lack of explicit documentation makes me hesitant.
Comparing the two examples I linked to above (both grab some 500 random words from /usr/share/dict/words if you compile and run it with make), I don't see any speed difference. Both use the same naïve way of picking prefix matches from a linked list, which means the two methods (GtkComboBox + model, or GtkComboBoxText) should be about equally fast.
On my own machine, both get annoyingly slow with more than 1000 or so matches in the popup; with just a hundred or less matches, it feels instantaneous. This, to me, indicates that the slow/naïve way of picking prefix matches from a linked list is not the culprit (because the entire list is traversed in both cases), but that the GTK+ combo boxes are just not designed for large lists. (The slowdown is definitely much, much worse than linear.)

When writing a Lua-facing function in C, what's a good way to check if an argument supports table-like lookups?

Here's a potential pattern that can check if an argument is a table:
int my_fn(lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
// .. do stuff with the table ..
}
This works whenever the first argument is a table. However, other Lua types support table lookups, such as a userdata, and in luajit, a cdata.
Is there a nice way to check if a table lookup, such as via lua_getfield, will succeed before I call it? I mean without restricting the type to tables. Relatedly, are tables, userdata, and cdata the only types in luajit that support indexed lookups?
I'm most interested in answers restricted to the Lua 5.1 C API because I'm using LuaJIT which currently works with this version.
Clarification
The advantage of the luaL_checkXXX functions is that, in one line, they:
throw an informative, user-friendly error message if the type is wrong, and
provide a C-friendly return value that can be used immediately.
I'm looking for something similar for tables. I don't expect a C-friendly hash-table return value, but I do want the same quality of error message to the user if the argument in question is not indexable.
I'm embracing the philosophy of duck typing. If I write a function that simply wants to index some keys from an argument, then I don't care if that argument is truly a table, or just a userdata that supports __index lookups. I want to accept either one.
In general, just tables have lookups because it's the only type which defines this property. Userdata are opaque, just the host knows what to do with it or adds a metatable (which can be analyzed) for specific behaviour. CData are part of Lua compiling with LuaJIT, i never used this type with C API (is it even supported?). At the end you have to check the type/metatable for possible lookups and request a field to check for setting, there's no way around lua_getfield (but raw access should be faster, see lua_rawget). The exception would be to check for table array length by lua_objlen.
Furthermore a cheaper solution for type checking would be lua_is*** functions.
Here's one way to do it:
// If the value at index narg is not indexable, this function does not return and
// provides a user-friendly error message; otherwise the stack is unchanged.
static void luaL_checkindexable(lua_State *L, int narg) {
if (lua_istable(L, narg)) return; // tables are indexable.
if (!luaL_getmetafield(L, narg, "__index")) {
// This function will show the user narg and the Lua-visible function name.
luaL_argerror(L, narg, "expected an indexable value such as a table");
}
lua_pop(L, 1); // Pop the value of getmetable(narg).__index.
}
This works for tables and any value with an __index value on its metatable.
It provides a standard-format error given by luaL_argerror. Here's an example error message:
a_file.lua:7: bad argument #1 to 'fn' (expected an indexable value such as a table)
You can use it like this:
// This Lua-facing function expects an indexable 1st argument.
int my_fn(lua_State *L) {
luaL_checkindexable(L, 1);
lua_getfield(L, 1, "key"); // --> arg1.key or nil is now on top of stack.
// .. your fn ..
}

Another winapi file permissions C head-scratcher. Why isn't my method working?

I'm really scratching my head over how to correctly use the windows api to determine file permissions. I have seen so many posts on this, but I just can't seem to get it right. Specifically, I would like to examine whether a user has read or write permissions for a given file. These are my steps:
(1) Access fully qualified username of the calling client (inc. domain name) with GetUserNameEx; (returns 0 error; user name appears to print out correctly using a cout debug message).
(2) Access the user's SID using LookupAccountName. (I do this twice, the first time for setting the SID and domain buffer sizes -- Returns 122 error on first call and 0 error on second (to be expected)). I assume the SID buffer is correctly set.
(3) Build a trustee with the obtained sid:
TRUSTEE t;
PTRUSTEE tptr = &t;
BuildTrusteeWithSid(tptr,&sid[0]);
(4) Obtain the DACL:
// following are freed up later using LocalFree (maybe I should use delete?)
PACL ppDacl = new ACL;
PSECURITY_DESCRIPTOR ppSecurityDescriptor = new SECURITY_DESCRIPTOR;
std::vector<TCHAR> v(pathString.begin(), pathString.end());
GetNamedSecurityInfo(&v[0],
SE_FILE_OBJECT,
READ_CONTROL,
NULL,
NULL,
&ppDacl,
NULL,
&ppSecurityDescriptor);
A simple call
std::cout<<"ACE count: "<<ppDacl->AceCount<<std::endl;
then indicates that there are 58 ACEs leading me to assume that the DACL struct is being correctly instantiated (I am further assuming that there are 58 ACEs although I'm not sure how to manually verify this; I'm really not a windows person). However, printing GetLastError() after the GetNamedSecurityInfo call gives me a 122 (i.e. ERROR_INSUFFICIENT_BUFFER) so it appears something is going wrong at this step.
Note that initializing the PACL and PSECURITY_DESCRIPTOR as follows:
ACL dacl;
PACL ppDacl = &dacl;
SECURITY_DESCRIPTOR sd;
PSECURITY_DESCRIPTO = &sd;
rather than new-ing them doesn't seem to correctly fill the DACL (at least the call
std::cout<<"ACE count: "<<ppDacl->AceCount<<std::endl;
reports 0 rather than 58). I'm not sure why.
(5) Finally, I attempt to get the file's access mask given the created trustee and dacl:
ACCESS_MASK access;
GetEffectiveRightsFromAcl(ppDacl, tptr, &access);
Which indicates no access rights when I do:
((access & GENERIC_WRITE)==GENERIC_WRITE)
or
((access & GENERIC_READ)==GENERIC_READ)
I hope one of you can shed some light on this
Cheers,
Ben.
The call to GetNamedSecurityInfo() shall have DACL_SECURITY_INFORMATION set in the set of flags being passed as 3rd parameter. Only then the data being referenced by the value returned in the 6th parameter will be valid after the call returned.
Verbatim from GetNamedSecurityInfo()'s documentation on MSDN:
ppDacl [out, optional]
...
The returned pointer is valid only if you set the DACL_SECURITY_INFORMATION flag.
Also as a side note: There is no need to initialise ppDacl and ppSecurityDescriptor as this is done by GetNamedSecurityInfo(). If you dynamically allocate memory to those this causes a memory leak, as by the call to GetNamedSecurityInfo() you lose the references to what you allocated.

Custom Find/Replace dialog box

First of all, please bear in mind that I'm new to Windows Programming. I'll try to cover my question in great detail, so that hopefully the answer will be too.
A short introduction:
I'm copying writing a Notepad-like application using Win32 API and pure C. For those of you familiar with Petzold's Windows Programming, this is a modified version of his POPPAD program which he used to describe Common Dialog Boxes. I'm writing this strictly for educational purposes, so please refrain from posting comments like "why you using old technology, use .NET", as those comments will not help me solve my problem :).
Description of a problem:
Petzold in his POPPAD program used Common Dialog Boxes to write this Notepad-like application. He used Edit Control to provide all the functions of a basic text editor. POPPAD, much like a Notepad, also had Find and Replace dialog boxes where you could, well, find stuff AND replace it! Mind boggling, I know.
So this is where I wanted to test my newly acquired knowledge from reading the past chapters, as I decided to write my very own Find and Replace dialog box. Granted, it would be in the simplest form possibly. How hard can it be? You have one text field where you enter some text and you have one fancy button which says "Find!" on it.
Now I'd like to remind you once more that I'm new to Windows programming, so excuse me for any possibly newbie questions. Also, I'd like to point out that I'll focus solely on making the Find dialog box working, as Replace shouldn't be too hard to implement then.
So I played with the resource editor in Visual Studio, and few hours later I got this:
(stackoverflow doesn't actually allows me to post images, so here's the link below)
http://i.imgur.com/R98x4.png
I named this dialog box "Find" (with the quotation marks), so I don't have to use MAKEINTRESOURCE macro in my program, as per Petzold's school of thought. I changed the caption of "Ok" button to "Find Next" and changed it's ID from IDOK to IDC_FIND. Also changed IDCANCEL to IDC_CANCEL and that single line Edit Control is IDC_FIND_FIND.
Now to the more serious things. In my main program's Windows Procedure, I have this piece of code:
case IDM_SEARCH_FIND:
hDlgModeless = CreateDialog (hInst, TEXT ("Find"),
hwnd, FindDlgProc) ;
return 0 ;
IDM_SEARCH_FIND is a message identifier of a Menu item, which when clicked should open up the Find dialog box. CreateDialog function is used to create a modeless dialog box and store it's handle into a global variable hDlgModeless. FindDlgProc is name of the dialog box procedure where (I think) all the code of finding the text should go.
So without further ado, here's the code of my Find dialog box procedure:
BOOL CALLBACK FindDlgProc (HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
static TCHAR szFindWhat[MAX_STRING_LEN]; //Text to find
static int iOffset ; //Offset from the beginning of Edit control to the result
int iLength, iPos, iSingleLength ; //Length of a main Edit control and single line Edit control
PTSTR pstrDoc, pstrPos ;
switch (message)
{
case WM_INITDIALOG:
return TRUE ;
case WM_COMMAND:
switch (LOWORD (wParam))
{
//If the button "Find Next" has been pressed, process all the logic of finding the text
case IDC_FIND:
// Get the text from a single-line edit control in Find dialog box
// and save it in szFindWhat variable
iSingleLength = GetWindowTextLength(GetDlgItem(hDlg, IDE_FIND_FIND)) ;
GetWindowText(GetDlgItem(hDlg, IDE_FIND_FIND), szFindWhat, iSingleLength) ;
// Get the text from a main Edit control, allocate memory for it
// and store it in pstrDoc variable
iLength = GetWindowTextLength (hwndEdit) ;
if (NULL == (pstrDoc = (PTSTR) malloc ((iLength + 1) * sizeof (TCHAR))))
return FALSE ;
GetWindowText (hwndEdit, pstrDoc, iLength + 1) ;
// Search the document for the find string
pstrPos = _tcsstr (pstrDoc + iOffset, szFindWhat) ;
free (pstrDoc) ;
// Return an error code if the string cannot be found
if (pstrPos == NULL)
return FALSE ;
// Find the position in the document and the new start offset
iPos = pstrPos - pstrDoc ;
iOffset = iPos + lstrlen (szFindWhat) ;
// Select the found text
SendMessage (hwndEdit, EM_SETSEL, iPos, iOffset) ;
SendMessage (hwndEdit, EM_SCROLLCARET, 0, 0) ;
case IDC_CANCEL:
DestroyWindow (hDlg) ;
hDlgModeless = NULL ;
break ;
}
break ;
case WM_CLOSE:
DestroyWindow (hDlg) ;
hDlgModeless = NULL ;
break ;
default:
return FALSE;
}
return FALSE ;
}
The only actual error I get here is that hwndEdit is undeclared identifier. hwndEdit is the main Edit control (not the single-line in Find dialog box). How do I get the handle to hwndEdit while I'm in a Find dialog box procedure?
I'd like to point out that I'm feeling a bit over my head here, so please say if I'm missing/doing wrong something obvious. I'm pretty sure that even if I fix the only error I'm getting, the program still won't work. Even though the concept of what I should be doing sounds fairly simple, actually programming that seems quite difficult :)
This is what the code above should do, in simplest form:
- Get the text from Find dialog box which I wish to search
- Get the text from main Edit control
- Do a substring search from the last offset (don't start from beginning every time)
- Find the position of a result and readjust offset
- Select the found text
I know I haven't really asked a direct question here, well I guess the direct question would be: How do I make this work? :) But more importantly it would be to understand how this exactly works. I'd appreciate if you can provide me with an elaborate answer. Thanks for all the help!
It looks like you're very close, you just need to get the hwndEdit from your main window. You passed your main window's handle in as a parent to your dialog box, so you should be able to get the parent window of your dialog box like so:
HWND hwndParent = GetParent(hDlg);
After that you can get the edit control from that parent by referencing the edit control ID in your main window definition. Something like this (assuming the control ID is IDC_EDIT):
HWND hwndEdit = GetDlgItem(hwndParent, IDC_EDIT);

Resources