I am looking for the normal way (that is, the way Microsoft thought about when creating its API) to load standard icons for commands in a pure C program, like the floppy disc image for saving, etc.
The Internet doesn't seem to contain the answer. I know the toolbars of commctl32 can receive a TB_LOADIMAGES message that fills an image list with standard icons, but what if I don't need toolbars in my app? I want icons in another control, let's say on an owner-draw button, or a menu item. Is there a way to fill the image list without creating a useless toolbar? Or even better, getting HICON or HBITMAP handles to avoid the commctl32 dependency?
The loud silence about it in Microsoft's docs, and on the web, makes me think there is no such feature. Maybe when an application is developed with Microsoft tools, the application creator injects as resources in the executable files the default icons the developer chooses in a predefined list? I cannot check it because I only use Unix-like compilers, can somebody confirm that and/or tell me more about default icon usage under Windows?
Also, would it be reliable to assume we can load libraries like shell32.dll to use its embedded icons (like all the good old functions that are available since an eternity in kernel32.dll, `user32.dll, ...)? I mean, is there a guarantee that icons in libraries will keep their semantics and indexes in future versions of Windows?
Coming some days later to post the final solution I opted for, just in case somebody would need to use the same. The most normal way to show command icons is to embed them in the application, so despite being unhappy with the creation of a dummy control, I use a temporary toolbar to load the icons in global image lists. This would unlikely fail, but since icons may sometimes be the only thing that indicates to the user what a widget does, I reinforced the conditions with the ability to run a fallback code when something is wrong.
The function that loads the icons is named WIN32_initIcons(), because it is supposed to be implemented alongside with something like a GTK_initIcons() or X11_initIcons() counterpart for Unix-like platforms.
HIMAGELIST WIN32_imglst16 = NULL;
HIMAGELIST WIN32_imglst24 = NULL;
bool WIN32_initIcons(void) {
bool def16 = false;
bool def32 = false;
HWND hWnd;
WIN32_imglst16 = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 80, 16);
WIN32_imglst32 = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 80, 16);
if (hWnd = CreateWindowA("ToolbarWindow32", NULL, TBSTYLE_LIST, 0, 0, 0, 0, NULL, (HMENU)0, GetModuleHandle(NULL), NULL)) {
if (WIN32_imglst16) {
SendMessage(hWnd, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)WIN32_imglst16);
if (!SendMessage(hWnd, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL)) def16 = true;
if (SendMessage(hWnd, TB_LOADIMAGES, (WPARAM)IDB_VIEW_SMALL_COLOR, (LPARAM)HINST_COMMCTRL) != 15) def16 = false;
if (SendMessage(hWnd, TB_LOADIMAGES, (WPARAM)IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL) != 27) def16 = false;
if (ImageList_GetImageCount(WIN32_imglst16) != 32) def16 = false;
}
if (WIN32_imglst24) {
SendMessage(hWnd, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)WIN32_imglst24);
if (!SendMessage(hWnd, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL)) def24 = true;
if (SendMessage(hWnd, TB_LOADIMAGES, (WPARAM)IDB_VIEW_SMALL_COLOR, (LPARAM)HINST_COMMCTRL) != 15) def24 = false;
if (SendMessage(hWnd, TB_LOADIMAGES, (WPARAM)IDB_HIST_SMALL_COLOR, (LPARAM)HINST_COMMCTRL) != 27) def24 = false;
if (ImageList_GetImageCount(WIN32_imglst24) != 32) def24 = false;
}
DestroyWindow(hWnd);
}
if (WIN32_imglst16 && !def16) {
// Load your custom 16x16 fallback icons in the list "WIN32_imglst16" here
// Don't forget to set "def16 = true" on success
}
if (WIN32_imglst24 && !def24) {
// Load your custom 24x24 fallback icons in the list "WIN32_imglst24" here
// Don't forget to set "def24 = true" on success
}
if (!def16) {
// Trigger your error management here because 16x16 icons cannot be loaded
// Maybe, call "ImageList_Destroy(WIN32_imglst16)" and set "WIN32_imglst16 = NULL"
}
if (!def24) {
// Trigger your error management here because 24x24 icons cannot be loaded
// Maybe, call "ImageList_Destroy(WIN32_imglst24)" and set "WIN32_imglst24 = NULL"
}
return (def16 && def24);
}
Note: In simple C, use <stdbool.h> to define the bool value.
Related
I have a statusbar, and I want to have its text being selectable (e.g. copy and pastable), on Linux/Debian, with GTK3 (3.21.5 on Debian/Sid). The label of the statusbar is the label field of its private data, and there is no direct API to access it.
I was able to code (in C99) the following, which is working:
mom_cmdstatusbar = // some global variable
gtk_statusbar_new ();
{
GtkWidget *statmsgarea =
gtk_statusbar_get_message_area (GTK_STATUSBAR (mom_cmdstatusbar));
MOM_ASSERTPRINTF (GTK_IS_CONTAINER (statmsgarea), "bad statmsgarea#%p",
statmsgarea);
GList *lischs = gtk_container_get_children (GTK_CONTAINER (statmsgarea));
for (GList * l = lischs; l != NULL; l = l->next)
{
GtkWidget *chwidg = l->data;
MOM_ASSERTPRINTF (GTK_IS_WIDGET (chwidg), "bad chwidg#%p", chwidg);
if (GTK_IS_LABEL (chwidg))
gtk_label_set_selectable (GTK_LABEL(chwidg), true);
}
g_list_free (lischs), lischs = NULL;
}
This does work, but is there a better or simpler way to do that? Getting the list of children inside the message area of the GtkStatusbar and testing each of them smells bad. It looks like some GtkWidget* gtk_statusbar_get_label (GtkStatusbar*); function is missing in in the GTK3 API.
PS. FWIW, the code is GPLv3+, on github in file gui.c on commit 58feb1d9473c34aca.. of the expjs branch. More details & motivation about that software project on this & that questions.
If there's no direct API to access the internal child, then that is probably on purpose, so that the GTK developers can keep their options open to reorganize the internal layout of the widget in future versions.
I have started working with DirectX in WPF app. My first step was to use simple library:
SharpdDX.WPF. Based on samples I've implemented WPF control drawing simple line. SharpDX.WPF uses D3DImage to render images in WPF.
Unfortunately application's memory increasing all time.
I implemented class TestControlRenderer : D3D10.
Vertex shader is initialized like:
var sizeInBytes = dataLength * sizeof(int) * 3;
var bufferDescription = new BufferDescription(
sizeInBytes,
ResourceUsage.Dynamic,
BindFlags.VertexBuffer,
CpuAccessFlags.Write,
ResourceOptionFlags.None);
using (var stream = new DataStream(sizeInBytes, true, true))
{
stream.Position = 0;
_graphDataVertexBuffer = new SharpDX.Direct3D10.Buffer(Device, stream, bufferDescription);
}
Device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(_graphDataVertexBuffer, sizeof(int) * 3, 0));
Device.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip;
Then constant buffer with parameters used in shader:
_controlInfoConstantBuffer = new ConstantBuffer<ControlParamsShaderData>(Device);
Device.VertexShader.SetConstantBuffer(0, _controlInfoConstantBuffer.Buffer);
To init animation Reset method was overriden like that:
base.Reset(args);
if (args.RenderSize.Width == 0) return;
_drawArgs = args;
InitVertexBuffer(dataLength);
_controlInfoConstantBuffer.Value = new ControlParamsShaderData
{
SamplesInControl = dataLength,
MinSignalDataY = -1500,
MaxSignalDataY = 1500
};
Device.VertexShader.SetConstantBuffer(0, _controlInfoConstantBuffer.Buffer);
The last step is RenderScene method:
public override void RenderScene(DrawEventArgs args)
{
if (args.RenderSize.Width == 0) return;
Device.ClearRenderTargetView(RenderTargetView, Color.Transparent);
using (var stream = _graphDataVertexBuffer.Map(MapMode.WriteDiscard, SharpDX.Direct3D10.MapFlags.None))
{
for (int i = 0; i < Data.Length; i++)
{
stream.Write(new Vector3(i, Data[i], 0));
}
}
_graphDataVertexBuffer.Unmap();
Device.Draw(Data.Length, 0);
}
Rendering is controlled by DispatcherTimer where OnTickMethod updates array with points coordinates and then invoke Render() method.
My question is simply, is that memory leak or something is created on each render iteration?
I don't change backbuffer or create another objects. Only change Data array, update it to GPU and Shaders process it to display.
My case is to display about 30 wpf controls width DirectX on one screen. Controls are with simple but realtime animation. Is that possible in that way?
Most likely you are leaking resources. You can see this by setting the static configuration property
SharpDX.Configuration.EnableObjectTracking = true;
then calling
SharpDX.Diagnostics.ObjectTracker.ReportActiveObjects()
at various points in your application lifetime to see if anything is leaking (at least on the SharpDX side). You can edit your code to make sure to dispose these objects. Only enable object tracking while debugging - it hurts performance.
SharpDX used to release COM objects when the finalizer ran if the object had not already been Diposed (at least as in version 2.4.2), but later disabled that (they detail why in one of their changelogs, I forget which one).
Additionally, DirectX requires that you release objects in the reverse order they were created - this can create hard-to-debug memory leaks. So when your code is
var device = new Devie(...);
var effect = new Effec(Device, byteCode);
technique = effect.GetTechniqueByName(techniqueName);
inputLayout = new InputLayout(Device, _technique.GetPassByIndex(0).Description.Signature, ...);
then your dispose code has to be
_inputLayout.Dispose();
_technique.Dispose();
_effect.Dispose();
_device.Dispose();
I am trying to create a map editor based on WPF. Currently I'm using a hack to render DirectX contents. I created a WinFormsHost and rendered on a WinForms-Panel.
This all because DirectX (I´m using DirectX 11 with Featurelevel 10) wants a Handle (alias IntPtr) where to render. I don´t know how I can initialize and use the DX Device without a handle.
But a WPF control has no handle. So I just found out, there is an interop class called "D3DImage". But I don't understand how to use it.
My current system works like this:
The inner loop goes through a list of "IGameloopElement"s. For each, it renders its content calling "Draw()". After that, it calls "Present()" of the swap chain to show the changes. Then it resets the device to switch the handle to the next element (mostly there is only one element).
Now, because D3DImage doesn't have a handle, how do I render onto it? I just know I have to use "Lock()" then "SetBackBuffer()", "AddDirtyRect()" and then "Unlock()".
But how do I render onto a DirectX11.Texture2D object without specifying a handle for the device?
I´m really lost... I just found the "DirectX 4 WPF" sample on codeplex, but this implements all versions of DirectX, manages the device itself and has such a huge overhead.
I want to stay at my current system. I´m managing the device by myself. I don´t want the WPF control to handle it.
The loop just should call "Render()" and then passes the backbuffer texture to the WPF control.
Could anyone tell me how to do this? I´m totally stuck ...
Thanks a lot :)
R
WPF's D3DImage only supports Direct3D9/Direct3D9Ex, it does not support Direct3D 11. You need to use DXGI Surface Sharing to make it work.
Another answer wrote, "D3DImage only supports Direct3D9/Direct3D9Ex"... which is perhaps not entirely true for the last few years anyway. As I summarized in a comment here, the key appears to be that Direct3D11 with DXGI has a very specific interop compatibility mode (D3D11_SHARED_WITHOUT_MUTEX flag) which makes the ID3D11Texture2D1 directly usable as a D3DResourceType.IDirect3DSurface9, without copying any bits, which just so happens to be exactly (and only) what WPF D3DImage is willing to accept.
This is a rough sketch of what worked for me, to create a D3D11 SampleAllocator that produces ID3D11Texture2D1 that are directly compatible with WPF's Direct3D9. Because all the .NET interop shown here is of my own design, this will not be totally ready-to-run code to drop in your project, but the method, intent, and procedures should be clear for easy adaptation.
1. preliminary helper
static D3D_FEATURE_LEVEL[] levels =
{
D3D_FEATURE_LEVEL._11_1,
D3D_FEATURE_LEVEL._11_0,
};
static IMFAttributes GetSampleAllocatorAttribs()
{
MF.CreateAttributes(out IMFAttributes attr, 6);
attr.SetUINT32(in MF_SA_D3D11_AWARE, 1U);
attr.SetUINT32(in MF_SA_D3D11_BINDFLAGS, (uint)D3D11_BIND.RENDER_TARGET);
attr.SetUINT32(in MF_SA_D3D11_USAGE, (uint)D3D11_USAGE.DEFAULT);
attr.SetUINT32(in MF_SA_D3D11_SHARED_WITHOUT_MUTEX, (uint)BOOL.TRUE);
attr.SetUINT32(in MF_SA_BUFFERS_PER_SAMPLE, 1U);
return attr;
}
static IMFMediaType GetMediaType()
{
MF.CreateMediaType(out IMFMediaType mt);
mt.SetUINT64(in MF_MT_FRAME_SIZE, new SIZEU(1920, 1080).ToSwap64());
mt.SetGUID(in MF_MT_MAJOR_TYPE, in WMMEDIATYPE.Video);
mt.SetUINT32(in MF_MT_INTERLACE_MODE, (uint)MFVideoInterlaceMode.Progressive);
mt.SetGUID(in MF_MT_SUBTYPE, in MF_VideoFormat.RGB32);
return mt;
}
2. the D3D11 device and context instances go somewhere
ID3D11Device4 m_d3D11_device;
ID3D11DeviceContext2 m_d3D11_context;
3. initialization code is next
void InitialSetup()
{
D3D11.CreateDevice(
null,
D3D_DRIVER_TYPE.HARDWARE,
IntPtr.Zero,
D3D11_CREATE_DEVICE.BGRA_SUPPORT,
levels,
levels.Length,
D3D11.SDK_VERSION,
out m_d3D11_device,
out D3D_FEATURE_LEVEL _,
out m_d3D11_context);
MF.CreateDXGIDeviceManager(out uint tok, out IMFDXGIDeviceManager m_dxgi);
m_dxgi.ResetDevice(m_d3D11_device, tok);
MF.CreateVideoSampleAllocatorEx(
ref REFGUID<IMFVideoSampleAllocatorEx>.GUID,
out IMFVideoSampleAllocatorEx sa);
sa.SetDirectXManager(m_dxgi);
sa.InitializeSampleAllocatorEx(
PrerollSampleSink.QueueMax,
PrerollSampleSink.QueueMax * 2,
GetSampleAllocatorAttribs(),
GetMediaType());
}
4. use sample allocator to repeatedly generate textures, as needed
ID3D11Texture2D1 CreateTexture2D(SIZEU sz)
{
var vp = new D3D11_VIEWPORT
{
TopLeftX = 0f,
TopLeftY = 0f,
Width = sz.Width,
Height = sz.Height,
MinDepth = 0f,
MaxDepth = 1f,
};
m_d3D11_context.RSSetViewports(1, ref vp);
var desc = new D3D11_TEXTURE2D_DESC1
{
SIZEU = sz,
MipLevels = 1,
ArraySize = 1,
Format = DXGI_FORMAT.B8G8R8X8_UNORM,
SampleDesc = new DXGI_SAMPLE_DESC { Count = 1, Quality = 0 },
Usage = D3D11_USAGE.DEFAULT,
BindFlags = D3D11_BIND.RENDER_TARGET | D3D11_BIND.SHADER_RESOURCE,
CPUAccessFlags = D3D11_CPU_ACCESS.NOT_REQUESTED,
MiscFlags = D3D11_RESOURCE_MISC.SHARED,
TextureLayout = D3D11_TEXTURE_LAYOUT.UNDEFINED,
};
m_d3D11_device.CreateTexture2D1(ref desc, IntPtr.Zero, out ID3D11Texture2D1 tex2D);
return tex2D;
}
Where do i find standard system icons of messageboxes via WinApi? I want to create an advanced dialogbox (with details-extension) as WinApi resource, but I want to use the system default icons like:
For .NET I know that i'll find them in System.Drawing.SystemIcons, but where do I find them using native C and WinApi? And how could I apply them?
You should be able to get them using LoadIcon. To get the question mark icon use LoadIcon(NULL, IDI_QUESTION), the other identifiers are IDI_ERROR, IDI_WARNING and IDI_INFORMATION.
Thats correct,
If someone needs here my code to set the icon and also to play the corresponding sound.
HICON hIcon = NULL;
if(mbdIcon == MBD_ICON_INFORMATION) {
hIcon = LoadIcon(NULL, IDI_INFORMATION);
MessageBeep(MB_ICONASTERISK);
} else if(mbdIcon == MBD_ICON_QUESTION) {
hIcon = LoadIcon(NULL, IDI_QUESTION);
MessageBeep(MB_ICONQUESTION);
} else if(mbdIcon == MBD_ICON_WARNING) {
hIcon = LoadIcon(NULL, IDI_WARNING);
MessageBeep(MB_ICONWARNING);
} else if(mbdIcon == MBD_ICON_ERROR) {
hIcon = LoadIcon(NULL, IDI_ERROR);
MessageBeep(MB_ICONERROR);
} else {
ShowWindow(hPictureIcon, SW_HIDE);
}
if(hIcon != NULL)
{
Static_SetIcon(hPictureIcon, hIcon);
}
May it saves someone some minutes. :)
I am trying to show a progress bar while my process is going on...in my application there will be a situation where I gotta read files and manipulate them(it will take some time to complete)..want to display a progress bar during this operation..the particular function I am calling is an win 32 ...so if you check my code below ...I am able to display the progressbar but it doesnt show any progress..actually its not doing any further process...Please help me..thanks in advance
//my function
int Myfunction(....)
{
MSG msg;
HWND dialog = CreateWindowEx(0,WC_DIALOG,L"Proccessing...",WS_OVERLAPPEDWINDOW|WS_VISIBLE,
600,300,280,120,NULL,NULL,NULL,NULL);
HWND pBar = CreateWindowEx(NULL,PROGRESS_CLASS,NULL,WS_CHILD|WS_VISIBLE,40,20,200, 20,
dialog,(HMENU)IDD_PROGRESS,NULL,NULL);
SendMessage(pBar,PBM_SETRANGE,0,MAKELPARAM(0,noOfFile));
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
Dispatch(&message);
}
HANDLE getHandle = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)SetFilesForOperation(...),
NULL,NULL,0);
}
LPARAM SetFilesForOperation(...)
{
for(int index = 0;index < noOfFiles; index++)
{
*checkstate = *(checkState + index);
if(*checkstate == -1)
{
*(getFiles+i) = new TCHAR[MAX_PATH];
wcscpy(*(getFiles+i),*(dataFiles +index));
i++;
}
else
{
(*tempDataFiles)->Add(*(dataFiles+index));
*(checkState + localIndex) = *(checkState + index);
localIndex++;
}
PostMessage(pBar,PBM_SETPOS,(WPARAM)index,0);
}
}
I suspect the problem is that you're creating the thread after your app exits - if you move the call to CreateThread above the message pump it may work better.
I prefer to use QT over MFC. Here's how I would use it to answer your question:
Use form designer to create a dialog, and use AfxBeginThread(someFunc, param) to create a thread.
In someFunc, use SendMessage to tell the dialog about the progress.
sample here:
http://www.tek-tips.com/faqs.cfm?fid=5162