I'm making a paint program where I have MDI and multiple dialogs that need to access menu items.
Right now, I stick the menu in global so everything can see it. However, I'd like to use
typedef struct datastruct
{
DWORD currentTool;
POINT start, end;
DWORD lastShape;
HINSTANCE hInst;
HMENU hMenuInit, hMenuHello;
HMENU hMenuInitWindow, hMenuHelloWindow;
}
DATA, *PDATA;
This struct, along with PDATA pdata = 0, pglobaldata=0;
To access the following items:
HINSTANCE hInst;
HMENU hMenuInit, hMenu;
HMENU hMenuInitWindow, hMenuWindow;
For example, when I need to access hMenuInit in a MDI child window, I would do this: pglobaldata->hMenuInit and I'd be able to access the same one WinMain is using: hMenuInit = LoadMenu (hInstance, MAKEINTRESOURCE(IDR_MENU));
How can I accomplish this?
Having issues pasting all the code here. I've put it on pastebin: http://pastebin.com/z9tKSwhG
It sounds like you want to associate some instance specific data with the window. You do that by specifying the size of the extra data in the cbWndExtra member of WNDCLASSEX when you register the window class. And then access that extra data call GetWindowLongPtr and SetWindowLongPtr passing 0 for nIndex. That index identifies the slow where your instance data is stored.
Related
I have inserted custom gtk source gutter renderer pixbuf and I want to render icon on a specific line.
The reference API states that the interface is very similar to that on GtkTreeView, but doesn't work with a tree model.
So... how am I supposed to render data to a specific line if the GtkSourceGutter doesn't work with a tree model?
I checked every function in the entire library, every suggested api and child objects and nothing even hints about that.
It just doesn't make sense. The man page says that the GtkSourceGutterRendererPixbuf is used to display icon IN A CELL.
Doing gtk_source_gutter_renderer_pixbuf_set_pixbuf(renderer, pixbuf); will render the icon for all cells in the gutter.
And if the only way is to draw the pixbuf manually using cairo..what's the point in those renderers ?
How do I render pixbuf in a specific line using the gtksourcegutterrenderer?
I haven't worked with GtkSourceView, but I can give you some clues.
How it's done by GtkSourceView's author
First of all, we need some links:
GtkSourceGutterRendererMarks source code
GtkSourceGutterRendererPixbuf source code
GtkSourceGutterRenderer documentation
Let's start with GtkSourceGutterRendererPixbuf. From it's class_init method we find out, that it overrides only draw method. It's only purpose is to render a pixbuf or icon. Pure drawing.
However, GtkSourceGutterRenderer documentation says, that there is a query-data signal which can be used to tune Renderer's internal state. At this point we should take a look at GtkSourceGutterRendererMarks which is inherited from RendererPixbuf. It doesn't override draw, but overrides query_data. (For some reason GtkSourceGutterRendererClass is not described in the documentation. I don't know why.)
/* Read my comments. */
static void
gutter_renderer_query_data (GtkSourceGutterRenderer *renderer,
GtkTextIter *start,
GtkTextIter *end,
GtkSourceGutterRendererState state)
{
GSList *marks;
GdkPixbuf *pixbuf = NULL;
view = GTK_SOURCE_VIEW (gtk_source_gutter_renderer_get_view (renderer));
buffer = GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
marks = gtk_source_buffer_get_source_marks_at_iter (buffer,
start,
NULL);
/* If there are marks, we find a pixbuf for one of them.
* Otherwise pixbuf is NULL. */
if (marks != NULL)
{
size = measure_line_height (view);
pixbuf = composite_marks (view, marks, size);
g_slist_free (marks);
}
/* Now tell parent class to render certain pixbuf
* It will render nothing if pixbuf is NULL. */
g_object_set (G_OBJECT (renderer),
"pixbuf", pixbuf,
NULL);
}
My recommendations.
You want to draw marks at certain lines (e.g. want to highlight current debugger line). If I were you, I would have inherited from RendererPixbuf, overriden query_data and use gtk_text_iter_get_line on GtkTextIter *start. Looks like that's the bare minimum.
Feel free to ask any further questions.
I personally cannot simply agree with the allegation that creating custom objects is easy. It isn't easy, not to everyone.
Mainly, because, this question is tagged c and people who don't know Object-Oriented programming might be unfamiliar with its concepts.
It is a matter of reading and practice.
So do not panic if you don't know how to, for instance create your own widget.
The easiest solution I can think of, doesn't involve creating your own renderer, but rather tell the renderer how to query rendering data.
Just connect the query-data signal on your GtkSourceGutterRenderer to a signal handler that looks like this:
G_MODULE_EXPORT void gutter_renderer_query_data (GtkSourceGutterRenderer *renderer, GtkTextIter *start, GtkTextIter *end, GtkSourceGutterRendererState state)
{
GtkSourceView* view = NULL;
GtkSourceBuffer* buffer = NULL;
GSList* marks = NULL;
GdkPixbuf* pixbuf = NULL;
view = GTK_SOURCE_VIEW(gtk_source_gutter_renderer_get_view(renderer));
buffer = GTK_SOURCE_BUFFER(gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)));
marks = gtk_source_buffer_get_source_marks_at_iter(buffer, start, NULL);
if(marks != NULL)
{
char *category = gtk_source_mark_get_category(marks->data);
if(!g_strcmp0(category, "CERTAIN_CATEGORY")) /* See note 1) */
pixbuf = gtk_image_get_pixbuf(gtk_image_new_from_file("icon_file_here")); /* See note 2) */
g_slist_free(marks);
}
g_object_set(G_OBJECT(renderer), "pixbuf", pixbuf, "yalign", 0.5, NULL);
}
Notes:
GtkSourceMark shares the GtkSourceGutterRenderer interface so you might want to filter your other source marks, by specifying the category of a source mark that is applied to the certain line. Otherwise your custom renderer pixbuf will also be rendered left to your other source marks.
You should specify the exact pixbuf you want to render internally. Doing this, you won't have to call gtk_source_gutter_renderer_pixbuf_set_pixbuf() . You let the API do the resource handling.
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.
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);
The way I see it, one use of a Window Procedure's WM_CREATE message is to relieve the caller of the burden of executing static code at window initialization. My window is to execute some code in the WM_CREATE message, including the ShowWindow function. I also want the ShowWindow to behave properly according to the nCmdShow parameter in WinMain. So here is pseudo-code to show how I have things set up:
int g_nCmdShow;
WinMain(..., int nCmdShow)
{
g_nCmdShow = nCmdShow;
...
CreateWindow(..., WM_OVERLAPPEDWINDOW, ...)
...
}
WndProc()
{
...
WM_CREATE:
...
ShowWindow(hWnd, g_nCmdShow);
...
...
}
So I set up the program to run Minimized (using Windows XP I created a shortcut to the .exe, and set up the properties of it accordingly), and it displays on the taskbar minimized but it does not restore when I click on it. Likewise, if I run it Maximized, it does not behave correctly when I click the maximize button (to un-maximize it).
What is the correct way to use nCmdShow-compatible ShowWindow within the WM_CREATE message?
The problem is that the window's restore bounds get affected by this. They become the size of the window after WM_CREATE returns. You would have to modify your code to re-establish those restore bounds:
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 300, 200, NULL, NULL, hInstance, NULL);
WINDOWPLACEMENT wp;
GetWindowPlacement(hWnd, &wp); // <= Note wp.rcNormalPosition after this call!
RECT rc = {100, 100, 400, 300};
wp.rcNormalPosition = rc;
SetWindowPlacement(hWnd, &wp);
You're not ahead by doing it this way.
If you absolutely have to keep it in the WndProc, try
case WM_CREATE:
PostMessage(hwnd,WM_APP,0,0);
break;
case WM_APP:
ShowWindow(hwnd,SW_SHOW);
break;
But if this is so important, why not just have a helper function that creates the window and calls ShowWindow? MyWindowType_Create(...) etc
Having the window show itself, or set its own position, is a bad design choice that goes against how WinAPI was meant to be used. The right place to do these decisions is in the code that creates the window. It's already reflected in the fact that the CreateWindow is responsible for the initial window placement and WS_VISIBLE style.
In your code you should call ShowWindow in WinMain, which will also eliminate the need for the g_nCmdShow global:
WinMain(..., int nCmdShow)
{
...
hWnd = CreateWindow(..., WM_OVERLAPPEDWINDOW, ...)
ShowWindow(hWnd, nCmdShow);
...
}
WndProc()
{
...
WM_CREATE:
...
...
}
WM_CREATE is rather responsible for initializing window-class specific behavior. Creating child windows or initializing internal data structures and the cbWndExtra slots are examples of that (e.g. think of implementing a list-box).
Can you handle WM_WINDOWPOSCHANGED and override the window size the first time the window is restored? Use GetWindowPlacement to find out if the window got restored.
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.